Extraer un canal RGB de una imagen.

22

Dada una imagen, ya sea como entrada (posiblemente en tripletes RGB) o con el nombre de archivo como entrada (puede suponer que la imagen tiene un nombre de archivo específico, posiblemente sin extensión), genera una imagen que representa un solo canal de color de la imagen.

También tomará otra entrada, que representa qué canal emitir. La entrada puede ser uno de los 3 símbolos distintos. Sin embargo, los símbolos deben ser una cadena o un número. Sin embargo, no puede tomar una matriz para aplicarla a la matriz como entrada. (como {1, 0, 0}, o {0, 1, 0}).

Sacará el <input>canal de la imagen de entrada. Puede guardarlo en un archivo o generar un conjunto de pares RGB.

Su programa no debe tener límites en el tamaño de la imagen (en px) y debe admitir tripletas RGB .png, .jpg/ .jpeg/ .JPGo como formatos de imagen. (Sin embargo, puede admitir tantos como desee)

Caso de prueba:

violeta original

Canal rojo:

rojo violeta

Canal verde:

verde violeta

Canal azul:

azul violeta

Y otro caso de prueba, completamente de rojo. Foto original , rojo , verde y azul . (advertencia: el canal liso y rojo duele mirar demasiado tiempo)

2 casos de prueba más:

Original , rojo , verde , azul .

Original , rojo , verde , azul .

Los últimos dos casos de prueba son de Imágenes con todos los colores .

Rɪᴋᴇʀ
fuente
Esta es una buena inspiración para un lenguaje de golf que transpila / compila a las operaciones de OpenCV.
Restablece a Monica - ζ--

Respuestas:

2

APL (Dyalog) , 7 bytes

I / O: conjunto de tripletes RGB

⎕×⊂⎕=⍳3

Pruébalo en línea!

⍳3 primeros tres enteros

⎕= comparar la entrada numérica (el canal elegido) con ese

 adjuntar (para que cada triplete de imagen empareje este triplete completo)

⎕× multiplicar la entrada numérica (la matriz de tripletes) con eso

Adán
fuente
12

JavaScript (ES6), 29 bytes

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

La entrada es una matriz 2D de enteros de 24 bits (p [[0x0000ff,0x00ff00],[0xff0000,0xffffff]]. Ej. ) Y 16711680para rojo, 65280para verde y 255para azul. Si esto no es válido, intente esto en su lugar:

JavaScript (ES6), 48 bytes

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

La entrada es una matriz 3D de valores de color y 0para rojo, 1para verde y 2para azul.

ETHproducciones
fuente
1
Formato de entrada descarado jaja
Conor O'Brien
10

Mathematica, 13 bytes

ImageMultiply

Esta debería ser la versión legítima de la respuesta de JungHwan Min. Esta función toma la imagen y uno de Red, Green, Bluecomo entrada. Por ejemplo:

ingrese la descripción de la imagen aquí

Como dato curioso, también existe el ColorSeparateque le brinda canales individuales, pero los devuelve como imágenes de un solo canal / escala de grises, por lo que deberá multiplicarlos por el color de todos modos.

Martin Ender
fuente
¿Hay algo para lo que Mathematica no tenga incorporado?
Brian Minton
8

Bash + ImageMagick, 35 32 27 bytes

mogrify -channel $1 -fx 0 i

Asume la imagen está en el archivo i, y el guión toma uno de RG, BG, BRpara el azul, rojo y verde, respectivamente; salidas al archivo i.

Betseg
fuente
vencerme Publiqué una respuesta diferente de bash + IM a continuación, con una optimización que puedes robar
Sparr
@Sparr hice un golf diferente
betseg
¿Podrías guardar dos bytes con mogrify y sin 'o'?
Sparr
7

Espectro , no competitivo, 1 byte

(No compite porque este desafío inspiró este lenguaje). En realidad, Spectrum es una biblioteca npm con una interfaz de idioma para los comandos.

I

Toma entrada como:

<filename>
channel

Llame al programa como:

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

Alternativamente, puede proporcionar información a las indicaciones:

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

Esto deja la imagen en la pila. Para verlo, agregue Oal final, así:

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

Para un poco de diversión extra, inténtalo echo filename | node spectrum.js "wO". Realiza los tres aislamientos de canal a la vez:

Warhol

Conor O'Brien
fuente
1
@ThisGuy Sí, puede hacer una comprobación de primalidad:n[d1=`[d1-P*][],.g!]#Pdd1-P~%-1=p
Conor O'Brien
1
@ ConorO'Brien, ¿viste mi probador de primalidades para el operador de FX de ImageMagick?
Sparr
@Sparr no, no lo he hecho. ¿Enlazar?
Conor O'Brien
7

JavaScript (ES6), 29 bytes

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

Muy parecido a la respuesta de ETHproductions pero con una entrada más flexible que el primer método y más pequeña que el segundo.

Esto define una función que acepta la imagen como una matriz unidimensional de intensidades numéricas de color. Esta función luego devuelve otra función que acepta un valor entero que representa el canal de color deseado.

Los colores se pueden representar mediante cualquier rango numérico siempre que 0 indique una ausencia completa de color. Por ejemplo 0.0 - 1.0o0 - 255

Ejemplos:

Si los datos de la imagen tienen el formato RGB, al llamar a la función con argumentos (imageData)(0), la imagen se devolverá solo con el canal rojo.

Si los datos de la imagen están en el formato BGR, la llamada a la función con argumentos (imageData)(2)también devolverá la imagen solo con el canal rojo.

Programador pragmático
fuente
Supongo que i%3==b&&vtambién funciona.
Neil
6

Python 2, 69 bytes

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

Todavía jugando al golf.

Toma la entrada como filename, n(donde nes 0, 1 o 2). Guarda la nueva imagen sobre la anterior. 0es verde, 1es rojo y 2es azul. Gracias a @ovs, @Mikhail y @Rod por los bytes desactivados.

Rɪᴋᴇʀ
fuente
Ahorre algunos bytes al soltar x y reemplazar k[:,:,x[i][0]]=k[:,:,x[i][1]]=0conk[:,:,[1,2,0][i]]=k[:,:,i]=0
ovs
@ovs ¡gracias! ... En realidad, acababa de hacer la segunda sugerencia, después de jugar con la tuya. Sin embargo, me hiciste ninja.
Rɪᴋᴇʀ
Puede usar from cv2 import*para guardar algunos bytes
Rod
Parece que se puede sustituir k[:,:,i-1]=k[:,:,i]=0conk[:,:,[i,i-1]]=0
Mikhail V
5

CJam , 12 bytes

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

Un bloque anónimo que espera una matriz 3D de tripletes RGB y un número entre 0 y 2 inclusive en la pila. Deja la matriz extraída en la pila después.

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

Posiblemente podría jugar golf usando un formato de entrada extraño, pero siento que eso es un poco trampa.

Pruébalo en línea!

El caso de prueba está hecho solo para demostrarlo, usar los trillizos de una imagen real sería demasiado grande.

Explicación

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)
Gato de negocios
fuente
5

PowerShell , 282 bytes

$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")

Nada de esto es lujoso "jugar al golf" o "usar incorporados". Phooey en eso. ;-)

Esto aquí toma la ruta completa de un PNG de entrada (aunque, estrictamente hablando, no necesita ser un PNG, ya que JPG, BMP, etc. son compatibles con .NET, pero solo lo he probado en PNG), y uno (R, G, B)para el canal de color, luego los almacena en $xy $y. Luego creamos un New-Objecttipo System.Drawing.Bitmapde $xy lo almacenamos $a.

Luego hacemos un doble bucle sobre todos los píxeles. Primero desde 1hasta $a's .Height, el establecimiento de $hcada iteración (que es un índice de cero, por lo que es por eso que --$_, lo que ahorra más de bytes ( .height-1). En el interior, nos bucle desde 1hasta $a' s .Width.

Cada iteración, estamos realizando un .GetPixelen las w,hcoordenadas particulares , que devuelve un System.Drawing.Colorobjeto. Sacamos selectlos R G Bvalores de los mismos. El iexaquí es un buen truco que convierte esto en una tabla hash (por ejemplo, algo así @{R=34; G=177; B=76}) para que podamos índice en que directamente con el canal de color deseada [$y]. Ese valor se almacena en $i.

A continuación, establecemos tres valores $r, $g, $bpara que sean el resultado de algunos operadores pseudoternarios basados ​​en el valor de la letra de $y. Entonces, por ejemplo, si $yes R, entonces el resultado aquí es $r=$i, $g=0, $b=0.

Luego, hacemos una .SetPixelcopia de seguridad de esa w,hcoordenada en particular , construyendo una nueva System.Drawing.Colorutilizando la estática FromARGB(que supone que el alfa es completamente opaco). Una vez que hayamos terminado el bucle, simplemente pasaremos .Saveel PNG a un nuevo archivo.

Nota: Esto lleva mucho tiempo, ya que recorre cada píxel de forma completamente independiente y realiza varios cálculos y llama a cada iteración.

Pruebas:
AdmBorkBork Red AdmBorkBork Green AdmBorkBork Blue

AdmBorkBork
fuente
3

Bash + ImageMagick, 41 bytes

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

La entrada es un archivo llamado x, línea de comando parámetro uno de Ro GoB

La salida sobrescribe el archivo de entrada

Se diferencia de la respuesta de betseg al tomar un parámetro de canal de una sola letra más natural. También sobrescribe en lugar de generar un nuevo archivo que betseg es libre de robar :)

Sparr
fuente
las $1comillas necesitan, los nombres de archivo pueden tener espacios
betseg
@betseg no realmente, dije que puedes asumir que tiene un nombre de archivo específico. Si lo desea, incluso puede cambiarlo para leerlo desde un nombre de archivo xdurante 1 byte.
Rɪᴋᴇʀ
@Riker oh, no me di cuenta de eso, eso también me ayuda: D
betseg
3

Chip , 78 bytes

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

Pruébalo en línea!

Chip es un lenguaje 2D que opera en los bits componentes de cada byte en una secuencia de bytes.

Visión general

Esta solución particular espera que el primer byte de entrada sea el carácter de control, para definir qué canal (es) mantener, y los siguientes son los bytes de datos de imagen. Los datos de la imagen deben ser tripletes RGB, un byte por canal, 24 bits por píxel:

|  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 |

El carácter de control se interpreta como un campo de bits, aunque solo los tres bits más bajos tienen significado:

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

Esto significa que podemos usar caracteres ASCII para seleccionar qué canal queremos:

1 significa rojo
2 significa azul
4significa verde

O haz algo más elegante:

5 mantener rojo y azul, pero no verde
7 mantener todos los canales (la imagen no cambia)
0soltar todos los canales (la imagen es negra)

Cómo funciona

Esta solución es bastante complicada debido al golf, pero aquí va:

  1. Leer los tres bits bajos del primer byte con C, By A, y almacenar los bits en sus correspondientesM células de Emory. Además, Spresione hacia arriba la salida para el primer ciclo.
  2. Recorre esos tres bits repetidamente. Si el bit actual está activado, cierre el/ está activado interruptores para generar el byte de entrada actual; si está apagado, abra los interruptores para que generemos un byte cero.
  3. Continúe hasta que se agote la entrada.

Ver los resultados

Claro, podría usar hexdump o algo aburrido, pero resulta que este es (casi) un formato de imagen válido real: PixMap portátil binario .

Simplemente coloque los datos de la imagen desde arriba (menos el byte de control, por supuesto) en el archivo a continuación, ajuste el ancho / alto para que sea válido, y puede ver la imagen en un visor adecuado como IrfanView, aunque más simples (como la mayoría del navegador incorporado) no puede manejarlo.

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

Por ejemplo (usando escapes para los datos sin procesar):

P6
3 1
255
\xff\x00\x00\x00\xff\x00\x00\x00\xff
Phlarx
fuente
3

MATL, 21 13 bytes

Yi3:iml&!*3YG

El canal de color debe ser especificado utilizando el siguiente mapeo: 1:red, 2:green,3:blue

Los intérpretes en línea no pueden usar imreadpara leer imágenes, así que aquí hay una versión ligeramente modificada donde he codificado una imagen aleatoria en la fuente .

Explicación

        % 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
Suever
fuente
2

05AB1E , 16 bytes

vyvy2ô²è}})¹0ègô

Pruébalo en línea!

Utiliza colores hexadecimales en un formato de matriz 2D y [0,1,2] para cada canal.

Urna de pulpo mágico
fuente
2

Clojure, 421 332 bytes

-89 bytes al incluir todo agresivamente, cambiar mi viejo método ridículo de quitar los canales y deshacerse de una importación accidental innecesaria.

(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")))

Golpeé esto media hora antes de que mi turno comenzara sin tener idea de lo que estaba haciendo. Tengo poca experiencia BufferedImage, por lo que puede haber una mejor manera de hacerlo. También estoy abusandoColor de convertir de ida y vuelta entre enteros y representaciones de colores de canales individuales.

Esto es cómicamente enorme en comparación con las otras respuestas por un par de razones (además de lo obvio que Clojure no es un lenguaje de golf):

  • En lugar de simplemente manipular una matriz de bytes, esto realmente toma como entrada una imagen, la altera y la emite.

  • Estoy usando Java-interop, que si bien es útil, a veces puede ser bastante detallado. Las importaciones solas son mayores que muchas respuestas.

Vea el código a continuación para un desglose.

(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"))))
Carcigenicate
fuente
Esta es la cosa más gloriosa u horrible que he visto. Me voy con el primero.
Rɪᴋᴇʀ
@Riker Definitivamente el primero. Comencé a escribir esto media hora antes de que comenzara mi turno sin tener idea de cómo iba a hacerlo. ¡Pero funciona!
Carcigenicate
* En realidad me refería a esto último, pero los desordenes gloriosos también son una cosa.
Carcigenicate
1

Lua (marco love2d), 498 bytes

Hice esto más como un ejercicio para mí, así que no es tan corto como podría ser (aunque intenté jugar al golf), pero quería agregarlo aquí porque creo que lo hice bien. Incluso si llego demasiado tarde.

Aquí el código de golf, debajo está la versión explicada y desenredada.

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

Aquí está el código que debe incluir un archivo * .jpg. Después de insertar la imagen, puede presionar los botones numéricos para los canales rojo (1) verde (2) o azul (3). También para ver la imagen predeterminada nuevamente, presione 0. En realidad, solo muestra la imagen en la ventana.

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

La parte importante que hace todo el trabajo es el sombreador, que es la declaración de cadena pequeña al principio o desenredada:

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;
}

que obtiene el píxel real de la imagen y solo muestra los canales según sea necesario.

Mi imagen de prueba y las diferentes salidas para los canales (también seguro que los otros) imagen predeterminada e imágenes de canal fusionadas

Lycea
fuente
Gracias por su sugerencia, lo arreglé, la próxima vez que lo sepa :)
Lycea
¡No hay problema! Bienvenido a ppcg, ¡espero que te quedes!
Rɪᴋᴇʀ
Además, todavía puedes jugar al golf. No necesita incluir los botones y tal.
Rɪᴋᴇʀ
0

C, 60 58 bytes

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

La entrada de imagen es una lista de números (en decimal) entre 0 y 255 stdin, p. Ej.

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

El canal se especifica como el primer argumento para el programa y es uno de

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

Ejemplo:

$ echo "255 0 0" | ./extract "%d%*d%*d"
255 
nneonneo
fuente