Bir resmin RGB kanalını çıkarın


22

Giriş olarak (muhtemelen RGB üçüzlerinde) veya giriş olarak dosya adıyla (bir görüntünün muhtemelen bir uzantısı olmadan belirli bir dosya adına sahip olduğunu varsayabilirsiniz) bir görüntü verildiğinde, görüntünün tek bir renk kanalını temsil eden bir görüntü çıkarır.

Ayrıca, hangi kanalı çıkartacağınızı gösteren başka bir giriş alacaksınız. Giriş, 3 farklı sembolden biri olabilir. Ancak, sembollerin bir dize veya bir sayı olması gerekir. Ancak diziye giriş olarak uygulamak için bir matrisi alamazsınız. (örneğin {1, 0, 0}, veya {0, 1, 0}).

Çıkış Alacaksın <input>giriş görüntüsünün kanalı. Bir dosyaya kaydedebilir veya bir dizi RGB çifti çıktısı alabilirsiniz.

Programınızın görüntünün boyutu (px cinsinden) üzerinde hiçbir sınırı olmamalı ve görüntü formatları olarak ya .png, .jpg/ .jpeg/ .JPGveya RGB üçlelerini desteklemesi gerekir. (ancak istediğiniz kadar destekleyebilir)

Test durumu:

menekşe orijinali

Kırmızı kanal:

menekşe kırmızı

Yeşil kanal:

menekşe yeşili

Mavi kanal:

menekşe mavisi

Ve başka bir test durumu, tamamen kırmızı. Orijinal fotoğraf , kırmızı , yeşil ve mavi . (uyarı: düz ve kırmızı kanal çok uzun süre bakmaktan zarar görmüş)

2 daha fazla test durumu:

Orijinal , kırmızı , yeşil , mavi .

Orijinal , kırmızı , yeşil , mavi .

Son iki test durumları tüm renkleri olan Görüntüler'dendir .


Bu, OpenCV işlemlerini gerçekleştiren / derleyen bir golf dili için ilham kaynağıdır.
Monica’yı eski durumuna getirin - ζ--

Yanıtlar:


2

APL (Dyalog) , 7 bayt

G / Ç: RGB üçlüsü dizisi

⎕×⊂⎕=⍳3

Çevrimiçi deneyin!

⍳3 ilk üç tam sayı

⎕= sayısal girişi (seçilen kanalla) karşılaştır

 kuşatın (böylece her görüntü üçlüsü tüm bu üçlüyü birleştirir)

⎕× sayısal girişi (üçüz dizisi) bununla çarp


12

JavaScript (ES6), 29 bayt

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

Giriş, 24 bit tam sayıların (örn. [[0x0000ff,0x00ff00],[0xff0000,0xffffff]]) 2B dizisidir ve 16711680kırmızı 65280için, yeşil 255için, mavi için. Bu geçerli değilse, bunun yerine şunu deneyin:

JavaScript (ES6), 48 bayt

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

Giriş, 3B renk dizisidir ve 0kırmızı 1için yeşil 2için mavi için.


1
Arsız giriş biçimi haha
Conor O'Brien,

10

Mathematica, 13 bayt

ImageMultiply

Bu JungHwan Min'in cevabının meşru versiyonu olmalı. Bu işlev resmini ve birini alır Red, Green, Bluegirdi olarak. Örneğin:

görüntü tanımını buraya girin

Eğlenceli bir gerçek olarak, ColorSeparatesize bireysel kanallar da veriyor, ancak onları tek kanallı / gri tonlamalı görüntüler olarak döndürüyor, bu nedenle bunları daha sonra renkle çarpmanız gerekir.


Mathematica'nın yerleşik bir özelliği yok mu?
Brian Minton

8

Bash + ImageMagick, 35 32 27 bayt

mogrify -channel $1 -fx 0 i

Devraldı görüntü dosyası içindedir ive komut birini alır RG, BG, BRsırasıyla kırmızı, mavi ve yeşil için; dosyaya çıktılar i.


beni döv. Aşağıda farklı bir bash + IM cevabı yazdım, çalabileceğiniz bir optimizasyonla
Sparr

@Sparr Farklı bir golf
oynamıştım

Hala iki bayt ile mogrify ve hiç 'o' kaydedebilirsiniz?
Sparr

7

Spektrum , rekabetçi olmayan, 1 bayt

(Rekabetçi olmadığından, bu zorluk bu dile ilham verdi.) Gerçekte, Spectrum komutlar için bir dil arayüzü olan bir npm kütüphanesidir.

I

Girişi şu şekilde alır:

<filename>
channel

Programı şu şekilde arayın:

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

Alternatif olarak, bilgi istemlerine bilgi sağlayabilirsiniz:

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

Bu görüntüyü yığında bırakır. Görmek Oiçin sonuna gibi ekleyin :

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

Bazı ekstra eğlence için, deneyin echo filename | node spectrum.js "wO". Her üç kanal yalıtımını da aynı anda gerçekleştirir:

warhol


1
@ThisGuy Evet, primallik kontrolü yapabilir:n[d1=`[d1-P*][],.g!]#Pdd1-P~%-1=p
Conor O'Brien

1
@ ConorO'Brien, ImageMagick'in fx operatörü için ilkel test cihazımı gördünüz mü?
Sparr

@Sparr hayır, yapmadım. Bağlantı?
Conor O'Brien,


7

JavaScript (ES6), 29 bayt

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

ETHproductions'un cevabı gibi ama ilk yöntemden daha esnek girdi ve ikinciden daha küçük.

Bu, görüntüyü 1 boyutlu bir sayısal renk yoğunluğu dizisi olarak kabul eden bir işlevi tanımlar. Ardından bu işlev, istenen renk kanalını temsil eden bir tam sayı değerini kabul eden başka bir işlev döndürür.

Renkler, rengin tamamen yok olduğunu gösterdiği sürece herhangi bir sayısal aralık ile temsil edilebilir. örneğin 0.0 - 1.0veya0 - 255

Örnekler:

Görüntü verileri RGB biçimindeyse, işlevi argümanlarla çağırmak (imageData)(0)görüntüyü yalnızca kırmızı kanalla döndürür.

Eğer görüntü verisi BGR formatındaysa, argümanlarla fonksiyonu çağırmak (imageData)(2)da görüntüyü sadece kırmızı kanalla gösterecektir.


Sanırım i%3==b&&vişe yarıyor.
Neil

6

Python 2,69 bayt

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

Hala golf oynuyorum.

Girişi filename, n( n0, 1 veya 2 olan) olarak alır. Yeni resmi eskisinin üzerine kaydeder. 0yeşil, 1kırmızı ve 2mavi. @Ovs, @Mikhail ve @Rod kapalı baytları için teşekkürler.


X 'yi bırakarak ve ile değiştirerek bazı baytları k[:,:,x[i][0]]=k[:,:,x[i][1]]=0k[:,:,[1,2,0][i]]=k[:,:,i]=0
tasarruf

@ovs teşekkürler! ... Ben sadece seninle uğraşırken, ikinci öneri kendim gelmişti. Yine de bana ninja ettin.
Rɪᴋᴇʀ

from cv2 import*Birkaç bayttan tasarruf etmek için kullanabilirsiniz
Rod

Eğer takabilmek görünüyor k[:,:,i-1]=k[:,:,i]=0ilek[:,:,[i,i-1]]=0
Mikhail V

5

CJam , 12 bayt

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

3B RGB dizisi dizisini ve yığında 0 ile 2 arasında bir sayı bekleyen anonim bir blok. Sonradan çıkarılan diziyi yığında bırakır.

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

Tuhaf bir giriş formatı kullanarak golf oynamak mümkün olabilir ama biraz hile yapıyormuş gibi hissediyorum.

Çevrimiçi deneyin!

Test durumu sadece göstermek için yapılmış, gerçek bir görüntüden üçüzlerin kullanılması çok büyük olurdu.

açıklama

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 bayt

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

Bu şıkların hiçbiri "girişi golf oynamak" veya "yerleşikleri kullanmak" değildir. Bunun üzerine Phooey. ;-)

Bu burada (, açık konuşmak gerekirse, bu değil gerçi bir giriş PNG tam yolunu alır ihtiyaç , .NET tarafından desteklenen vb, JPG, BMP beri bir PNG, olmak, ama ben sadece PNG üstünde denedim) ve (R, G, B)renk kanalı için bir taneden sonra bunları $xve içine depolar $y. Sonra bir oluşturmak New-ObjectÇeşidi System.Drawing.Bitmapait $xolduğunu içine ve mağaza $a.

Sonra tüm piksellerin üzerinde çift döngü yaparız. İlk gelen 1için yukarı $a's .Height, ayar $hher yinelenir (o, sıfır endeksli yüzden biz niye en --$_kaydeder üzerinde bayt ( .height-1). İçini, biz döngü 1için yukarı $a' s .Width.

Her yinelemede, bir nesneyi döndüren .GetPixelbelirli bir w,hkoordinat üzerinde performans gösteriyoruz System.Drawing.Color. Biz selectüzerinden R G Bbunların değerleri. iexBurada Hashtable'a bu döner düzgün bir hiledir (örn gibi bir şey @{R=34; G=177; B=76}) biz bunu doğrudan istenilen renk kanalı ile o içine endeksi [$y]. Bu değer içine kaydedilir $i.

Sonra, harf değerini temel alan sözde üçlü operatörlerin$r, $g, $b sonucu olarak üç değer belirledik . Yani, örneğin, bir , daha sonra burada sonucudur .$y$yR$r=$i, $g=0, $b=0

Ardından, statik kullanarak (alfa'nın tamamen opak olduğu varsayılır) yeni bir yapı .SetPixeloluşturarak, belirli bir w,hkoordinat üzerine geri döneriz . Döngüyü bitirdikten sonra , PNG'yi yeni bir dosyaya aktarırız.System.Drawing.ColorFromARGB.Save

Not: Bu uzun bir zaman alır, çünkü her pikselden tamamen bağımsız olarak dolanır ve bir sürü hesaplama yapar ve her yinelemeyi çağırır.

Testler:
AdmBorkBork Red AdmBorkBork Yeşil AdmBorkBork Blue


3

Bash + ImageMagick, 41 bayt

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

Girdi adlı bir dosya x, biri parametre komut satırı Rveya GveyaB

Çıktı giriş dosyasının üzerine yazar

Betseg'in daha doğal tek harfli kanal parametresi almasında cevabını zorlaştırıyor. Ayrıca çalmak için ücretsiz olan betseg yeni bir dosya çıktısı yerine üzerine yazmak :)


$1tırnak işareti ihtiyacı dosya adları boşluk olabilir
betseg

@ betseg gerçekten değil, belirli bir dosya adı olduğunu varsayabilirsin dedim. İsterse, x1 byte kapalı bir dosya adından okumak için bile değiştirebilir .
Rɪᴋᴇʀ

D: ah @Riker, ben daha hiç haber beni de yardımcı olduğunu, o
betseg

3

Çip , 78 bayt

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

Çevrimiçi deneyin!

Chip, bir bayt akışındaki her baytın bileşen bitleri üzerinde çalışan bir 2D dilidir.

genel bakış

Bu özel çözüm, girişin ilk baytının kontrol karakteri olmasını bekler - hangi kanal (lar) ın tutulacağını tanımlamak - ve ardından görüntü verilerinin baytları. Görüntü verileri, RGB üçlüsü, kanal başına bir bayt, piksel başına 24 bit olmalıdır:

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

Kontrol karakteri bit alanı olarak yorumlanır, ancak yalnızca en düşük üç bitin anlamı vardır:

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

Bu, istediğimiz kanalı seçmek için ASCII karakterlerini kullanabileceğimiz anlamına gelir:

1kırmızı
2, mavi
4, yeşil anlamına gelir

Veya bir şeyler meraklısı yapın:

5kırmızı ve mavi renklerini koru, ancak yeşil
7olmalarını engelle, tüm kanalları tut (görüntü değişmeden),
0tüm kanalları bırak (görüntü siyah)

Nasıl çalışır

Bu çözüm, golf nedeniyle oldukça karışık, ancak işte:

  1. İlk baytın üç düşük bit oku C, Bve A, ve bunların karşılık gelen bu biti saklamak MEmory hücreleri. Ayrıca, Silk döngü için çıktıyı yükseltin.
  2. Tekrar tekrar bu üç bit üzerinde döngü. Geçerli bit açıksa, /geçerli giriş baytını almak için anahtarları kapatın, açıksa, sıfır baytlık bir çıkış vermemiz için anahtarları açın.
  3. Giriş tükenene kadar devam edin.

Sonuçları görüntüleme

Tabii ki, hexdump veya sıkıcı bir şey kullanabilirsiniz, ancak bunun gerçek bir geçerli resim formatı olduğu ortaya çıkıyor: binary Portable PixMap .

Resim verilerini yukarıdan aşağıya doğru kaydırın (eksi kontrol baytını elbette) aşağıdaki dosyaya yerleştirin, genişlik / yüksekliği geçerli olacak şekilde ayarlayın ve görüntüyü daha basit olanlar (en çok tarayıcı gibi) gibi IrfanView gibi uygun bir görüntüleyicide görüntüleyebilirsiniz. yerleşikler) bununla başa çıkamaz.

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

Örneğin (ham veriler için kaçışları kullanma):

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

3

MATL, 21 13 bayt

Yi3:iml&!*3YG

Renk kanalı aşağıdaki eşleştirme kullanılarak belirtilmelidir: 1:red, 2:green,3:blue

Çevrimiçi tercümanlar imreadgörüntüleri okumak için kullanamıyorlar , bu yüzden kaynakta rastgele bir görüntüyü kodladığım biraz değiştirilmiş bir sürüm .

açıklama

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

-89 , her şeyi agresif bir biçimde iç içe geçirerek, saçma eski kanallarımı soyma yöntemimden geçerek ve gereksiz bir kazayla içe aktarma işleminden kurtularak bayt .

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

Vardiyam başlamadan yarım saat önce, ne yaptığım hakkında hiçbir fikrim yok. Çok az deneyimim var BufferedImage, bu yüzden bu konuda daha iyi bir yol olabilir. Ayrıca Colortamsayı ve renklerin tek tek kanal gösterimleri arasında ileri geri dönüştürme kötüye kullanıyorum.

Bu, birkaç nedenden ötürü diğer cevaplara kıyasla, oldukça büyük (ayrıca, Clojure’un bir golf dili olmadığı açıkça görülüyor):

  • Sadece bir bayt dizisini değiştirmek yerine, bu aslında bir girdi girdi olarak alır, değiştirir ve çıkarır.

  • Java-interop kullanıyorum; bu arada kullanışlı, zaman zaman oldukça ayrıntılı olabilir. Yalnızca ithalat, birçok cevaptan daha büyük.

Arıza için aşağıdaki koda bakın.

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

Bu şimdiye kadar gördüğüm en görkemli ya da korkunç şey. Eski ile gidiyorum.
Rɪᴋᴇʀ

@Riker Kesinlikle eski. Bunu vardiyam başlamadan yarım saat önce yazmaya başladım, nasıl yapacağım hakkında hiçbir fikrim yoktu. Ama işe yarıyor!
Carcigenicate

* Aslında ikincisini kastettim, ama şanlı mesajlar da bir şey.
Carcigenicate

1

Lua (love2d Çerçeve), 498 bayt

Bunu kendim için bir egzersiz olarak daha çok yaptım, bu yüzden olabildiğince kısa değil (golf oynamaya çalıştığım halde), ama buraya eklemek istedim çünkü iyi yaptığımı düşünüyorum. Çok geç kalsam bile.

Burada golf kodu, altında açıklanmış ve dolaştırılmamış versiyondur.

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

İşte içine düştü bir * .jpg dosyası almak zorunda kod. Görüntü eklendikten sonra kırmızı (1) yeşil (2) veya mavi (3) kanallar için sayı düğmelerine basabilirsiniz. Ayrıca varsayılan resmi tekrar görmek için 0 tuşuna basın. Aslında sadece resmi pencerede gösterir.

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

Tüm işi yapan önemli kısım, başında küçük harf bildirimi veya dolaşmayan gölgelendiricidir:

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

Resmin asıl pikselini alır ve sadece kanalları gerektiği gibi gösterir.

Test resmim ve kanalların farklı çıktıları (elbette diğerleri için de) varsayılan görüntü ve kanal görüntüleri birleştirildi



Sorun değil! Ppcg'ye hoşgeldiniz, etrafta dolaşırsınız!
Rɪᴋᴇʀ

Ayrıca, hala bu golf olabilir. Düğmeleri vb. Eklemeniz gerekmez.
Rɪᴋᴇʀ

0

C, 60 58 bayt

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

Görüntü girişi stdin, örneğin 0 ile 255 arasındaki (ondalık sayıdaki) sayıların listesidir.

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

Kanal, programın ilk argümanı olarak belirtilmiştir ve

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

Örnek:

$ echo "255 0 0" | ./extract "%d%*d%*d"
255 
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.