Ekstrak saluran RGB dari suatu gambar


22

Diberikan gambar, baik sebagai input (mungkin dalam RGB triplets) atau dengan nama file sebagai input (Anda dapat menganggap gambar memiliki nama file tertentu, mungkin tanpa ekstensi), menampilkan gambar yang mewakili saluran warna tunggal dari gambar.

Anda juga akan mengambil input lain, mewakili saluran mana yang akan di-output. Input dapat berupa salah satu dari 3 simbol berbeda. Namun, simbol harus berupa string atau angka. Anda tidak dapat mengambil matrik untuk diterapkan ke array sebagai input. (seperti {1, 0, 0}, atau {0, 1, 0}).

Anda akan menampilkan <input>saluran gambar input. Anda bisa menyimpannya ke file atau output satu set pasangan RGB.

Program Anda seharusnya tidak memiliki batasan pada ukuran gambar (dalam px), dan harus mendukung .png, .jpg/ .jpeg/ .JPG, atau triplet RGB sebagai format gambar. (namun dapat mendukung sebanyak yang Anda inginkan)

Kasus cobaan:

ungu asli

Jalur Merah:

merah ungu

Jalur Hijau:

hijau ungu

Saluran biru:

biru ungu

Dan satu lagi test case, seluruhnya merah. Foto asli , merah , hijau , dan biru . (peringatan: saluran polos dan merah terlalu menyakitkan untuk dilihat terlalu lama)

2 kasus uji lagi:

Asli , merah , hijau , biru .

Asli , merah , hijau , biru .

Dua test case terakhir berasal dari Images dengan semua warna .


Ini adalah inspirasi yang baik untuk bahasa golf yang mengubah / mengkompilasi ke operasi OpenCV.
Pasang kembali Monica - ζ--

Jawaban:


2

APL (Dyalog) , 7 byte

I / O: array kembar tiga RGB

⎕×⊂⎕=⍳3

Cobalah online!

⍳3 tiga bilangan bulat pertama

⎕= bandingkan input numerik (saluran yang dipilih) dengan itu

 terlampir (sehingga setiap triplet gambar memasangkan seluruh triplet ini)

⎕× mengalikan input numerik (array triplet) dengan itu


12

JavaScript (ES6), 29 byte

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

Input adalah array 2D bilangan bulat 24-bit (mis. [[0x0000ff,0x00ff00],[0xff0000,0xffffff]]) Dan 16711680untuk merah, 65280untuk hijau, 255untuk biru. Jika ini tidak valid, coba ini sebagai gantinya:

JavaScript (ES6), 48 byte

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

Input adalah array 3D dari nilai warna dan 0untuk merah, 1untuk hijau, 2untuk biru.


1
Format masukan kurang sopan haha
Conor O'Brien

10

Mathematica, 13 byte

ImageMultiply

Ini harus menjadi versi sah dari jawaban JungHwan Min. Fungsi ini mengambil gambar dan satu dari Red, Green, Bluesebagai masukan. Sebagai contoh:

masukkan deskripsi gambar di sini

Sebagai fakta yang menyenangkan, ada juga ColorSeparateyang memberi Anda saluran tersendiri, tetapi mengembalikannya sebagai gambar saluran tunggal / skala abu-abu, jadi Anda harus mengalikannya dengan warna setelahnya.


Apakah ada sesuatu yang tidak dimiliki Mathematica untuk built-in?
Brian Minton

8

Bash + ImageMagick, 35 32 27 byte

mogrify -channel $1 -fx 0 i

Mengasumsikan gambar ada dalam file idan skrip mengambil salah satunyaRG , BG, BRuntuk biru, merah, dan hijau masing-masing; output ke file i.


kalahkan aku untuk itu. Saya memposting jawaban bash + IM yang berbeda di bawah ini, dengan optimasi yang dapat Anda curi
Sparr

@Sparr Saya membuat golf yang berbeda
betseg

Anda masih bisa menyimpan dua byte dengan mogrify dan tidak ada 'o'?
Sparr

7

Spectrum , noncompeting, 1 byte

(Non-bersaing karena tantangan ini menginspirasi bahasa ini.) Pada kenyataannya, Spectrum adalah pustaka npm dengan antarmuka bahasa untuk perintah.

I

Mengambil input sebagai:

<filename>
channel

Panggil program sebagai:

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

Atau, Anda dapat memberikan informasi ke petunjuk:

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

Ini meninggalkan gambar di tumpukan. Untuk melihatnya, tambahkan Odi bagian akhir, seperti:

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

Untuk kesenangan ekstra, cobalah echo filename | node spectrum.js "wO". Ia melakukan ketiga isolasi saluran sekaligus:

warhol


1
@ ThisGuy Ya, itu bisa melakukan pemeriksaan awal:n[d1=`[d1-P*][],.g!]#Pdd1-P~%-1=p
Conor O'Brien

1
@ ConorO'Brien apakah Anda melihat tester primality saya untuk operator fx ImageMagick?
Sparr

@Parr tidak, saya belum. Link?
Conor O'Brien


7

JavaScript (ES6), 29 byte

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

Sangat mirip dengan jawaban ETHproductions tetapi dengan input yang lebih fleksibel daripada metode pertama dan lebih kecil dari yang kedua.

Ini mendefinisikan fungsi yang menerima gambar sebagai array 1 dimensi dari intensitas warna numerik. Fungsi ini kemudian mengembalikan fungsi lain yang menerima nilai integer yang mewakili saluran warna yang diinginkan.

Warna dapat diwakili oleh rentang angka apa pun selama 0 menunjukkan tidak adanya warna sama sekali. Misalnya 0.0 - 1.0atau0 - 255

Contoh:

Jika data gambar dalam format RGB maka memanggil fungsi dengan argumen (imageData)(0) akan mengembalikan gambar hanya dengan saluran merah.

Jika data gambar dalam format BGR maka memanggil fungsi dengan argumen (imageData)(2)juga akan mengembalikan gambar hanya dengan saluran merah.


Saya kira i%3==b&&vjuga berhasil.
Neil

6

Python 2, 69 byte

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

Masih bermain golf.

Mengambil input sebagai filename, n(di mana n0, 1, atau 2). Menyimpan gambar baru dari yang lama. 0berwarna hijau, 1merah, dan 2biru. Berkat @ovs, @Mikhail, dan @Rod untuk byte mati.


Simpan beberapa byte dengan menjatuhkan x dan mengganti k[:,:,x[i][0]]=k[:,:,x[i][1]]=0dengank[:,:,[1,2,0][i]]=k[:,:,i]=0
ovs

@ovs terima kasih! ... Saya sebenarnya baru saja datang dengan saran kedua sendiri, setelah mengacaukan Anda. Anda ninja'ed saya untuk itu.
Rɪᴋᴇʀ

Anda dapat menggunakan from cv2 import*untuk menyimpan beberapa byte
Rod

Tampaknya Anda dapat mengganti k[:,:,i-1]=k[:,:,i]=0dengank[:,:,[i,i-1]]=0
Mikhail V

5

CJam , 12 byte

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

Blok anonim yang mengharapkan array 3D triplet RGB dan angka antara 0 dan 2 inklusif pada tumpukan. Meninggalkan array yang diekstrak pada stack sesudahnya.

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

Mungkin bisa bermain golf dengan menggunakan format input yang aneh, tapi saya merasa seperti itu sedikit curang.

Cobalah online!

Tempat uji dibuat hanya untuk menunjukkan, menggunakan kembar tiga dari gambar yang sebenarnya akan terlalu besar.

Penjelasan

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

Tak satu pun dari ini suka "golf input" atau "menggunakan built-in." Phooey tentang itu. ;-)

Ini di sini mengambil path lengkap dari input PNG (meskipun, sebenarnya, tidak perlu menjadi PNG, karena JPG, BMP, dll didukung oleh .NET, tapi saya baru mencobanya di PNG), dan salah satu (R, G, B)untuk saluran warna, lalu menyimpannya ke dalam $xdan $y. Kami kemudian membuat New-Objecttipe System.Drawing.Bitmapdari $xdan menyimpan ke dalam$a .

Lalu kami melakukan loop ganda pada semua piksel. Pertama dari 1hingga $a's .Height, pengaturan $hsetiap iterasi (itu nol-diindeks, sehingga ini mengapa kita --$_, yang menyimpan byte lebih ( .height-1). Di dalam, kita loop dari 1hingga $a' s .Width.

Setiap iterasi, kami melakukan a .GetPixel pada w,hkoordinat tertentu , yang mengembalikan System.Drawing.Colorobjek. Kami selectmengeluarkan R G Bnilainya. Di iexsini adalah trik rapi yang mengubah ini menjadi hashtable (misalnya, sesuatu seperti @{R=34; G=177; B=76}) sehingga kita dapat mengindeks langsung dengan saluran warna yang diinginkan [$y]. Nilai itu disimpan ke dalam $i.

Selanjutnya, kami menetapkan tiga nilai $r, $g, $bmenjadi hasil dari beberapa operator pseudo-ternary berdasarkan nilai huruf $y. Jadi, misalnya, jika $yadalah R, maka hasil di sini adalah $r=$i, $g=0, $b=0.

Kemudian, kita lakukan .SetPixelkembali ke w,hkoordinat tertentu itu , membangun yang baru System.Drawing.Colormenggunakan statis FromARGB(yang menganggap alpha sepenuhnya buram). Setelah kita selesai mengulang, kita cukup .Savedengan PNG ke file baru.

Catatan: Ini memang memakan waktu lama, karena benar-benar secara independen perulangan melalui setiap piksel dan melakukan banyak perhitungan dan memanggil setiap iterasi.

Tes:
AdmBorkBork Red AdmBorkBork Green AdmBorkBork Blue


3

Bash + ImageMagick, 41 byte

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

Input adalah file bernama x, salah satu parameter baris perintahR atau GatauB

Output menimpa file input

Berbeda dari jawaban betseg dalam mengambil lebih banyak parameter saluran satu huruf. Juga menimpa alih-alih menghasilkan file baru yang betseg bebas untuk mencuri :)


yang $1membutuhkan tanda kutip, nama file dapat memiliki ruang
betseg

@ Betseg tidak terlalu, saya katakan Anda dapat menganggap itu memiliki nama file tertentu. Jika dia mau, dia bahkan bisa mengubahnya untuk membaca dari nama file xselama 1 byte.
Rɪᴋᴇʀ

@ Pembalap oh, saya tidak memperhatikan itu, itu membantu saya juga: 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

Cobalah online!

Chip adalah bahasa 2D yang beroperasi pada bit komponen setiap byte dalam aliran byte.

Ikhtisar

Solusi khusus ini mengharapkan byte pertama input menjadi karakter kontrol - untuk menentukan saluran mana yang harus disimpan - dan berikut ini adalah byte dari data gambar. Data gambar harus berupa triplet RGB, satu byte per saluran, 24 bit per piksel:

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

Karakter kontrol ditafsirkan sebagai bidang bit, meskipun hanya tiga bit terendah yang memiliki arti:

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

Ini berarti kita dapat menggunakan karakter ASCII untuk memilih saluran mana yang kita inginkan:

1berarti merah
2berarti biru
4berarti hijau

Atau lakukan sesuatu yang lebih menarik:

5 tetap merah dan biru, tetapi tidak hijau
7 menyimpan semua saluran (gambar tidak berubah)
0 jatuhkan semua saluran (gambar hitam)

Bagaimana itu bekerja

Solusi ini agak campur aduk karena golf, tetapi begini:

  1. Membaca tiga bit rendah dari byte pertama dengan C, B, dan A, dan menyimpan mereka bit dalam mereka sesuai Msel Emory. Juga,S tekan output untuk siklus pertama.
  2. Ulangi ketiga bit itu berulang kali. Jika bit saat ini aktif, tutup/ switch untuk output byte input saat ini, jika tidak aktif, buka switch sehingga kami menghasilkan byte nol.
  3. Lanjutkan sampai input habis.

Melihat hasilnya

Tentu, Anda bisa menggunakan hexdump atau sesuatu yang membosankan, tetapi ternyata ini adalah (hampir) format gambar yang sebenarnya valid: binary Portable PixMap .

Cukup colokkan data gambar dari atas (minus byte kontrol, tentu saja) ke dalam file di bawah ini, sesuaikan lebar / tinggi agar valid, dan Anda dapat melihat gambar dalam penampil yang tepat seperti IrfanView, meskipun yang lebih sederhana (seperti kebanyakan browser) built-in) tidak bisa mengatasinya.

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

Misalnya (menggunakan escapes untuk data mentah):

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

3

MATL, 21 13 byte

Yi3:iml&!*3YG

Saluran warna harus ditentukan dengan menggunakan pemetaan berikut: 1:red, 2:green,3:blue

Interpreter online tidak dapat digunakan imreaduntuk membaca gambar jadi di sini adalah versi yang sedikit dimodifikasi di mana saya telah mengkodekan gambar acak ke dalam sumber .

Penjelasan

        % 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 bytes dengan agresif menguraikan semuanya, berubah dari metode lama saya yang menggelikan saluran, dan menyingkirkan impor kebetulan yang tidak perlu.

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

Memukul ini setengah jam sebelum shift saya mulai tanpa tahu apa yang saya lakukan. Saya memiliki sedikit pengalaman BufferedImage, jadi mungkin ada cara yang lebih baik untuk melakukan hal ini. Saya juga menyalahgunakanColor untuk mengonversi bolak-balik antara representasi warna saluran dan integer.

Ini sangat besar dibandingkan dengan jawaban lain karena beberapa alasan (selain itu jelas bahwa Clojure bukan bahasa golf):

  • Alih-alih hanya memanipulasi array byte, ini sebenarnya mengambil input gambar, mengubahnya, dan output itu.

  • Saya menggunakan Java-interop, yang sementara berguna bisa sangat bertele-tele. Impor saja lebih besar dari banyak jawaban.

Lihat kode di bawah ini untuk rinciannya.

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

Ini adalah hal yang paling mulia atau mengerikan yang pernah saya lihat. Saya pergi dengan mantan.
Rɪᴋᴇʀ

@Riker Pasti yang pertama. Saya mulai menulis setengah jam sebelum shift saya mulai tanpa tahu bagaimana saya akan melakukannya. Tapi berhasil!
Carcigenicate

* Sebenarnya saya maksud yang terakhir, tetapi kekacauan yang mulia juga penting.
Carcigenicate

1

Lua (love2d Framework), 498 byte

Saya melakukan ini lebih sebagai latihan untuk diri saya sendiri, jadi ini tidak sesingkat mungkin (walaupun saya memang mencoba bermain golf), tetapi saya ingin menambahkannya ke sini karena saya pikir saya melakukan yang baik. Bahkan jika saya terlambat.

Di sini kode golf, di bawahnya adalah versi yang dijelaskan dan tidak terurai.

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

Berikut adalah kode yang harus dimasukkan dalam file * .jpg. Setelah gambar dimasukkan, Anda dapat menekan tombol angka untuk saluran merah (1) hijau (2) atau biru (3). Juga untuk melihat gambar default lagi tekan 0. Sebenarnya itu hanya menampilkan gambar di jendela.

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

Bagian penting yang melakukan semua pekerjaan adalah shader yang merupakan deklarasi string kecil di awal atau tidak terurai:

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

yang mendapatkan piksel sebenarnya dari gambar dan hanya menampilkan saluran yang diperlukan.

Gambar pengujian saya dan output yang berbeda untuk saluran (juga pasti yang lain) default image and channel images merged


Terima kasih atas petunjuk Anda, saya memperbaikinya, lain kali saya tahu :)
Lycea

Tidak masalah! Selamat datang di ppcg, harap Anda tetap disini!
Rɪᴋᴇʀ

Juga, Anda masih bisa bermain golf ini. Anda tidak perlu memasukkan tombol dan semacamnya.
Rɪᴋᴇʀ

0

C, 60 58 byte

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

Input gambar adalah daftar angka (dalam desimal) antara 0 dan 255 aktif stdin, misalnya

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

Saluran ditentukan sebagai argumen pertama ke program, dan merupakan salah satu

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

Contoh:

$ echo "255 0 0" | ./extract "%d%*d%*d"
255 
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.