Estrai un canale RGB di un'immagine


22

Dato un'immagine, o come input (possibilmente in terzine RGB) o con il nome file come input (si può supporre che l'immagine abbia un nome file specifico, possibilmente senza estensione), emette un'immagine che rappresenta un singolo canale di colore dell'immagine.

Prenderai anche un altro input, che rappresenta quale canale emettere. L'ingresso può essere uno di 3 simboli distinti. Tuttavia, i simboli devono essere una stringa o un numero. Tuttavia, non è possibile utilizzare una matrice da applicare all'array come input. (come {1, 0, 0}, o {0, 1, 0}).

Verrà emesso il <input>canale dell'immagine di input. È possibile salvarlo in un file o generare un set di coppie RGB.

Il vostro programma non dovrebbe avere limiti alle dimensioni dell'immagine (in px), e deve supportare sia .png, .jpg/ .jpeg/ .JPGo RGB triplette come formati di immagine. (può supportare quanti ne vuoi comunque)

Caso di prova:

originale viola

Canale Rosso:

rosso violetto

Canale Verde:

verde viola

Canale blu:

blu viola

E un altro caso di test, interamente di colore rosso. Foto originale , rosso , verde e blu . (attenzione: il canale semplice e rosso fa male a guardare troppo a lungo)

Altri 2 casi di test:

Originale , rosso , verde , blu .

Originale , rosso , verde , blu .

Gli ultimi due casi di test provengono da immagini con tutti i colori .


Questa è una buona fonte d'ispirazione per un linguaggio del golf che traspila / compila alle operazioni OpenCV.
Ripristina Monica - ζ--

Risposte:


2

APL (Dyalog) , 7 byte

I / O: array di terzine RGB

⎕×⊂⎕=⍳3

Provalo online!

⍳3 primi tre numeri interi

⎕= confronta l'input numerico (il canale scelto) con quello

 allegare (quindi ogni tripletta di immagine accoppia l'intera tripletta)

⎕× moltiplica l'input numerico (l'array di terzine) con quello


12

JavaScript (ES6), 29 byte

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

L'input è un array 2D di numeri interi a 24 bit (ad es. [[0x0000ff,0x00ff00],[0xff0000,0xffffff]]) E 16711680per il rosso, 65280per il verde, 255per il blu. Se questo non è valido, prova invece:

JavaScript (ES6), 48 byte

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

L'input è un array 3D di valori di colore e 0per il rosso, 1per il verde, 2per il blu.


1
Sfacciato formato di input haha
Conor O'Brien

10

Mathematica, 13 byte

ImageMultiply

Questa dovrebbe essere la versione legittima della risposta di JungHwan Min. Questa funzione prende l'immagine e uno Red, Green, Bluecome input. Per esempio:

enter image description here

Come fatto divertente, c'è anche quello ColorSeparateche ti dà i singoli canali, ma li restituisce come immagini a canale singolo / scala di grigi, quindi dovresti comunque moltiplicarli per il colore in seguito.


C'è qualcosa per cui Mathematica non ha un built-in?
Brian Minton,

8

Bash + ImageMagick, 35 32 27 byte

mogrify -channel $1 -fx 0 i

Assume l'immagine è nel file ie lo script prende una delle RG, BG, BRper il blu, rosso e verde, rispettivamente; output al file i.


battimi. Di seguito ho pubblicato una risposta bash + IM diversa, con un'ottimizzazione che puoi rubare
Sparr

@Sparr Ho fatto un golf diverso
betseg il

potresti ancora salvare due byte con mogrify e senza 'o'?
Sparr,

7

Spettro , non competitivo, 1 byte

(Non competere perché questa sfida ha ispirato questo linguaggio.) In realtà, Spectrum è una libreria npm con un'interfaccia linguistica per i comandi.

I

Accetta input come:

<filename>
channel

Chiama il programma come:

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

In alternativa, è possibile fornire informazioni ai prompt:

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

Questo lascia l'immagine in pila. Per vederlo, aggiungi Oalla fine, in questo modo:

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

Per un po 'di divertimento in più, prova echo filename | node spectrum.js "wO". Esegue tutti e tre gli isolamenti dei canali contemporaneamente:

warhol


1
@ThisGuy Sì, può fare il controllo della primalità:n[d1=`[d1-P*][],.g!]#Pdd1-P~%-1=p
Conor O'Brien

1
@ ConorO'Brien hai visto il mio tester di primalità per l'operatore fx di ImageMagick?
Sparr,

@Sparr no, non l'ho fatto. Link?
Conor O'Brien,


7

JavaScript (ES6), 29 byte

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

Un po 'come la risposta di ETHproductions ma con input più flessibili del primo metodo e più piccoli del secondo.

Questo definisce una funzione che accetta l'immagine come una matrice monodimensionale di intensità di colore numeriche. Questa funzione restituisce quindi un'altra funzione che accetta un valore intero che rappresenta il canale di colore desiderato.

I colori possono essere rappresentati da qualsiasi intervallo numerico purché 0 indichi una completa assenza di colore. Ad esempio 0.0 - 1.0o0 - 255

Esempi:

Se i dati dell'immagine sono nel formato RGB, la chiamata della funzione con argomenti (imageData)(0)restituirà l'immagine con solo il canale rosso.

Se i dati dell'immagine sono nel formato BGR, la chiamata della funzione con argomenti (imageData)(2)restituirà anche l'immagine con solo il canale rosso.


Immagino che funzioni i%3==b&&vanche.
Neil

6

Python 2, 69 byte

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

Ancora golf.

Accetta input come filename, n(dove nè 0, 1 o 2). Salva la nuova immagine sopra quella vecchia. 0è verde, 1è rosso ed 2è blu. Grazie a @ovs, @Mikhail e @Rod per byte disattivati.


Salva alcuni byte rilasciando x e sostituendoli k[:,:,x[i][0]]=k[:,:,x[i][1]]=0conk[:,:,[1,2,0][i]]=k[:,:,i]=0
ovs

@ovs grazie! ... In realtà mi ero appena inventato il secondo suggerimento, dopo aver rovinato il tuo. Mi hai fatto il ninja.
Rɪᴋᴇʀ

È possibile utilizzare from cv2 import*per salvare pochi byte
Rod

Sembra che puoi sostituirlo k[:,:,i-1]=k[:,:,i]=0conk[:,:,[i,i-1]]=0
Mikhail V,

5

CJam , 12 byte

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

Un blocco anonimo che prevede una matrice 3D di terzine RGB e un numero compreso tra 0 e 2 incluso nello stack. Lascia l'array estratto in pila successivamente.

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

Potrebbe essere possibile giocare a golf usando un formato di input bizzarro, ma mi sembra che questo stia tradendo un po '.

Provalo online!

Il caso di prova è inventato solo per dimostrare, usare le terzine da un'immagine reale sarebbe troppo grande.

Spiegazione

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 byte

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

Nessuna di queste fantasiose "giocate a golf sull'input" o "usando i built-in". Phooey su quello. ;-)

Questo qui prende l'intero percorso di un PNG di input (sebbene, a rigor di termini, non debba essere un PNG, poiché JPG, BMP, ecc. Sono supportati da .NET, ma l'ho provato solo su PNG), e uno (R, G, B)per il canale colore, quindi memorizza quelli in $xe $y. Quindi creiamo un New-Objecttipo System.Drawing.Bitmapdi $xe lo memorizziamo in $a.

Quindi eseguiamo un doppio ciclo su tutti i pixel. Innanzitutto da 1up a $a's .Height, impostando $hogni iterazione (è a zero, quindi è per questo che --$_, che salva i byte sopra ( .height-1). All'interno, eseguiamo il loop da 1fino a $a' s.Width .

Ad ogni iterazione, stiamo eseguendo una .GetPixelsulle w,hcoordinate particolari , che restituisce un System.Drawing.Coloroggetto. Ne selectesaltiamo i R G Bvalori. Il iexqui è un trucco che trasforma questo in una tabella hash (ad esempio, qualcosa di simile @{R=34; G=177; B=76}) e quindi siamo in grado di indicizzare in quella direttamente con il canale di colore desiderato [$y]. Quel valore è archiviato in $i.

Successivamente, impostiamo tre valori $r, $g, $bper essere il risultato di alcuni operatori pseudo-ternari in base al valore della lettera di $y. Quindi, ad esempio, se lo $yè R, il risultato qui è $r=$i, $g=0, $b=0.

Quindi, facciamo un .SetPixelpasso indietro su quella particolare w,hcoordinata, costruendone una nuova System.Drawing.Colorusando lo statico FromARGB(che assume che l'alfa sia completamente opaco). Una volta terminato il loop, quindi semplicemente .Saveil PNG in un nuovo file.

Nota: questo richiede molto tempo, poiché esegue il ciclo in modo completamente indipendente su ogni pixel ed esegue un sacco di calcoli e chiama ogni iterazione.

test:
AdmBorkBork Red AdmBorkBork Green AdmBorkBork Blue


3

Bash + ImageMagick, 41 byte

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

L'input è un file denominato x, parametro della riga di comando uno di RoG oB

L'output sovrascrive il file di input

Si differenzia dalla risposta di betseg nel prendere un parametro di canale a lettera singola più naturale. Anche sovrascrivere invece di emettere un nuovo file che betseg è libero di rubare :)


le $1virgolette necessarie, i nomi dei file possono avere spazi
betseg

@betseg non proprio, ho detto che puoi presumere che abbia un nome file specifico. Se lo desidera, può anche cambiarlo per leggere da un nome file xper 1 byte di sconto.
Rɪᴋᴇʀ

@Riker oh, non me ne sono accorto, anche questo mi aiuta: D
Betseg

3

Chip , 78 byte

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

Provalo online!

Chip è un linguaggio 2D che opera sui bit componenti di ciascun byte in un flusso di byte.

Panoramica

Questa particolare soluzione prevede che il primo byte di input sia il carattere di controllo - per definire quale / i canale / i da conservare - e i seguenti sono i byte di dati immagine. I dati dell'immagine devono essere triplette RGB, un byte per canale, 24 bit per 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 |

Il carattere di controllo viene interpretato come un campo di bit, sebbene solo i tre bit più bassi abbiano un significato:

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

Ciò significa che possiamo usare i caratteri ASCII per selezionare quale canale vogliamo:

1significa rosso
2significa blu
4 significa verde

O fai qualcosa di più elaborato:

5mantieni rosso e blu, ma non verde
7mantieni tutti i canali (l'immagine è invariata)
0 elimina tutti i canali (l'immagine è nera)

Come funziona

Questa soluzione è piuttosto confusa a causa del golf, ma ecco qui:

  1. Leggere i tre bit meno significativi del primo byte con C, Be A, e memorizzare i bit nelle corrispondenti Mcelle Emory. Anche,S sovraccaricare l'output per il primo ciclo.
  2. Ripeti ripetutamente questi tre bit. Se il bit corrente è attivo, chiudere il/ interruttori per emettere il byte di ingresso corrente, se è spento, aprire gli interruttori in modo da emettere un byte zero.
  3. Continua fino a quando l'input è esaurito.

Visualizzazione dei risultati

Certo, potresti usare hexdump o qualcosa di noioso, ma si scopre che questo è (quasi) un vero formato di immagine valido: BinM Portable PixMap .

Plop i dati dell'immagine dall'alto (meno il byte di controllo, ovviamente) nel file sottostante, regola la larghezza / altezza per essere validi e puoi visualizzare l'immagine in un visualizzatore adeguato come IrfanView, anche se più semplici (come la maggior parte dei browser built-in) non può gestirlo.

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

Ad esempio (utilizzando le escape per i dati non elaborati):

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

3

MATL, 21 13 byte

Yi3:iml&!*3YG

Il canale di colore deve essere specificato utilizzando il seguente mappatura: 1:red, 2:green,3:blue

Gli interpreti online non sono in grado di utilizzare imreadper leggere le immagini, quindi ecco una versione leggermente modificata in cui ho codificato un'immagine casuale nella fonte .

Spiegazione

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

-89 byte aggressivo tutto, cambiando dal mio ridicolo vecchio metodo di spogliare i canali e sbarazzarsi di un'importazione accidentale non necessaria.

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

Me ne sono sbarazzato mezz'ora prima che il mio turno iniziasse senza avere idea di cosa stavo facendo. Ho poca esperienza BufferedImage, quindi potrebbe esserci un modo migliore per farlo. Sto anche abusando Colordi convertire avanti e indietro tra rappresentazioni di colori di interi e singoli canali.

Questo è comicamente enorme rispetto alle altre risposte per un paio di motivi (oltre all'ovvio che Clojure non è un linguaggio da golf):

  • Invece di manipolare un array di byte, questo in realtà prende come input un'immagine, la altera e la emette.

  • Sto usando Java-Interop, che a volte può essere abbastanza dettagliato a volte. Le importazioni da sole sono più grandi di molte risposte.

Vedi il codice qui sotto per una suddivisione.

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

Questa è la cosa più gloriosa o orribile che abbia mai visto. Vado con il primo.
Rɪᴋᴇʀ

@Riker Sicuramente il primo. Ho iniziato a scrivere questa mezz'ora prima che iniziasse il mio turno senza avere idea di come avrei fatto. Ma funziona!
Carcigenicate,

* In realtà intendevo quest'ultimo, ma anche i gloriosi pasticci sono una cosa.
Carcigenicate,

1

Lua (love2d Framework), 498 byte

L'ho fatto più come un esercizio per me stesso, quindi non è così breve come potrebbe essere (anche se ho provato a giocare a golf), ma volevo aggiungerlo qui perché penso di aver fatto bene. Anche se sono troppo tardi.

Qui il codice golf, sotto di esso è la versione spiegata e districata.

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

Ecco il codice che deve contenere un file * .jpg. Dopo aver inserito l'immagine è possibile premere i pulsanti numerici per i canali rosso (1) verde (2) o blu (3). Inoltre, per visualizzare nuovamente l'immagine predefinita, premere 0. In realtà mostra solo l'immagine nella finestra.

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 che fa tutto il lavoro è lo shader che è la piccola dichiarazione di stringa all'inizio o districata:

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

che ottiene il pixel effettivo dell'immagine e mostra semplicemente i canali secondo necessità.

La mia immagine di prova e le diverse uscite per i canali (sicuramente anche le altre) immagine predefinita e immagini del canale unite


Grazie per il tuo suggerimento, l'ho risolto, la prossima volta che lo so :)
Lycea,

Nessun problema! Benvenuto in ppcg, spero che rimani in giro!
Rɪᴋᴇʀ

Inoltre, puoi ancora giocare a golf. Non è necessario includere i pulsanti e così via.
Rɪᴋᴇʀ

0

C, 60 58 byte

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

L'immissione dell'immagine è un elenco di numeri (in decimali) compreso tra 0 e 255 stdin, ad es

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

Il canale è specificato come primo argomento del programma ed è uno di

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

Esempio:

$ echo "255 0 0" | ./extract "%d%*d%*d"
255 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.