Extraire un canal RVB d'une image

22

Étant donné une image, soit en entrée (éventuellement en triplets RVB) ou avec le nom de fichier en entrée (vous pouvez supposer que l'image a un nom de fichier spécifique, éventuellement sans extension), sortez une image représentant un seul canal de couleur de l'image.

Vous prendrez également une autre entrée, représentant le canal à produire. L'entrée peut être l'un des 3 symboles distincts. Cependant, les symboles doivent être soit une chaîne soit un nombre. Cependant, vous ne pouvez pas prendre une matrice à appliquer au tableau en entrée. (comme {1, 0, 0}ou {0, 1, 0}).

Vous sortirez le <input>canal de l'image d'entrée. Vous pouvez soit l'enregistrer dans un fichier, soit produire un ensemble de paires RVB.

Votre programme ne doit pas avoir de limites sur la taille de l'image (en px) et doit prendre en charge les triplets .png, .jpg/ .jpeg/ .JPG, ou RVB en tant que formats d'image. (il peut cependant en prendre en charge autant que vous le souhaitez)

Cas de test:

violet original

Circuit Rouge:

violet rouge

Circuit Vert:

vert violet

Canal bleu:

bleu violet

Et un autre cas de test, entièrement de rouge. Photo originale , rouge , verte et bleue . (avertissement: le canal uni et rouge fait mal à regarder trop longtemps)

2 autres cas de test:

Original , rouge , vert , bleu .

Original , rouge , vert , bleu .

Les deux derniers cas de test proviennent d' images avec toutes les couleurs .

Rɪᴋᴇʀ
la source
C'est une bonne inspiration pour un langage de golf qui transpile / compile en opérations OpenCV.
Rétablir Monica - ζ--

Réponses:

2

APL (Dyalog) , 7 octets

E / S: tableau de triplets RVB

⎕×⊂⎕=⍳3

Essayez-le en ligne!

⍳3 trois premiers entiers

⎕= comparer l'entrée numérique (le canal choisi) à celle

 joindre (donc chaque triplet d'image associe ce triplet entier)

⎕× multiplier l'entrée numérique (le tableau des triplets) avec celle

Adam
la source
12

JavaScript (ES6), 29 octets

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

L'entrée est un tableau 2D d'entiers 24 bits (par exemple [[0x0000ff,0x00ff00],[0xff0000,0xffffff]]) et 16711680pour le rouge, 65280pour le vert, 255pour le bleu. Si ce n'est pas valide, essayez ceci à la place:

JavaScript (ES6), 48 octets

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

L'entrée est un tableau 3D de valeurs de couleur et 0pour le rouge, le 1vert et le 2bleu.

ETHproductions
la source
1
Format d'entrée effronté haha
Conor O'Brien
10

Mathematica, 13 octets

ImageMultiply

Cela devrait être la version légitime de la réponse de JungHwan Min. Cette fonction prend l'image et l' une Red, Green, Bluecomme entrée. Par exemple:

entrez la description de l'image ici

Pour vous amuser, il y a aussi ColorSeparatequi vous donne des canaux individuels, mais il les renvoie sous forme d'images monocanal / en niveaux de gris, vous devrez donc les multiplier par la couleur par la suite.

Martin Ender
la source
Y a-t-il quelque chose que Mathematica n'a pas intégré pour?
Brian Minton
8

Bash + ImageMagick, 35 32 27 octets

mogrify -channel $1 -fx 0 i

Suppose l'image est dans le fichier iet le script prend l' une RG, BG, BRpour le bleu, rouge et vert respectivement; sorties dans le fichier i.

betseg
la source
me battre à elle. J'ai posté une réponse bash + IM différente ci-dessous, avec une optimisation que vous pouvez voler
Sparr
@Sparr J'ai fait un golf différent
betseg
vous pouvez toujours enregistrer deux octets avec mogrify et pas de «o»?
Sparr
7

Spectre , sans concurrence, 1 octet

(Non concurrent car ce défi a inspiré ce langage.) En réalité, Spectrum est une bibliothèque npm avec une interface de langage pour les commandes.

I

Prend l'entrée comme:

<filename>
channel

Appelez le programme comme:

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

Vous pouvez également fournir des informations aux invites:

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

Cela laisse l'image sur la pile. Pour le voir, ajoutez Oà la fin, comme ceci:

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

Pour plus de plaisir, essayez echo filename | node spectrum.js "wO". Il effectue les trois isolations de canaux à la fois:

warhol

Conor O'Brien
la source
1
@ThisGuy Oui, il peut faire un contrôle de primalité:n[d1=`[d1-P*][],.g!]#Pdd1-P~%-1=p
Conor O'Brien
1
@ ConorO'Brien avez-vous vu mon testeur de primalité pour l'opérateur fx d'ImageMagick?
Sparr
@Sparr non, je ne l'ai pas fait. Lien?
Conor O'Brien
7

JavaScript (ES6), 29 octets

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

Un peu comme la réponse d'ETHproductions mais avec une entrée plus flexible que la première méthode et plus petite que la seconde.

Ceci définit une fonction qui accepte l'image comme un tableau unidimensionnel d'intensités de couleur numériques. Cette fonction renvoie ensuite une autre fonction qui accepte une valeur entière représentant le canal de couleur souhaité.

Les couleurs peuvent être représentées par n'importe quelle plage numérique tant que 0 indique une absence totale de couleur. Par exemple 0.0 - 1.0ou0 - 255

Exemples:

Si les données d'image sont au format RVB, l'appel de la fonction avec des arguments (imageData)(0)renvoie l'image avec uniquement le canal rouge.

Si les données d'image sont au format BGR, l'appel de la fonction avec des arguments (imageData)(2)renvoie également l'image avec uniquement le canal rouge.

Programmeur Pragmatique
la source
Je suppose que ça i%3==b&&vmarche aussi.
Neil
6

Python 2, 69 octets

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

Toujours au golf.

Prend l'entrée comme filename, n(où nest 0, 1 ou 2). Enregistre la nouvelle image sur l'ancienne. 0est vert, 1rouge et 2bleu. Merci à @ovs, @Mikhail et @Rod pour les octets désactivés.

Rɪᴋᴇʀ
la source
Économisez quelques octets en k[:,:,x[i][0]]=k[:,:,x[i][1]]=0k[:,:,[1,2,0][i]]=k[:,:,i]=0
supprimant
@ovs merci! ... Je venais juste de proposer la deuxième suggestion moi-même, après avoir joué avec la vôtre. Vous m'avez bien entendu ninja.
Rɪᴋᴇʀ
Vous pouvez utiliser from cv2 import*pour économiser quelques octets
Rod
Semble que vous pouvez remplacer k[:,:,i-1]=k[:,:,i]=0park[:,:,[i,i-1]]=0
Mikhail V
5

CJam , 12 octets

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

Un bloc anonyme qui attend un tableau 3D de triplets RVB et un nombre compris entre 0 et 2 inclus sur la pile. Laisse ensuite le tableau extrait sur la pile.

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

Pourrait peut-être jouer au golf en utilisant un format d'entrée bizarre, mais j'ai l'impression que ça triche un peu.

Essayez-le en ligne!

Le cas de test est constitué juste pour démontrer, l'utilisation des triplets à partir d'une image réelle serait beaucoup trop grande.

Explication

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)
Chat d'affaires
la source
5

PowerShell , 282 octets

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

Rien de tout cela "jouer au golf à l'entrée" ou "à l'aide de fonctions intégrées". Phooey là-dessus. ;-)

Ceci prend ici le chemin complet d'un PNG d'entrée (cependant, à proprement parler, il n'a pas besoin d'être un PNG, car JPG, BMP, etc. sont pris en charge par .NET, mais je ne l'ai essayé que sur PNG), et un (R, G, B)pour le canal de couleur, puis les stocke dans $xet $y. Nous créons ensuite un New-Objecttype System.Drawing.Bitmapde $xet stockons cela dans$a .

Ensuite, nous faisons une double boucle sur tous les pixels. Tout d' abord de 1jusqu'à $a« s .Height, réglage de $hchaque itération (il est indexé zéro, c'est pourquoi nous --$_, ce qui permet d' économiser sur octets ( .height-1). A l' intérieur, on boucle de 1jusqu'à $a» s .Width.

Chaque itération, nous effectuons un .GetPixelsur les w,hcoordonnées particulières , ce qui renvoie un System.Drawing.Colorobjet. Nous en selectsortons les R G Bvaleurs. Le iexvoici une astuce qui transforme cela en une table de hachage (par exemple, quelque chose comme @{R=34; G=177; B=76}) afin que nous puissions indexer directement avec ce canal de couleur désirée [$y]. Cette valeur est stockée dans $i.

Ensuite, nous avons défini trois valeurs $r, $g, $bcomme étant le résultat de certains opérateurs pseudo-ternaires basés sur la valeur de la lettre de $y. Ainsi, par exemple, si $yc'est le cas R, le résultat est ici $r=$i, $g=0, $b=0.

Ensuite, nous faisons un .SetPixelretour sur cette w,hcoordonnée particulière , en construisant une nouvelle en System.Drawing.Colorutilisant la statique FromARGB(qui suppose que l'alpha est entièrement opaque). Une fois que nous avons terminé la boucle, nous avons simplement .Savele PNG dans un nouveau fichier.

Remarque: cela prend beaucoup de temps, car il effectue une boucle complètement indépendante à travers chaque pixel et effectue un tas de calculs et appelle chaque itération.

Tests:
AdmBorkBork Red AdmBorkBork Green AdmBorkBork Blue

AdmBorkBork
la source
3

Bash + ImageMagick, 41 octets

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

L'entrée est un fichier nommé x, paramètre de ligne de commande l'un Rou GouB

La sortie écrase le fichier d'entrée

Diffère de la réponse de betseg en prenant un paramètre de canal à lettre unique plus naturel. Écraser également au lieu de sortir un nouveau fichier que betseg est libre de voler :)

Sparr
la source
les $1guillemets ont besoin, les noms de fichiers peuvent avoir des espaces
betseg
@betseg pas vraiment, j'ai dit que vous pouvez supposer qu'il a un nom de fichier spécifique. S'il le souhaite, il peut même le changer pour lire à partir d'un nom de fichier xpour 1 octet de moins.
Rɪᴋᴇʀ
@Riker oh, je n'ai pas remarqué ça, ça m'aide aussi: D
betseg
3

Puce , 78 octets

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

Essayez-le en ligne!

La puce est un langage 2D qui fonctionne sur les bits composants de chaque octet dans un flux d'octets.

Présentation

Cette solution particulière s'attend à ce que le premier octet d'entrée soit le caractère de contrôle - pour définir quel (s) canal (s) conserver - et ce qui suit est l'octet des données d'image. Les données d'image doivent être des triplets RVB, un octet par canal, 24 bits par 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 |

Le caractère de contrôle est interprété comme un champ de bits, bien que seuls les trois bits les plus bas aient une signification:

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

Cela signifie que nous pouvons utiliser des caractères ASCII pour sélectionner le canal que nous voulons:

1signifie rouge
2signifie bleu
4signifie vert

Ou faites quelque chose de plus chic:

5garder le rouge et le bleu, mais pas le vert
7garder tous les canaux (l'image est inchangée)
0supprimer tous les canaux (l'image est noire)

Comment ça marche

Cette solution est plutôt brouillée en raison du golf, mais voici:

  1. Lire les trois bits de poids faible du premier octet avec C, Bet A, et stocker les bits correspondants dans leurs Mcellules Emory. En outre, Ssupprimez la sortie pour le premier cycle.
  2. Faites une boucle sur ces trois bits à plusieurs reprises. Si le bit actuel est activé, fermez les /commutateurs pour sortir l'octet d'entrée actuel, s'il est éteint, ouvrez les commutateurs pour que nous sortions un octet zéro.
  3. Continuez jusqu'à ce que l'entrée soit épuisée.

Affichage des résultats

Bien sûr, vous pouvez utiliser hexdump ou quelque chose d'ennuyeux, mais il s'avère que c'est (presque) un format d'image valide réel: PixMap portable binaire .

Plop juste les données d'image d'en haut (moins l'octet de contrôle, bien sûr) dans le fichier ci-dessous, ajustez la largeur / hauteur pour être valide, et vous pouvez afficher l'image dans une visionneuse appropriée comme IrfanView, bien que plus simple (comme la plupart des navigateurs) intégrés) ne peut pas le gérer.

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

Par exemple (en utilisant des échappements pour les données brutes):

P6
3 1
255
\xff\x00\x00\x00\xff\x00\x00\x00\xff
Phlarx
la source
3

MATL, 21 13 octets

Yi3:iml&!*3YG

Le canal de couleur doit être spécifiée en utilisant le mappage suivant: 1:red, 2:green,3:blue

Les interprètes en ligne ne peuvent pas utiliser imreadpour lire les images, voici donc une version légèrement modifiée où j'ai codé en dur une image aléatoire dans la source .

Explication

        % 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
la source
2

05AB1E , 16 octets

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

Essayez-le en ligne!

Utilise des couleurs hexadécimales dans un format de tableau 2D et [0,1,2] pour chaque canal.

Urne de poulpe magique
la source
2

Clojure, 421 332 octets

-89 octets en insérant agressivement tout, en changeant de ma vieille méthode ridicule de supprimer les canaux et en supprimant une importation accidentelle inutile.

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

J'ai giflé ça une demi-heure avant le début de mon quart de travail, sans savoir ce que je faisais. J'ai peu d'expérience avec BufferedImage, donc il peut y avoir une meilleure façon de procéder. J'abuse également Colorpour convertir des va-et-vient entre les représentations de couleurs entières et individuelles.

C'est comiquement énorme par rapport aux autres réponses pour quelques raisons (en plus de l'évidence que Clojure n'est pas une langue de golf):

  • Au lieu de simplement manipuler un tableau d'octets, cela prend en fait en entrée une image, la modifie et la sort.

  • J'utilise Java-interop, qui, bien que pratique, peut parfois être assez verbeux. Les importations à elles seules dépassent de nombreuses réponses.

Voir le code ci-dessous pour une ventilation.

(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
la source
C'est la chose la plus glorieuse ou la plus horrible que j'aie jamais vue. Je pars avec l'ancien.
Rɪᴋᴇʀ
@Riker Certainement l'ancien. J'ai commencé à écrire cette demi-heure avant le début de mon quart de travail, sans savoir comment j'allais le faire. Mais ça marche!
Carcigenicate
* Je voulais dire ce dernier, mais les désordres glorieux sont aussi une chose.
Carcigenicate
1

Lua (framework love2d), 498 octets

Je l'ai fait plus comme un exercice pour moi-même, donc ce n'est pas aussi court que cela pourrait être (même si j'ai essayé de jouer au golf), mais je voulais l'ajouter ici parce que je pense que j'ai bien fait. Même si je suis trop tard.

Ici, le code golfé, en dessous est la version expliquée et démêlée.

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

Voici le code qui doit contenir un fichier * .jpg. Une fois l'image insérée, vous pouvez appuyer sur les touches numériques des canaux rouge (1) vert (2) ou bleu (3). Pour voir à nouveau l'image par défaut, appuyez sur 0. En fait, elle montre simplement l'image dans la fenêtre.

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 partie importante qui fait tout le travail est le shader qui est la petite déclaration de chaîne au début ou démêlée:

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

qui obtient le pixel réel de l'image et montre simplement les canaux selon les besoins.

Mon image de test et les différentes sorties pour les canaux (aussi bien sûr les autres) image par défaut et images de canal fusionnées

Lycea
la source
Merci pour votre indice, je l'ai corrigé, la prochaine fois que je sais :)
Lycea
Aucun problème! Bienvenue à ppcg, j'espère que vous resterez!
Rɪᴋᴇʀ
En outre, vous pouvez toujours jouer au golf. Vous n'avez pas besoin d'inclure les boutons et autres.
Rɪᴋᴇʀ
0

C, 60 58 octets

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

L'entrée d'image est une liste de nombres (en décimal) entre 0 et 255 stdin, par exemple

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

Le canal est spécifié comme premier argument du programme et est l'un des

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

Exemple:

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