Extrair um canal RGB de uma imagem


22

Dada uma imagem, como entrada (possivelmente em trigêmeos RGB) ou com o nome do arquivo como entrada (você pode assumir que a imagem tem um nome de arquivo específico, possivelmente sem extensão), produza uma imagem representando um único canal de cor da imagem.

Você também fará outra entrada, representando qual canal sair. A entrada pode ser um dos três símbolos distintos. No entanto, os símbolos devem ser uma sequência ou um número. Você não pode utilizar uma matriz para aplicar à matriz como entrada. (tal como{1, 0, 0} , ou {0, 1, 0}).

Você emitirá o <input> canal da imagem de entrada. Você pode salvá-lo em um arquivo ou gerar um conjunto de pares RGB.

Seu programa não deve ter limites no tamanho da imagem (em px) e deve suportar .png, .jpg/ .jpeg/.JPG , ou RGB trigêmeos como formatos de imagem. (ele pode suportar quantos você quiser)

Caso de teste:

violeta original

Canal vermelho:

vermelho violeta

Canal verde:

verde violeta

Canal azul:

azul violeta

E outro caso de teste, totalmente em vermelho. Foto original , vermelha , verde e azul . (aviso: o canal liso e vermelho doem ao olhar por muito tempo)

Mais 2 casos de teste:

Original , vermelho , verde , azul .

Original , vermelho , verde , azul .

Os dois últimos casos de teste são de Imagens com todas as cores .


Isso é uma boa inspiração para uma linguagem de golfe que transpila / compila para operações OpenCV.
Reinstate Monica - Mar-- 30/03

Respostas:


2

APL (Dyalog) , 7 bytes

E / S: matriz de trigêmeos RGB

⎕×⊂⎕=⍳3

Experimente online!

⍳3 primeiros três inteiros

⎕= comparar a entrada numérica (o canal escolhido) com a

 delimite (para que cada trigêmeo de imagem emparelhe esse trigêmeo inteiro)

⎕× multiplicar a entrada numérica (a matriz de trigêmeos) com essa


12

JavaScript (ES6), 29 bytes

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

A entrada é uma matriz 2D de números inteiros de 24 bits (por exemplo [[0x0000ff,0x00ff00],[0xff0000,0xffffff]]) e 16711680para vermelho, 65280para verde, 255para azul. Se isso não for válido, tente o seguinte:

JavaScript (ES6), 48 bytes

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

A entrada é uma matriz 3D de valores de cores e 0para vermelho, 1verde e 2azul.


1
Formato de entrada atrevido haha
Conor O'Brien

10

Mathematica, 13 bytes

ImageMultiply

Essa deve ser a versão legítima da resposta de JungHwan Min. Esta função recebe a imagem e um dos Red, Green, Bluecomo entrada. Por exemplo:

insira a descrição da imagem aqui

Como um fato divertido, também há ColorSeparatecanais que oferecem canais individuais, mas os retornam como imagens de canal único / escala de cinza, para que você precise multiplicá-los pela cor posteriormente de qualquer maneira.


Existe algo para o qual o Mathematica não tenha um built-in?
27717 Brian Minton

8

Bash + ImageMagick, 35 32 27 bytes

mogrify -channel $1 -fx 0 i

Assume a imagem está no arquivo ieo script leva um dos RG, BG, BRpara o azul, vermelho e verde, respectivamente; saídas para o arquivo i.


me derrote. Eu postei uma festança resposta diferente + IM abaixo, com uma otimização você pode roubar
Sparr

@Sparr Eu fiz um golfe diferente
betseg 29/03

você ainda pode salvar dois bytes com mogrify e sem 'o'?
Sparr

7

Espectro , não competidor, 1 byte

(Não competindo porque esse desafio inspirou esse idioma.) Na realidade, o Spectrum é uma biblioteca npm com uma interface de idioma para os comandos.

I

Toma entrada como:

<filename>
channel

Chame o programa como:

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

Como alternativa, você pode fornecer informações para os prompts:

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

Isso deixa a imagem na pilha. Para visualizá-lo, adicione Ono final, da seguinte forma:

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

Para um pouco de diversão extra, tente echo filename | node spectrum.js "wO". Ele executa todos os três isolamentos de canal de uma vez:

Warhol


1
@ThisGuy Sim, ele pode fazer a verificação de primalidade:n[d1=`[d1-P*][],.g!]#Pdd1-P~%-1=p
Conor O'Brien

1
@ ConorO'Brien, você viu meu testador de primalidade para o operador fx do ImageMagick?
Sparr

@ Sparr não, eu não tenho. Ligação?
Conor O'Brien


7

JavaScript (ES6), 29 bytes

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

Muito parecido com a resposta da ETHproductions, mas com uma entrada mais flexível que o primeiro método e menor que o segundo.

Isso define uma função que aceita a imagem como uma matriz unidimensional de intensidades numéricas de cores. Essa função retorna outra função que aceita um valor inteiro representando o canal de cores desejado.

As cores podem ser representadas por qualquer intervalo numérico, desde que 0 indique uma completa ausência de cor. Por exemplo, 0.0 - 1.0ou0 - 255

Exemplos:

Se os dados da imagem estiverem no formato RGB, chame a função com argumentos (imageData)(0) retornará a imagem apenas com o canal vermelho.

Se os dados da imagem estiverem no formato BGR, a chamada da função com argumentos (imageData)(2)também retornará a imagem apenas com o canal vermelho.


Eu acho que i%3==b&&vtambém funciona.
911 Neil

6

Python 2, 69 bytes

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

Ainda jogando golfe.

Recebe a entrada como filename, n(onde né 0, 1 ou 2). Salva a nova imagem sobre a antiga. 0é verde, 1é vermelho e 2é azul. Obrigado a @ovs, @Mikhail e @Rod pelos bytes desativados.


Salve alguns bytes soltando x e substituindo k[:,:,x[i][0]]=k[:,:,x[i][1]]=0pork[:,:,[1,2,0][i]]=k[:,:,i]=0
ovs 29/03

@ovs obrigado! ... Na verdade, eu tinha acabado de fazer a segunda sugestão, depois de mexer na sua. Você me ninja'ed embora.
Rɪᴋᴇʀ

Você pode usar from cv2 import*para salvar alguns bytes
Rod

Parece que você pode substituir k[:,:,i-1]=k[:,:,i]=0pork[:,:,[i,i-1]]=0
Mikhail V

5

CJam , 12 bytes

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

Um bloco anônimo que espera uma matriz 3D de trigêmeos RGB e um número entre 0 e 2, inclusive na pilha. Deixa a matriz extraída na pilha posteriormente.

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

Pode ser possível jogar golfe usando um formato de entrada bizarro, mas eu sinto que isso é trapaça.

Experimente online!

O caso de teste é composto apenas para demonstrar, o uso dos trigêmeos de uma imagem real seria muito grande.

Explicação

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 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 disso gosta de "jogar a entrada" ou "usar built-ins". Phooey nisso. ;-)

Isso aqui segue o caminho completo de um PNG de entrada (embora, estritamente falando, ele não precise ser um PNG, pois JPG, BMP etc. são suportados pelo .NET, mas eu só tentei em PNGs), e um (R, G, B)para o canal de cores, depois os armazena em $xe $y. Em seguida, criamos um New-Objecttipo System.Drawing.Bitmapde $xe armazenamos isso em$a .

Em seguida, fazemos um loop duplo sobre todos os pixels. Primeiro de 1até $a's .Height, definindo $hcada iteração (é zero indexados, então é por isso que nós --$_, o que economiza bytes mais ( .height-1). No interior, circuito de 1até $a' s .Width.

Cada iteração, estamos realizando um .GetPixel nas w,hcoordenadas específicas , que retornam um System.Drawing.Colorobjeto. Nós selectexpomos os R G Bvalores dos mesmos. A iexaqui é um truque que transforma isso em uma tabela hash (por exemplo, algo como @{R=34; G=177; B=76}) para que possamos índice em que diretamente com o canal de cor desejada [$y]. Esse valor é armazenado em$i .

Em seguida, definimos três valores $r, $g, $bpara serem o resultado de alguns operadores pseudo-ternários com base no valor da letra de $y. Então, por exemplo, se $yfor R, então o resultado aqui é $r=$i, $g=0, $b=0.

Em seguida, .SetPixelretornamos a essa w,hcoordenada específica , construindo um novo System.Drawing.Colorusando a estática FromARGB(que assume que o alfa é totalmente opaco). Depois de terminar o loop, simplesmente .Saveo PNG para um novo arquivo.

Nota: Isso leva um longo tempo, já que percorre todos os pixels de forma independente e executa vários cálculos e chama cada iteração.

Testes:
AdmBorkBork Red AdmBorkBork Green AdmBorkBork Blue


3

Bash + ImageMagick, 41 bytes

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

Entrada é um arquivo chamado x, parâmetro de linha de comando um de Rou GouB

Saída substitui o arquivo de entrada

Difere da resposta da betseg ao aceitar parâmetros de canal de letra única mais naturais. Também sobrescreve em vez de emitir um novo arquivo que o betseg é livre para roubar :)


o $1precisa de aspas, os nomes de arquivo pode ter espaços
betseg

@ betseg não, na verdade, eu disse que você pode assumir que ele tem um nome de arquivo específico. Se ele quiser, ele pode mudar para ler um nome de arquivo xcom 1 byte de desconto.
Rɪᴋᴇʀ

@Riker oh, eu não percebi isso, isso também me ajuda: D
betseg 29/03

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

Experimente online!

Chip é uma linguagem 2D que opera nos bits componentes de cada byte em um fluxo de bytes.

visão global

Essa solução específica espera que o primeiro byte de entrada seja o caractere de controle - para definir quais canais manter - e a seguir estão os bytes dos dados da imagem. Os dados da imagem devem ser trigêmeos RGB, um byte por canal, 24 bits por pixel:

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

O caractere de controle é interpretado como um campo de bit, embora apenas os três bits mais baixos tenham significado:

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

Isso significa que podemos usar caracteres ASCII para selecionar qual canal queremos:

1significa vermelho
2significa azul
4significa verde

Ou faça algo mais sofisticado:

5mantenha vermelho e azul, mas não verde
7mantenha todos os canais (a imagem permanece inalterada)
0 solte todos os canais (a imagem é preta)

Como funciona

Esta solução é bastante confusa devido ao golfe, mas aqui vai:

  1. Ler os três baixas bits do primeiro byte com C, Be A, e armazenar os bits na sua correspondenteM células Emory. Além disso, Spressione a saída para o primeiro ciclo.
  2. Repita esses três bits repetidamente. Se o bit atual estiver ativado, feche o/ comutadores para gerar o byte de entrada atual; se estiver desativado, abra os comutadores para gerar um byte zero.
  3. Continue até a entrada se esgotar.

Visualizando os resultados

Claro, você pode usar hexdump ou algo chato, mas acontece que este é (quase) um formato de imagem válido real: binário PixMap portátil .

Basta colocar os dados da imagem de cima (menos o byte de controle, é claro) no arquivo abaixo, ajustar a largura / altura para que sejam válidos e você pode ver a imagem em um visualizador adequado como o IrfanView, embora os mais simples (como a maioria dos navegadores) embutidos) não pode lidar com isso.

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

Por exemplo (usando escapes para os dados brutos):

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

3

MATL, 21 13 bytes

Yi3:iml&!*3YG

O canal de cor deve ser especificada utilizando o seguinte mapeamento: 1:red, 2:green,3:blue

Os intérpretes on-line não podem usar imreadpara ler imagens, então aqui está uma versão ligeiramente modificada na qual codifiquei uma imagem aleatória na fonte .

Explicação

        % 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, 421 332 bytes

-89 bytes , incorporando tudo agressivamente, mudando do meu velho e ridículo método de descascar os canais e eliminando uma importação acidental desnecessária.

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

Chequei isso meia hora antes do meu turno começar, sem ideia do que eu estava fazendo. Eu tenho pouca experiência com BufferedImage, então pode haver uma maneira melhor de fazer isso. Também estou abusando Colorda conversão entre representações de cores de canais inteiros e individuais.

Isso é cômico em comparação com as outras respostas por algumas razões (além do óbvio que Clojure não é uma linguagem de golfe):

  • Em vez de apenas manipular uma matriz de bytes, isso realmente leva como entrada uma imagem, altera-a e gera-a.

  • Estou usando a interoperabilidade Java, que, embora útil, pode ser bem detalhada às vezes. Somente as importações são maiores que muitas respostas.

Veja o código abaixo para uma análise detalhada.

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

Essa é a coisa mais gloriosa ou horrível que eu já vi. Eu vou com o primeiro.
Rɪᴋᴇʀ

@Riker Definitivamente o primeiro. Comecei a escrever meia hora antes do meu turno começar, sem ter idéia de como eu iria fazê-lo. Mas funciona!
Carcigenicate

* Na verdade, eu quis dizer o último, mas bagunças gloriosas também são importantes.
Carcigenicate

1

Lua (estrutura do love2d), 498 bytes

Fiz isso mais como um exercício para mim, por isso não é tão curto quanto poderia ser (embora eu tenha tentado jogar golfe), mas eu queria adicioná-lo aqui porque acho que fiz o bem. Mesmo que seja tarde demais.

Aqui o código do golfe, abaixo dele, é a versão explicada e desembaraçada.

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

Aqui está o código que deve obter um arquivo * .jpg nele. Após a inserção da imagem, você pode pressionar as teclas numéricas dos canais vermelho (1) verde (2) ou azul (3). Também para ver a imagem padrão novamente, pressione 0. Na verdade, apenas mostra a imagem na janela.

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

A parte importante que faz todo o trabalho é o shader, que é a pequena declaração de string no início ou desembaraçada:

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 obtém o pixel real da imagem e mostra apenas os canais conforme necessário.

Minha imagem de teste e as diferentes saídas para os canais (também com certeza os outros) imagem padrão e imagens de canal mescladas


Obrigado por sua sugestão, eu fixa-lo, da próxima vez eu sei :)
Lycea

Sem problemas! Bem-vindo ao ppcg, espero que você fique por aqui!
Rɪᴋᴇʀ

Além disso, você ainda pode jogar golfe. Você não precisa incluir os botões e tal.
Rɪᴋᴇʀ

0

C, 60 58 bytes

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

A entrada de imagem é uma lista de números (em decimal) entre 0 e 255 stdin, por exemplo,

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

O canal é especificado como o primeiro argumento para o programa e é um dos

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

Exemplo:

$ echo "255 0 0" | ./extract "%d%*d%*d"
255 
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.