Kunci Chroma untuk Sukses

23

Nilai warna RGB #00FF00agak penting: digunakan untuk membuat film, acara TV, pengumuman cuaca, dan banyak lagi. Ini adalah warna "TV hijau" atau "layar hijau" yang terkenal.

Tantangan

Tugas Anda adalah menulis sebuah program yang mengambil dua gambar input, baik dalam format PNG (atau dalam tipe objek gambar pustaka gambar Anda) dan dengan dimensi yang sama. Satu gambar bisa berupa gambar lama. Yang lainnya adalah gambar yang akan memiliki latar belakang warna #00FF00. Gambar output akan terdiri dari gambar kedua yang dilapis di atas gambar pertama, tanpa ada #00FF00warna (kecuali pada gambar pertama). Input dan output dapat dilakukan dengan file, GUI, dll. Anda diizinkan untuk mengambil array nilai RGB sebagai input, seperti yang terlihat di sini . Anda dapat berasumsi bahwa suatu gambar hanya memiliki piksel opacity penuh.

Pada dasarnya ...

Buat program yang mengambil setiap #00FF00piksel dalam satu gambar dan ganti dengan piksel yang sesuai di gambar latar belakang.

Uji Kasus

Bermurah hati disediakan oleh @dzaima: Latar Belakang: Foreground: Output:
gambar profil saya

dennis

keluaran


Tentu saja, celah standar dilarang keras . Ini termasuk menggunakan sumber daya online untuk melakukannya untuk Anda.
Ini adalah , jadi semoga kode terpendek menang dan programmer terbaik ...

ckjbgames
sumber
2
Bolehkah kita mengambil objek gambar dalam format asli bahasa / pustaka sebagai input, atau apakah kita harus membaca gambar melalui nama file?
notjagan
@ notjagan Anda dapat mengambil objek gambar sebagai input.
ckjbgames
3
Apakah I / O array array integer dapat diterima atau apakah kita sebenarnya terbatas pada rangkaian gambar I / O lainnya?
Jonathan Allan
1
@PeterCordes Saya akan mengizinkannya.
ckjbgames
1
@PeterCordes ok
ckjbgames

Jawaban:

14

kode mesin x86-64 (dan x86-32), 13 15 13 byte

changelog:

  1. Perbaikan bug: versi pertama hanya memeriksa G = 0xff, tidak memerlukan R dan B menjadi 0. Saya mengubah untuk memodifikasi latar di tempat sehingga saya dapat menggunakan lodsddi latar depan untuk memiliki fg piksel dalam eaxuntuk cmp eax, imm32pengkodean bentuk pendek (5 byte) ), alih-alih cmp dh,0xff(3 byte).

  2. Simpan 2 byte: perhatikan bahwa memodifikasi bg pada tempatnya diizinkan menggunakan operan memori untuk cmov, menghemat movbeban 2-byte (dan menyimpan register, jika perlu).


Ini adalah fungsi yang mengikuti konvensi pemanggilan Sistem V x86-64, dapat dipanggil langsung dari C atau C ++ (pada sistem x86-64 non-Windows) dengan tanda tangan ini:

void chromakey_blend_RGB32(uint32_t *background /*rdi*/,
                     const uint32_t *foreground /*rsi*/,
                  int dummy, size_t pixel_count /*rcx*/);

Format gambar adalah RGB0 32bpp, dengan komponen hijau di alamat memori terendah ke-2 dalam setiap piksel. Gambar latar latar depan dimodifikasi di tempat. pixel_countadalah baris * kolom. Itu tidak peduli tentang baris / kolom; itu hanya campuran chromekey namun banyak memori yang Anda tentukan.

RGBA (dengan A harus 0xFF) akan membutuhkan menggunakan konstanta yang berbeda, tetapi tidak ada perubahan dalam ukuran fungsi. DWORD foreground dibandingkan untuk kesetaraan tepat terhadap konstanta 32-bit yang sewenang-wenang yang disimpan dalam 4 byte, sehingga warna urutan-pixel atau warna kunci-kroma dapat dengan mudah didukung.

Kode mesin yang sama juga berfungsi dalam mode 32-bit. Untuk berkumpul sebagai 32-bit, ubah rdike edidalam sumber. Semua register lain yang menjadi 64-bit adalah implisit (lodsd / stosd, dan loop), dan regs eksplisit lainnya tetap 32-bit. Tetapi perhatikan bahwa Anda memerlukan pembungkus untuk menelepon dari 32-bit C, karena tidak ada konvensi pemanggilan x86-32 standar yang menggunakan regs yang sama dengan SysV x86-64.

Daftar NASM (kode mesin + sumber), dikomentari untuk pemula ASM dengan deskripsi tentang apa yang dilakukan instruksi yang lebih kompleks. (Menggandakan manual referensi instruksi adalah gaya yang buruk dalam penggunaan normal.)

 1                       ;; inputs:
 2                       ;; Background image pointed to by RDI, RGB0 format  (32bpp)
 3                       ;; Foreground image pointed to by RSI, RGBA or RGBx (32bpp)
 4          machine      ;; Pixel count in RCX
 5          code         global chromakey_blend_RGB32
 6          bytes        chromakey_blend_RGB32:
 7 address               .loop:                      ;do {
 8 00000000 AD               lodsd                   ; eax=[rsi], esi+=4. load fg++
 9 00000001 3D00FF0000       cmp    eax, 0x0000ff00  ; check for chromakey
10 00000006 0F4407           cmove  eax, [rdi]       ; eax = (fg==key) ? bg : fg
11 00000009 AB               stosd                   ; [rdi]=eax, edi+=4. store into bg++
12 0000000A E2F4             loop .loop              ;} while(--rcx)
13                       
14 0000000C C3               ret

##  next byte starts at 0x0D, function length is 0xD = 13 bytes

Untuk mengeluarkan sumber NASM asli dari daftar ini, hapus 26 karakter utama dari setiap baris <chromakey.lst cut -b 26- > chromakey.asm. Saya membuat ini dengan
nasm -felf64 chromakey-blend.asm -l /dev/stdout | cut -b -28,$((28+12))- daftar NASM meninggalkan lebih banyak kolom kosong daripada yang saya inginkan antara kode mesin dan sumber. Untuk membuat file objek, Anda dapat menautkannya dengan C atau C ++, gunakan nasm -felf64 chromakey.asm. (Atau yasm -felf64 chromakey.asm).

belum diuji , tapi saya cukup yakin bahwa ide dasar load / load / cmov / store adalah suara, karena sangat sederhana.

Saya bisa menghemat 3 byte jika saya bisa meminta penelepon untuk meneruskan kunci chroma-key (0x00ff00) sebagai argumen tambahan, alih-alih mengkodekan konstanta ke dalam fungsi. Saya tidak berpikir aturan yang biasa memungkinkan penulisan fungsi yang lebih umum yang membuat pemanggil mengatur konstanta untuk itu. Tetapi jika itu terjadi, arg ke-3 (saat ini dummy) diteruskan dalam edxSysV ABI x86-64. Ubah cmp eax, 0x0000ff00(5B) menjadi cmp eax, edx(2B).


Dengan SSE4 atau AVX, Anda mungkin melakukan ini lebih cepat (tetapi ukuran kode lebih besar) dengan pcmpeqddan blendvpsuntuk melakukan campuran variabel ukuran elemen ukuran 32-bit yang dikendalikan oleh topeng pembanding. (Dengan pand, Anda dapat mengabaikan byte tinggi). Untuk RGB24 yang dikemas, Anda dapat menggunakan pcmpeqbdan kemudian 2x pshufb+ panduntuk mendapatkan TRUE dalam byte di mana ketiga komponen piksel itu cocok, lalu pblendvb.

(Saya tahu ini adalah kode-golf, tapi saya sempat mempertimbangkan mencoba MMX sebelum menggunakan skalar integer.)

Peter Cordes
sumber
Bisakah Anda mengirimkan saya sebuah executable yang dibuat dengan kode mesin ini?
ckjbgames
x86_32, silakan.
ckjbgames
@ckjbgames: Saya belum menulis pemanggil yang memuat / menyimpan gambar, hanya bagian modifikasi-piksel-di-tempat. Saya harus melakukan itu sebelum masuk akal untuk membangun executable. Tetapi jika saya lakukan, apa yang bisa dieksekusi? Windows PE32? Linux ELF32? FreeBSD ??
Peter Cordes
ELF32, jika Anda mau.
ckjbgames
@ckjbgames: Jika saya menemukan waktu, saya akan mencari pustaka pemuatan gambar dan menulis sesuatu. Saya menambahkan paragraf tentang cara mengubah cantuman kembali menjadi kode yang dapat Anda kumpulkan nasm -felf32. (Untuk 32-bit, Anda juga perlu fungsi pembungkus untuk memanggil dari C, karena masih menggunakan register yang sama dengan SysV ABI x86-64.)
Peter Cordes
13

Mathematica 57 35 byte

pembaruan: secara default, latar belakang hijau dihapus menggunakan RemoveBackground. Kiriman pertama termasuk parameter kedua yang tidak perlu, `{" Background ", Green}".


#~ImageCompose~RemoveBackground@#2&

Menghapus latar belakang gambar 2 dan menyusun hasilnya dengan gambar 1.


Contoh

i1

Berikut ini, dalam bentuk awalan dan bukan infiks, menunjukkan lebih jelas bagaimana kode bekerja.

i2

DavidC
sumber
4
Apakah ini berfungsi untuk gambar yang bukan "latar belakang" yang hijau? (Tampaknya ada sepetak kecil hijau yang tersisa di output Anda)
DBS
Jika ada "pulau" hijau dalam gambar, parameter tambahan, `{" Background ", Green}", akan diperlukan, yang akan meningkatkan total menjadi 57 byte. Itu adalah pengiriman pertama saya. Karena saya tidak melihat hijau terisolasi di latar depan gambar, parameter itu dijatuhkan
DavidC
11

Python 3 + numpy , 59 byte

lambda f,b:copyto(f,b,'no',f==[0,255,0])
from numpy import*

Cobalah online!

Input diberikan dalam format numpyarray, dengan triplet bilangan bulat mewakili piksel ( #00FF00di mana dalam kode warna hex setara dengan [0, 255, 0]). Array input diubah pada tempatnya, yang diizinkan per meta .

Contoh Gambar

Masukan (dari pertanyaan)

Latar Belakang:

gambar profil ckjbgames

Latar depan:

Gambar profil Dennis

Gambar latar depan setelah menjalankan fungsi:

Gambar yang digabungkan dengan # 00FF00 diganti dengan piksel latar belakang

Implementasi Referensi (digunakan opencvuntuk membaca file gambar)

g = lambda f,b:copyto(f,b,'no',f==[0,255,0])
from numpy import*

import cv2

f = cv2.imread("fg.png")
b = cv2.imread("bg.png")

g(f, b)

cv2.imshow("Output", f)
cv2.imwrite("out.png", f)

Menampilkan gambar ke layar dan menulisnya ke file output.

notjagan
sumber
17
Ada apa dengan semua titik merah pada gambar yang dihasilkan?
Yytsi
1
Saya sudah bertanya tentang I / O - ini tampaknya sesuai dengan kata-kata saat ini (yaitu "perpustakaan Anda"), jika demikian, apakah cv2 sendiri memerlukan impor numpy? Jika tidak Anda bisa melakukannya dalam 54 dengan tidak menggunakan fungsi numpy, dan tidak mengimpor numpy: lambda f,b:[x[list(x[0])==[0,255,0]]for x in zip(f,b)]. Jika daftar daftar bilangan bulat sebenarnya dapat diterima juga maka Anda bisa melakukannya di 48 denganlambda f,b:[x[x[0]==[0,255,0]]for x in zip(f,b)]
Jonathan Allan
Bahkan sebenarnya meskipun numpy yang diperlukan untuk cv2 untuk melakukan konversi saya masih berpikir Anda bisa melakukan versi 54 byte, karena kita tidak perlu cv2 impor untuk tantangan.
Jonathan Allan
5
Jika G == 255, nilai akan diganti bahkan jika R dan B bukan nol yang mengarah ke titik merah. Ini juga terjadi untuk band-band lain bahkan yang tangguh yang kurang terlihat. Jadi ia melakukan pengecekan logika secara independen satu sama lain dan menukar saluran tunggal meskipun hanya satu syarat terpenuhi. Misalnya jika pixel adalah [0 255 37]pita merah dan hijau akan diganti.
Leander Moesinger
2
@LeanderMoesinger: Terlihat dengan baik. Saya juga memiliki bug itu>. <; IDK mengapa saya berpikir bahwa hanya memeriksa hijau = 0xFF sementara mengabaikan R dan B benar!
Peter Cordes
9

Memproses, 116 99 byte

PImage f(PImage b,PImage f){int i=0;for(int c:f.pixels){if(c!=#00FF00)b.pixels[i]=c;i++;}return b;}

Sayangnya, pemrosesan tidak mendukung hal-hal java 8, seperti lambdas.

Contoh implementasi: (menyimpan gambar sebagai out.pngdan juga menggambarnya di layar)

PImage bg;
void settings() {
  bg = loadImage("bg.png");
  size(bg.width,bg.height);
}
void setup() {
  image(f(bg, loadImage("fg.png")), 0, 0);
  save("out.png");
}
PImage f(PImage b,PImage f){int i=0;for(int c:f.pixels){if(c!=#00FF00)b.pixels[i]=c;i++;}return b;}
dzaima
sumber
Anda dapat menyingkirkan settings()dan setup()fungsi dan hanya menjalankan kode secara langsung.
Kevin Workman
@KevinWorkman Saya memiliki pengaturan dan pengaturan di sana sehingga akan menampilkan gambar di layar, yang jika tidak tidak mungkin
dzaima
Apakah #ff00atau 0xff00sama seperti #00ff00dalam Memproses?
Peter Cordes
@PeterCordes # FF00 memberikan kesalahan sintaks, sayangnya, dan # 00FF00 == 0xFF00FF00, jadi 0xFF00 tidak berfungsi karena memeriksa nilai alfa 0
dzaima
@dzaima: Bisakah Anda mengambil gambar dalam format RGB0, jadi 0x0000FF00apakah pola bit yang Anda cari?
Peter Cordes
6

Bash + ImageMagick, 45 byte

convert $1 $2 -transparent lime -composite x:

Mengambil dua gambar sebagai argumen dan menampilkan output di layar. Ubah x:menjadi $3menulis ke argumen file ketiga sebagai gantinya. Metode ini sederhana: baca gambar "latar belakang"; baca imagek ​​"foreground"; menafsirkan kembali warna "kapur" (# 00ff00) sebagai transparansi pada gambar kedua; kemudian gabungkan gambar kedua ke yang pertama dan hasilkan.

ImageMagick: 28 byte?

Saya bisa mengirimkan ini sebagai jawaban ImageMagick tetapi tidak jelas bagaimana cara menangani argumen. Jika Anda ingin menyatakan bahwa ImageMagick adalah bahasa berbasis tumpukan (yang agak agak tidak benar tetapi hampir ... itu aneh) maka -transparent lime -compositeadalah fungsi yang mengharapkan dua gambar pada tumpukan dan meninggalkan satu gambar yang digabungkan pada tumpukan .. mungkin itu cukup baik untuk dihitung?

hobbs
sumber
3

MATL , 40 37 31 byte

,jYio255/]tFTF1&!-&3a*5M~b*+3YG

Contoh dijalankan dengan penerjemah offline. Gambar-gambar dimasukkan oleh URL-nya (nama file lokal juga dapat disediakan).

masukkan deskripsi gambar di sini

Penjelasan

,        % Do this twice
  j      %   Input string with URL or filename
  Yi     %   Read image as an M×N×3 uint8 array
  o      %  Convert to double
  255/   %   Divide by 255
]        % End
t        % Duplicate the second image
FTF      % Push 1×3 vector [0 1 0]
1&!      % Permute dimensions to give a 1×1×3 vector
-        % Subtract from the second image (M×N×3 array), with broadcast
&3a      % "Any" along 3rd dim. This gives a M×N mask that contains
         % 0 for pure green and 1 for other colours
*        % Mulltiply. This sets green pixels to zero
5M       % Push mask M×N again
~        % Negate
b        % Bubble up the first image
*        % Multiply. This sets non-green pixels to zero
+        % Add the two images
3YG      % Show image in a window
Luis Mendo
sumber
3

Pyth , 27 byte

M?q(Z255Z)GHG.wmgVhded,V'E'

Dibutuhkan input yang dikutip. Input adalah dua jalur file gambar. Keluaran file o.pngSayangnya itu tidak dapat diuji pada juru bahasa online karena alasan keamanan ( 'dinonaktifkan di dalamnya). Anda harus mendapatkan Pyth di komputer Anda untuk mengujinya.

Penjelasan

M?q(Z255Z)GHG                  # Define a function g which takes two tuples G and H and returns G if G != (0, 255, 0), H otherwise
                       V'E'    # Read the images. They are returned as lists of lists of colour tuples
                      ,        # Zip both images
               m  hded         # For each couple of lists in the zipped list...
                gV             # Zip the lists using the function g
             .w                # Write the resulting image to o.png
Jim
sumber
Fungsi campuran chroma-key sendiri adalah 13 byte, sama dengan jawaban kode mesin x86 saya. Saya tidak menyadari sebelumnya bahwa ini adalah program lengkap yang menyerahkan gambar I / O juga.
Peter Cordes
2

Matlab 2016b dan Oktaf, 62 59 byte

Input: A = MxNx3 unit8 foreground matrix, B = MxNx3 unit8 background matrix.

k=sum(A(:,:,2)-A(:,:,[1 3]),3)==510.*ones(1,1,3);A(k)=B(k);

Output: A = MxNx3 unit8 matrix

Penggunaan sampel:

A = imread('foreground.png');
B = imread('backgroundimg.png');

k=sum(A(:,:,2)-A(:,:,[1 3]),3)==510.*ones(1,1,3);A(k)=B(k);

imshow(A)
Leander Moesinger
sumber
1

C ++, 339 byte

Ini menggunakan CImg, dan dapat mengambil file dalam format lain juga. Hasilnya ditampilkan di jendela.

#include<CImg.h>
using namespace cimg_library;
int main(int g,char** v){CImg<unsigned char> f(v[1]),b(v[2]);for(int c=0;c<f.width();c++){for(int r=0;r<f.height();r++){if((f(c,r)==0)&&(f(c,r,0,1)==255)&&(f(c,r,0,2)==0)){f(c,r)=b(c,r);f(c,r,0,1)=b(c,r,0,1);f(c,r,0,2) = b(c,r,0,2);}}}CImgDisplay dis(f);while(!dis.is_closed()){dis.wait();}}

Kompilasi dengan g++ chromakey.cpp -g -L/usr/lib/i386-linux-gnu -lX11 -o chromakey -pthread.

ckjbgames
sumber
1

R, 135 byte

function(x,y,r=png::readPNG){a=r(x);m=apply(a,1:2,function(x)all(x==0:1));for(i in 1:4)a[,,i][m]=r(y)[,,i][m];png::writePNG(a,"a.png")}

Fungsi anonim, mengambil jalur file 2 png sebagai argumen dan menampilkan gambar png yang disebut a.png.

Sedikit ungolfed, dengan penjelasan:

function(x,y){
    library(png)
    # readPNG output a 3D array corresponding to RGBA values on a [0,1] scale:
    a = readPNG(x)
    # Logical mask, telling which pixel is equal to c(0, 1, 0, 1), 
    # i.e. #00FF00 with an alpha of 1:
    m = apply(a, 1:2, function(x) all(x==0:1))
    # For each RGB layer, replace that part with the equivalent part of 2nd png:
    for(i in 1:4) a[,,i][m] = readPNG(y)[,,i][m]
    writePNG(a,"a.png")
}
plannapus
sumber
1

SmileBASIC, 90 byte whats the key

DEF C I,J
DIM T[LEN(I)]ARYOP.,T,I,16711936ARYOP 2,T,T,T
ARYOP 6,T,T,0,1ARYOP 5,I,I,J,T
END

I adalah latar depan dan output, J adalah latar belakang. Keduanya adalah array integer piksel, dalam format ARGB 32 bit.

Tidak disatukan

DEF C IMAGE,BACKGROUND 'function
 DIM TEMP[LEN(IMAGE)]  'create array "temp"
 ARYOP #AOPADD,TEMP,IMAGE,-RGB(0,255,0)    'temp = image - RGB(0,255,0)
 ARYOP #AOPCLP,TEMP,TEMP,-1,1              'temp = clamp(temp, -1, 1)
 ARYOP #AOPMUL,TEMP,TEMP,TEMP              'temp = temp * temp
 ARYOP #AOPLIP,IMAGE,IMAGE,BACKGROUND,TEMP 'image = linear_interpolate(image, background, temp)
END

Penjelasan:

ARYOP adalah fungsi yang menerapkan operasi sederhana untuk setiap elemen dalam array.
Ini disebut sepertiARYOP mode, output_array, input_array_1, input_array_2, ...

Pertama, untuk menentukan piksel mana dalam gambar yang berwarna hijau, -16711936(representasi RGBA dari warna hijau) dikurangi dari setiap piksel dalam gambar latar depan. Ini memberikan array di mana0 mewakili piksel hijau, dan angka lainnya mewakili piksel non-hijau.

Untuk mengkonversi semua nilai bukan nol, nilai 1tersebut dikuadratkan (untuk menghapus angka negatif), lalu dijepit di antara 0dan 1.

Ini menghasilkan array dengan hanya 0s dan 1s.
0s mewakili piksel hijau pada gambar latar depan, dan harus diganti dengan piksel dari latar belakang.
1s mewakili piksel non-hijau, dan piksel tersebut perlu diganti dengan piksel dari latar depan.

Ini dapat dengan mudah dilakukan dengan menggunakan interpolasi linier.

12Me21
sumber
0

PHP, 187 byte

for($y=imagesy($a=($p=imagecreatefrompng)($argv[1]))-1,$b=$p($argv[2]);$x<imagesx($a)?:$y--+$x=0;$x++)($t=imagecolorat)($b,$x,$y)-65280?:imagesetpixel($b,$x,$y,$t($a,$x,$y));imagepng($b);

mengasumsikan file PNG 24bit; mengambil nama file dari argumen baris perintah, menulis ke stdout.
Jalankan dengan -r.

kerusakan

for($y=imagesy(                                 # 2. set $y to image height-1
        $a=($p=imagecreatefrompng)($argv[1])    # 1. import first image to $a
    )-1,
    $b=$p($argv[2]);                            # 3. import second image to $b
    $x<imagesx($a)?:                            # Loop 1: $x from 0 to width-1
        $y--+$x=0;                              # Loop 2: $y from height-1 to 0
        $x++)
            ($t=imagecolorat)($b,$x,$y)-65280?:     # if color in $b is #00ff00
                imagesetpixel($b,$x,$y,$t($a,$x,$y));   # then copy pixel from $a to $b
imagepng($b);                                   # 5. output
Titus
sumber
0

JavaScript (ES6), 290 byte

a=>b=>(c=document.createElement`canvas`,w=c.width=a.width,h=c.height=a.height,x=c.getContext`2d`,x.drawImage(a,0,0),d=x.getImageData(0,0,w,h),o=d.data,o.map((_,i)=>i%4?0:o[i+3]=o[i++]|o[i++]<255|o[i]?255:0),x.drawImage(b,0,0),createImageBitmap(d).then(m=>x.drawImage(m,0,0)||c.toDataURL()))

Mengambil input sebagai dua Imageobjek (dalam sintaks currying), yang dapat dibuat dengan <image>elemen HTML . Mengembalikan Janji yang memutuskan ke URL data Base64 dari gambar yang dihasilkan, yang dapat diterapkan ke srca<image> .

Idenya di sini adalah mengatur nilai alpha untuk setiap #00FF00piksel0 dan kemudian mengecat latar depan, dengan latar belakangnya dikunci, di atas latar belakang.

Cuplikan Tes

Termasuk latar depan dan latar belakang dengan URL data mereka terlalu besar untuk dikirim di sini, jadi itu dipindahkan ke CodePen:

Cobalah online!

Justin Mariner
sumber
0

OSL , 83 byte

shader a(color a=0,color b=0,output color c=0){if(a==color(0,1,0)){c=b;}else{c=a;}}

Mengambil dua input. Yang pertama adalah latar depan, dan yang kedua, latar belakang.

Scott Milner
sumber