提取图像的RGB通道


22

在给定图像的情况下,要么作为输入(可能是RGB三元组),要么使用文件名作为输入(您可以假定图像具有特定的文件名,可能没有扩展名),则输出表示图像的单个颜色通道的图像。

您还将接受另一个输入,代表要输出的通道。输入可以是任何3个不同的符号之一。但是,符号必须是字符串或数字。但是,您不能将矩阵应用于输入数组。(例如{1, 0, 0},或{0, 1, 0})。

您将输出<input>输入图像的通道。您既可以将其保存到文件中,也可以输出一组RGB对。

您的程序对图像的大小(以px为单位)应该没有限制,并且必须支持.png.jpg/ .jpeg/ .JPG或RGB三胞胎作为图像格式。(但是它可以支持任意数量)

测试用例:

紫罗兰色原始

红色通道:

紫红色

绿色通道:

紫绿色

蓝色频道:

紫蓝色

还有另一个测试用例,完全是红色的。 原始照片红色绿色蓝色。(警告:看得太久的普通和红色通道太痛了)

另外2个测试用例:

原始红色绿色蓝色

原始红色绿色蓝色

后两个测试用例来自所有颜色的图像


这是将高尔夫语言编译/编译为OpenCV操作的良好灵感。
恢复莫妮卡-ζ-17年

Answers:


2

APL(Dyalog),7个字节

I / O:RGB三元组数组

⎕×⊂⎕=⍳3

在线尝试!

⍳3 前三个整数

⎕= 比较数字输入(所选通道)

 附上(因此每个图像三元组将整个三元组配对)

⎕× 将数字输入(三元组的数组)与此相乘


12

JavaScript(ES6),29个字节

a=>n=>a.map(b=>b.map(c=>c&n))

输入是一个24位整数的2D数组(例如[[0x0000ff,0x00ff00],[0xff0000,0xffffff]]),16711680红色65280表示绿色,255蓝色表示蓝色。如果这无效,请尝试以下方法:

JavaScript(ES6),48个字节

a=>n=>a.map(b=>b.map(c=>c.map((d,i)=>i==n?d:0)))

输入是颜色值的3D数组,0红色1表示绿色,2蓝色表示蓝色。


1
厚脸皮的输入格式哈哈
Conor O'Brien

10

Mathematica,13个字节

ImageMultiply

这应该是郑焕敏答案的合法版本。该函数将图像和中的一个RedGreenBlue作为输入。例如:

在此处输入图片说明

有趣的是,它还ColorSeparate为您提供了单独的通道,但是它将它们作为单通道/灰度图像返回,因此无论如何您都需要将它们乘以颜色。


Mathematica有没有内置的功能吗?
Brian Minton

8

Bash + ImageMagick,35 32 27字节

mogrify -channel $1 -fx 0 i

假定图像文件中i和脚本需要之一RGBGBR分别为蓝色,红色和绿色; 输出到文件i


击败我。我在下面发布了一个不同的bash + IM答案,并进行了优化,您可以窃取
-Sparr

@Sparr我打了一场不一样的高尔夫球

您仍然可以使用mogrify保留两个字节,并且不加“ o”?
Sparr

7

频谱,非竞争性,1个字节

(不竞争,因为这一挑战启发了这种语言。)实际上,Spectrum是一个npm库,具有用于命令的语言界面。

I

输入为:

<filename>
channel

将该程序调用为:

cat input.txt | node spectrum.js "I"

或者,您可以向提示提供信息:

λ node spectrum.js "I"
input> Ov3Gm.png
input> r
[ Image { 512x512 } ]

这会将图像保留在堆栈上。要查看它,请O在末尾添加,如下所示:

λ node spectrum.js "IO"
input> Ov3Gm.png
input> r
[]

要获得一些额外的乐趣,请尝试echo filename | node spectrum.js "wO"。它一次执行所有三个通道隔离:

沃霍尔


1
@ThisGuy是的,它可以进行素性检查:n[d1=`[d1-P*][],.g!]#Pdd1-P~%-1=p
Conor O'Brien

1
@ ConorO'Brien您是否看到了我对ImageMagick的fx运算符的素性测试器?
Sparr

@Sparr不,我没有。链接?
科纳·奥布莱恩

@ ConorO'Briencodegolf.meta.stackexchange.com/ questions
Sparr

7

JavaScript(ES6),29个字节

a=>b=>a.map((v,i)=>i%3^b?0:v)

ETHproductions的答案很相似,但输入的灵活性比第一种方法小,但比第二种方法小。

这定义了一个函数,该函数接受图像作为数字颜色强度的一维数组。然后,此函数返回另一个函数,该函数接受代表所需颜色通道的整数值。

颜色可以由任何数值范围表示,只要0表示完全没有颜色即可。例如0.0 - 1.00 - 255

例子:

如果图像数据为RGB格式,则使用参数调用函数(imageData)(0)将仅返回红色通道的图像。

如果图像数据的格式为BGR,则使用参数调用函数(imageData)(2)也将仅通过红色通道返回图像。


我想i%3==b&&v也可以。
尼尔

6

Python 2,69个字节

from cv2 import*
def f(s,i):k=imread(s);k[:,:,[i,i-1]]=0;imwrite(s,k)

还在打高尔夫球。

将输入作为filename, n(其中n0、1或2)。将新图像保存在旧图像上。0是绿色,1红色和2蓝色。感谢@ ovs,@ Mikhail和@Rod减少了字节数。


通过删除x并替换k[:,:,x[i][0]]=k[:,:,x[i][1]]=0k[:,:,[1,2,0][i]]=k[:,:,i]=0
ovs,

@ovs谢谢!...实际上,在弄乱了您的建议之后,我本人实际上只是想出了第二个建议。你虽然忍了我。
Rɪᴋᴇʀ

您可以from cv2 import*用来节省一些字节
Rod

似乎您可以替换k[:,:,i-1]=k[:,:,i]=0k[:,:,[i,i-1]]=0
Mikhail V

5

CJam,12个字节

{3,f=f{f.*}}

一个匿名块,需要3D RGB三元组数组,并且堆栈中的数字介于0和2之间(含0和2)。之后将提取的数组留在堆栈上。

Red   -> 0
Green -> 1
Blue  -> 2

也许可以通过使用一种奇怪的输入格式来打高尔夫球,但是我觉得这有点作弊。

在线尝试!

测试用例只是为了演示,使用实际图像中的三元组太大了。

说明

3,          e# The range [0 1 2]
  f=        e# Check each for equality with the RGB indicator, gives the indicator array:
            e#  [1 0 0] for 0, [0 1 0] for 1, [0 0 1] for 2
    f{      e# Map on each row of the array using the indicator array as an extra parameter
      f.*   e#  Perform vectorized multiplication of the indicator array with each triplet.
            e#   For red, multiplies red by 1, and green and blue by 0. Does similarly
            e#   for green and blue.
         }  e# (end of block)

5

PowerShell,282字节

$x,$y=$args;1..($a=New-Object System.Drawing.Bitmap $x).Height|%{$h=--$_;1..$a.Width|%{$i=("$($a.GetPixel(--$_,$h)|select R,G,B)"|iex)[$y];$r,$g,$b=(((0,0,$i),(0,$i,0))[$y-eq'G'],($i,0,0))[$y-eq'R'];$a.SetPixel($_,$h,[system.drawing.color]::fromargb($r,$g,$b))}};$a.save("$x$y.png")

这些幻想都不是“寻找输入”或“使用内置”。Phooey。;-)

这里采用输入PNG的完整路径(尽管严格来说,它不需要是PNG,因为.NET支持JPG,BMP等,但我只在PNG上尝试过),和其中一个(R, G, B)用于颜色通道,然后将其存储到$x和中$y。然后,我们创建一个New-Object类型System.Drawing.Bitmap$x并将其存储到中$a

然后,我们对所有像素进行双循环。首先从1最高$a.Height,设置$h每次迭代(这是零指数的,所以这就是为什么我们--$_,从而节省了字节( .height-1)。里面,我们从环路1最多$a.Width

每次迭代时,我们都会.GetPixel在特定的w,h坐标上执行,这将返回一个System.Drawing.Color对象。我们select找出其中的R G B价值。这iex是一个巧妙的技巧,可以将其转换为哈希表(例如@{R=34; G=177; B=76}),因此我们可以直接使用所需的颜色通道对其进行索引[$y]。该值存储在中$i

接下来,我们基于的字母值将三个值设置$r, $g, $b为某些伪三元运算符的结果$y。因此,例如,如果$yR,则结果为$r=$i, $g=0, $b=0

然后,我们.SetPixel回退到该特定w,h坐标,System.Drawing.Color使用静态FromARGB(假定Alpha完全不透明)构造一个新坐标。完成循环后,我们只需.Save将PNG转换为新文件即可。

注意:这确实要花很长时间,因为它完全独立地遍历每个像素并执行一堆计算并调用每次迭代。

测试:
AdmBorkBork红色 AdmBorkBork绿色 AdmBorkBork蓝色


3

Bash + ImageMagick,41个字节

C="RGB"
mogrify -channel ${C//$1} -fx 0 x

输入是名为或或的x命令行参数文件RGB

输出覆盖输入文件

与betseg的答案不同,它采用了更自然的单字母通道参数。也覆盖而不是输出betseg可以窃取的新文件:)


$1需要引号,文件名可以有空格
betseg

@betseg不是,我说过您可以假设它具有特定的文件名。如果需要,他甚至可以将其更改为从文件名中读取x1个字节。
Rɪᴋᴇʀ

@Riker哦,我没有注意到,这也对我有帮助:D
betseg

3

芯片,78字节

 ~Z~vS
f/F,^-.
e/E|,-Z.
d/D|>zz^.
a/AMx-x-].
b/BMx-]v-'
c/CM]v-'
 >--v'
G/gh/H

在线尝试!

Chip是一种2D语言,可对字节流中每个字节的组成位进行操作。

总览

此特定解决方案期望输入的第一个字节为控制字符(定义要保留的通道),其次为图像数据的字节。图像数据必须是RGB三元组,每个通道一个字节,每个像素24位:

|  1  |  2  |  3  |  4  |  5  |  6  |  7  | ... | 3n-2 |  3n  | 3n+1 |
|     |   First Pixel   |   Second Pixel  | ... |      nth Pixel     |
| Ctl | Red | Grn | Blu | Red | Grn | Blu | ... |  Red |  Grn |  Blu |

控制字符被解释为位字段,尽管只有最低的三个位才有意义:

0x1  keep Red channel
0x2  keep Green channel
0x4  keep Blue channel

这意味着我们可以使用ASCII字符来选择所需的通道:

1表示红色
2表示蓝色
4表示绿色

或做一些更奇特的事情:

5 保持红色和蓝色,但不保持绿色
7保持保留所有通道(图像未更改)
0丢弃所有通道(图像为黑色)

怎么运行的

由于打高尔夫球,此解决方案比较混乱,但是这里有:

  1. 与阅读的第一个字节的低3位CBA,以及这些比特存储在它们相应的M埃默里细胞。同样,S在第一个周期增加输出。
  2. 重复循环这三个位。如果当前位打开,则关闭/开关以输出当前输入字节;如果关闭,则打开开关,以便我们输出零字节。
  3. 继续直到输入耗尽。

查看结果

当然,您可以使用hexdump或无聊的东西,但事实证明,这(几乎)是实际的有效图像格式:二进制Portable PixMap

只需将图像数据从上方(当然要减去控制字节)放入下面的文件中,将宽度/高度调整为有效,就可以在像IrfanView这样的适当查看器中查看图像,尽管更简单的查看器(例如大多数浏览器)内置)无法处理。

P6
{width as ASCII} {height as ASCII}
255
{binary image data here}

例如(对原始数据使用转义符):

P6
3 1
255
\xff\x00\x00\x00\xff\x00\x00\x00\xff

3

MATL,21 13字节

Yi3:iml&!*3YG

颜色通道应当使用下面的映射来指定:1:red2:green3:blue

在线解释器无法使用imread读取图像,因此这里是经过稍微修改的版本,其中我已将随机图像硬编码到源中

说明

        % Implicitly grab first input as a string (filename)
Yi      % Read the image in from a filename or URL
3:      % Push the string literal 'rgb' to the stack
i       % Grab the second input as a number
m       % Check for membership. So for example 2 will yield [false, true, false]
l&!     % Permute the dimensions to turn this 1 x 3 array into a 1 x 1 x 3 array
*       % Multiply this with the input RGB image. It will maintain the channel which
        % corresponds with the TRUE values and zero-out the channels that corresponded to
        % the FALSE values
3YG     % Display the image


2

Clojure,421332字节

-89个字节,通过积极地内联所有内容,从我原来的荒谬的剥离通道方法转变为过去,并摆脱了不必要的意外导入。

(import '(java.awt.image BufferedImage)'(clojure.lang Keyword)'(javax.imageio ImageIO)'(java.io File)'(java.awt Color))(fn[p i](doseq[y(range(.getHeight p))x(range(.getWidth p))](.setRGB p x y(.getRGB(apply #(Color. % %2 %3)(#(let[c(Color. %)](assoc [0 0 0]i(([(.getRed c)(.getGreen c)(.getBlue c)]%)i)))(.getRGB p x y))))))(ImageIO/write p"jpg"(File."./o.jpg")))

轮班开始前半小时,我不知所措。我对的经验不足BufferedImage,因此可能会有更好的方法。我也Color想在整数和单个通道的颜色表示之间来回转换。

与其他答案相比,这有很多可笑的地方,这有几个原因(除了Clojure显然不是高尔夫语言之外):

  • 实际上,这不仅是处理字节数组,还需要将图片作为输入,对其进行更改并输出。

  • 我正在使用Java-interop,虽然有时很方便,但它很方便。仅进口一项就比许多答案要大。

请参阅下面的代码进行细分。

(ns bits.restrict-channel
  (:import (java.awt.image BufferedImage)
           (clojure.lang Keyword)
           (javax.imageio ImageIO)
           (java.io File)
           (java.awt Color)))

(defn restrict-channel
  "Accepts a BufferedImage and a index between 0 and 2 (inclusive).
  Removes color from all channels EXCEPT the channel indicated by color-i.
  color-i of 0 = keep red
  color-i of 1 = keep green
  color-i of 2 = keep blue"
  [^BufferedImage image ^long color-i]
  (let [; Turn a number representing RGB into a triplet representing [R G B]
        channels #(let [c (Color. %)]
                    [(.getRed c) (.getGreen c) (.getBlue c)])

        ; Create a new triplet that only contains color in the color-i channel
        zero-channels #(assoc [0 0 0] color-i ((channels %) color-i))]

    ; Loop over each pixel
    (doseq [y (range (.getHeight image))
            x (range (.getWidth image))]

      ; Grab the current color...
      (let [cur-color (.getRGB image x y)]

        ; ... setting it to stripped color triplet returned by zero-channels
        (.setRGB image x y

                          ; This "apply" part is just applying the stripped triplet to the Color constructor
                         ;  This is needed to convert the separate channels into the integer representation that `BufferedImage` uses. 

                 (.getRGB (apply #(Color. % %2 %3) (zero-channels cur-color))))))

    ; Save the result to file
    (ImageIO/write image "jpg" (File. "./o.jpg"))))

这是我见过的最光荣或最恐怖的事情。我要和前者一起去。
Rɪᴋᴇʀ

@Riker绝对是前者。我开始轮班前半个小时开始写作,却不知道该怎么做。但这有效!
Carcigenicate

*我实际上是指后者,但光荣的混乱也是一回事。
Carcigenicate's

1

Lua(love2d框架),498字节

我更多地将其作为自己的练习,因此它虽然不算太短(尽管我确实尝试过打高尔夫球),但我想将其添加到此处,因为我认为我做得很好。即使我来不及。

在这里,高尔夫球代码是解释不完整的版本。

l=love g,p,rm,bm,gm,s=l.graphics,0,1,1,1,[[uniform float m[4];vec4 effect(vec4 co,Image t,vec2 c,vec2 s){vec4 p=Texel(t,c);p.r=p.r*m[0];p.b=p.b*m[1];p.g=p.g*m[2];return p;}]]t=g.setShader h=g.newShader(s)function l.draw()h:send("m",rm,gm,bm)if p~=0 then t(h)g.draw(p)t()end end function l.filedropped(f)a=f:getFilename()p=g.newImage(f)end function l.keypressed(k)if k=="0"then rm,gm,bm=1,1,1 end if k=="1"then rm,gm,bm=1,0,0 end if k=="2"then rm,gm,bm=0,1,0 end if k=="3"then rm,gm,bm=0,0,1 end end

这是必须将* .jpg文件放入其中的代码。插入图像后,您可以按红色(1)绿色(2)或蓝色(3)通道的数字按钮。同样要再次查看默认图片,请按0。实际上,它只是在窗口中显示图片。

l=love
g=l.graphics
p=0
rm,bm,gm=1,1,1
s = [[uniform float m[4];
vec4 effect(vec4 co,Image t,vec2 c,vec2 s){vec4 p=Texel(t,c);p.r = p.r * m[0];p.b = p.b * m[1]; p.g = p.g * m[2]; return p;}
]]
sh=g.newShader(s)

function l.draw()
  sh:send("m",rm,gm,bm)
  if p~=0 then
    g.setShader(sh)
    g.draw(p)
    g.setShader()
  end
end

function l.filedropped(f)
  a=f:getFilename()
  p=g.newImage(f)
end

function l.keypressed(k)
  if k=="0"then rm,gm,bm=1,1,1 end
  if k=="1"then rm,gm,bm=1,0,0 end
  if k=="2"then rm,gm,bm=0,1,0 end
  if k=="3"then rm,gm,bm=0,0,1 end
end

做所有工作的重要部分是着色器,它是开头或未缠结的小字符串声明:

uniform float m[4];
vec4 effect(vec4 co,Image t,vec2 c,vec2 s)
{
    vec4 p=Texel(t,c);
    p.r = p.r * m[0];
    p.b = p.b * m[1];
    p.g = p.g * m[2]; 
    return p;
}

它获取图像的实际像素,并仅根据需要显示通道。

我的测试图像和通道的不同输出(也可以肯定其他输出) 默认图像和通道图像合并


谢谢您的提示,下次我知道时,我
已将其修复

没问题!欢迎来到ppcg,希望您能坚持住!
Rɪᴋᴇʀ

此外,您仍然可以打高尔夫球。您不需要包括按钮等。
Rɪᴋᴇʀ

0

C, 60 58字节

main(a,b)char**b;{while(scanf(b[1],&a)>0)printf("%d ",a);}

图像输入是在上的0到255之间的数字列表(十进制)stdin,例如

255 0 0  192 192 192  31 41 59 ...

通道被指定为程序的第一个参数,并且是

red   -> "%d%*d%*d"
green -> "%*d%d%*d"
blue  -> "%*d%*d%d"

例:

$ echo "255 0 0" | ./extract "%d%*d%*d"
255 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.