Chroma Başarının Anahtarı


23

RGB renk değeri #00FF00oldukça önemlidir: filmler, TV şovları, hava durumu duyuruları ve daha fazlasını yapmak için kullanılır. Ünlü "TV yeşili" veya "yeşil ekran" rengidir.

Meydan okuma

Göreviniz, hem PNG biçiminde (ya da resim kitaplığınızın resim nesnesi türünde) hem de aynı boyutlarda iki giriş görüntüsü alan bir program yazmaktır. Bir görüntü, herhangi bir eski görüntü olabilir. Diğeri, rengin bir arka planına sahip olacak görüntüdür #00FF00. Çıktı görüntüsü, herhangi bir #00FF00renk olmadan (ilk görüntü hariç), birincinin üzerine yerleştirilen ikinci görüntüden oluşacaktır . Giriş ve çıkış dosyalar, bir GUI, vb. İle yapılabilir . Burada görüldüğü gibi giriş olarak RGB değerleri dizisi almanıza izin verilir . Bir görüntünün yalnızca tam opaklığa sahip pikselleri olduğunu varsayabilirsiniz.

Esasında ...

#00FF00Bir görüntüdeki her pikseli alan bir program yapın ve onu arka plan görüntüsündeki ilgili pikselle değiştirin.

Test Kılıfları

Cömertçe @dzaima tarafından sağlandı: Arka Plan: Ön Plan: Çıktı:
profil resmim

dennis

çıktı


Tabii ki, standart boşluklar kesinlikle yasaktır . Bu, sizin için yapmak için çevrimiçi bir kaynak kullanmayı içerir.
Bu , bu yüzden en kısa kod kazanır ve en iyi programcı prosper olabilir ...


2
Bir dilin / kütüphanenin yerel formatındaki bir görüntü nesnesini girdi olarak alabilir miyiz, yoksa görüntüyü dosya adı üzerinden okumak zorunda mıyız?
notjagan

@notjagan Görüntü nesnelerini girdi olarak alabilirsiniz.
ckjbgames

3
Tamsayı dizilerinin G / Ç dizileri kabul edilebilir mi, yoksa gerçekten başka bazı görüntü I / O dizileriyle sınırlı mıyız?
Jonathan Allan,

1
@PeterCordes Buna izin vereceğim.
ckjbgames

1
@PeterCordes ok
ckjbgames

Yanıtlar:


14

x86-64 (ve x86-32) makine kodu, 13 15 13 bayt

changelog:

  1. Hata düzeltme: ilk sürüm yalnızca G = 0xff'i kontrol ediyordu, R ve B'nin 0 olmasını gerektirmiyordu. Arka planı yerinde değiştirerek kısa form kodlaması için lodsdfg pikselleri kullanmak için ön planda kullanabilmek için değiştirdim (5 bayt ) yerine (3 bayt).eaxcmp eax, imm32cmp dh,0xff

  2. 2 bayt kaydet: bg'yi yerinde değiştirmenin, cmov2 baytlık bir movyükü (ve önemli olması durumunda bir kayıt defterini kaydetme) hafıza işleneni kullanmasına izin verildiğini fark ettim .


Bu, x86-64 System V çağrı kuralını izleyen, doğrudan C veya C ++ ile (x86-64 dışı Windows sistemlerinde) bu imzayla çağrılabilen bir işlevdir:

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

Görüntü formatı RGB0 32bpp'dir, yeşil bileşen her pikselin 2. en düşük hafıza adresindedir. Ön plan arka plan görüntüsü yerinde değiştirilir. pixel_countSatırlar * sütunlar. Satırlar / sütunlar umrunda değil; sadece chromekey, ancak belirlediğiniz birçok belleğin harmanını karıştırır.

RGBA (A'nın 0xFF olması gerekir) farklı bir sabit kullanmayı gerektirir, ancak işlev boyutunda değişiklik yapılmaz. Ön plan DWORD'leri, 4 baytta depolanan keyfi bir 32 bit sabitine karşı tam eşitlik için karşılaştırılır, böylece herhangi bir piksel sırası veya renk anahtarı rengi kolayca desteklenebilir.

Aynı makine kodu 32 bit modunda da çalışır. 32 bit olarak monte rdietmek ediiçin kaynağa geçin . 64 bit olan diğer tüm kayıtlar örtüktür (lodsd / stosd ve loop) ve diğer açık kayıtlar 32-bit kalır. Ancak, 32 bit C'den aramak için bir sarmalayıcıya ihtiyacınız olacağını unutmayın, çünkü standart x86-32 çağrı kurallarının hiçbiri x86-64 SysV ile aynı regleri kullanmaz.

NASM listelemesi (makine kodu + kaynak), yeni başlayanlara, daha karmaşık talimatların ne yaptığının açıklamalarını içeren bir yorumda bulundu. (Talimat referans kılavuzunun çoğaltılması normal kullanımda kötüdür.)

 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

Orijinal NASM kaynağını bu listeden çıkarmak için, her satırın önde gelen 26 karakterini ile sıyırın <chromakey.lst cut -b 26- > chromakey.asm.
nasm -felf64 chromakey-blend.asm -l /dev/stdout | cut -b -28,$((28+12))- NASM listeleri ile bunu oluşturdum , makine kodu ve kaynak arasında istediğimden daha fazla boş sütun bırakın. Bir nesne dosyası oluşturmak için C veya C ++ ile bağlayabilirsiniz, kullanın nasm -felf64 chromakey.asm. (Veyayasm -felf64 chromakey.asm ).

denenmemiş , ancak yük / yük / cmov / mağaza temel fikrinin sağlam olduğuna eminim, çünkü çok basit.

Arayanın, sabit fonksiyona sabit kodlama yerine, chroma-key sabitini (0x00ff00) ekstra bir argüman olarak geçirmesini gerektirebilirsem, 3 byte tasarruf edebilirim. Alışılmış kuralların, arayan kişi için sabit ayarlanmış daha genel bir fonksiyon yazmasına izin verdiğini sanmıyorum. Ama eğer öyleyse, 3. argüman (şu anda dummy) edxx86-64 SysV ABI'ye iletilir . Sadece cmp eax, 0x0000ff00(5B) 'yi cmp eax, edx(2B) olarak değiştirin.


SSE4 veya AVX ile, bunu daha hızlı (ancak daha büyük kod boyutu) karşılaştırma maskesi tarafından kontrol edilen 32 bitlik bir eleman boyutu değişken karışımı ile yapabilir pcmpeqdve blendvpsyapabilirsiniz. ( pandYüksek baytları görmezden gelebilirsiniz). Paketlenmiş RGB24 için, o pikselin 3 bileşeninin hepsinin eşleştiği bayt cinsinden DOĞRU almak için pcmpeqbve ardından 2x pshufb+ tuşlarını pandkullanabilirsiniz pblendvb.

(Bunun kod golf olduğunu biliyorum, ancak skalar tamsayıya gitmeden önce MMX'i denemeyi düşündüm.)


Bana bu makine koduyla yapılmış bir çalıştırılabilir gönderir misiniz?
ckjbgames

x86_32 lütfen.
ckjbgames

@ckjbgames: Yalnızca pikselleri yerinde değiştiren kısmı yükleyen / kaydeden bir arayan kişi yazmadım. Çalıştırılabilir bir yapı oluşturmak mantıklı gelmeden önce bunu yapmak zorunda kalırdım. Ama eğer yaparsam ne tür bir yürütülebilir? Windows PE32? Linux ELF32? FreeBSD ??
Peter Cordes

ELF32, eğer yapacaksan.
ckjbgames

@ckjbgames: Eğer zaman bulursam, resim yükleyen bir kütüphane arayacağım ve bir şeyler yazacağım. Listeyi tekrar bir araya getirebileceğiniz koda dönüştürmekle ilgili bir paragraf ekledim nasm -felf32. (32 bit için, C'den çağıran bir sarmalayıcı işlevine de ihtiyacınız olacak, çünkü hala x86-64 SysV ABI ile aynı kayıtları kullanıyor.)
Peter Cordes

13

Mathematica 57 35 bayt

güncelleme: varsayılan olarak, kullanılarak yeşil bir arka plan kaldırılır RemoveBackground. İlk başvuru, gereksiz ikinci parametreyi içeriyordu, `{" Background ", Green}".


#~ImageCompose~RemoveBackground@#2&

Resmin 2 arka planını kaldırır ve sonucu resimle 1 oluşturur.


Örnek

i1

Aşağıdaki, infix formundan ziyade önekte kodun nasıl çalıştığını daha açık bir şekilde göstermektedir.

i2


4
Bu, yeşil olan “arka plan” olmadığı görüntüler için işe yarar mı? (Çıktınızda küçük bir yeşil yama kalmış gibi görünüyor)
DBS

Resimde yeşil bir "ada" olsaydı, "{" Arka Plan ", Yeşil}" ek parametresi gerekliydi, bu da toplam 57 bayta yükselecekti. Bu benim ilk gönderimdi. resmin ön tarafında izole edildiğinde, bu parametre düşürüldü
DavidC

11

Python 3 + numpy , 59 bayt

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

Çevrimiçi deneyin!

Girdi, numpypikselleri temsil eden tam sayı üçlelerinin ( #00FF00onaltılık renk kodunun eşdeğeri olduğu [0, 255, 0]) bir dizinin biçiminde verilir . Giriş dizisi, meta başına izin verilen yerinde değiştirilir .

Örnek Görüntüler

Girdi (sorudan)

Arka fon:

ckjbgames' profile picture

Ön Plan:

Dennis' profile picture

Fonksiyonu çalıştırdıktan sonra ön plan görüntüsü:

Merged image with #00FF00 replaced with background pixels

Referans Uygulaması ( opencvgörüntü dosyalarını okumak için kullanılır)

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)

Görüntüyü ekrana getirir ve bir çıktı dosyasına yazar.


17
Ortaya çıkan görüntüdeki tüm kırmızı noktalarda ne var?
Yytsi

1
G / Ç hakkında sordum - bu, şu anki ifadelere (yani "kütüphaneniz") uygun görünüyor, eğer öyleyse, cv2 kendi başına numpy ithalatı gerektiriyor mu? Değilse, 54'te herhangi bir numpy işlevini kullanmadan ve numpy: 'ı almayarak yapabilirsiniz lambda f,b:[x[list(x[0])==[0,255,0]]for x in zip(f,b)]. Eğer tamsayıların listesi de gerçekten kabul edilebilirse, bunu 48 ile yapabilirsinlambda f,b:[x[x[0]==[0,255,0]]for x in zip(f,b)]
Jonathan Allan,

.. aslında dönüşüm için cv2 için numpy gerekli olsa bile , hala mücadele için cv2 almamız gerekmediği için hala 54 byte versiyonunu yapabileceğinizi düşünüyorum.
Jonathan Allan,

5
Eğer G == 255, R ve B sıfır olmasa bile değer değiştirilir, bu da kırmızı noktalara yol açar. Bu, diğer gruplar için daha az görünür olan en sert gruplarda bile olur. Bu nedenle mantık kontrolleri birbirinden bağımsız olarak gerçekleştirilir ve koşullardan yalnızca biri karşılansa bile tek kanalların yerini alır. Örneğin, bir piksel ise [0 255 37]kırmızı ve yeşil bantlar değiştirilecektir.
Leander Moesinger

2
@ LeanderMoesinger: Benekliyim. Bende o böcek de vardı>. <; IDK neden R ve B'yi yok sayarak sadece yeşil = 0xFF kontrolünün doğru olduğunu düşündüm!
Peter Cordes

9

İşlem, 116 99 bayt

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

Maalesef, işleme, lambdalar gibi java 8'i desteklemiyor.

Örnek uygulama: (görüntüyü olduğu gibi kaydeder out.pngve ekranda çizer)

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

settings()Ve setup()işlevlerinden kurtulabilir ve doğrudan kodu çalıştırabilirsiniz.
Kevin Workman

Ben ayarları ve kurulum var @KevinWorkman aksi mümkün olmazdı ekranda görüntüyü, orada göstermek istiyorum böylece
dzaima

#ff00yoksa 0xff00aynı #00ff00Hazırlamada?
Peter Cordes

@PeterCordes # FF00 ne yazık ki sözdizimi hatası veriyor ve # 00FF00 == 0xFF00FF00, bu nedenle 0xFF00 0 0 alfa değerini denetlediği için çalışmıyor
dzaima

@dzaima: Resimlerinizi RGB0 formatında çekebilir misiniz, yani 0x0000FF00aradığınız bit desen nedir?
Peter Cordes

6

Bash + ImageMagick, 45 bayt

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

İki görüntüyü argüman olarak alır ve çıktıları ekranda görüntüler. Değişiklikx: için $3yerine üçüncü bir dosya tartışmaya yazmak için. Yöntem basittir: "arkaplan" resmini okuyun; "ön plan" imagek'i oku; ikinci görüntüdeki "kireç" rengini (# 00ff00) şeffaflık olarak yeniden yorumlayın; daha sonra ikinci görüntüyü birinciye birleştirin ve çıktı alın.

ImageMagick: 28 bayt?

Bunu bir ImageMagick cevabı olarak gönderebilirdim, ancak argümanlarla nasıl başa çıkılacağı net değil. ImageMagick'in yığın temelli bir dil olduğunu belirtmek istiyorsanız (bu tür gerçekten doğru değil ama neredeyse ... gariptir) o zaman -transparent lime -compositeyığında iki görüntü bekleyen ve yığında bir birleştirilmiş görüntü bırakan bir işlevdir. belki de sayılacak kadar iyi olabilir?


3

MATL , 40 37 31 bayt

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

Çevrimdışı tercüman ile çalışan örnek. Resimler, URL'lerine göre girilir (yerel dosya adları da sağlanabilir).

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

açıklama

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

3

Pyth , 27 bayt

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

Alınan girdi alır. Giriş, görüntü dosyalarının iki yoludur. Bir dosyanın çıktısı o.pngMaalesef, güvenlik nedeniyle çevrimiçi tercüman üzerinde test edilemiyor ( 'üzerinde devre dışı bırakılmış). Pyth almak gerekecekTest etmek için bilgisayarınızda .

açıklama

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

Chroma-key harmanlama işlevi kendi başıma x86 makine kodu yanıtımla aynı şekilde 13 bayttır. Daha önce bunun G / Ç imajını da veren eksiksiz bir program olduğunu bilmiyordum.
Peter Cordes,

2

Matlab 2016b ve Octave, 62 59 bayt

Giriş: A = MxNx3 unit8 ön plan matrisi, B = MxNx3 unit8 arka plan matrisi.

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

Çıktı: A = MxNx3 unit8 matrisi

Örnek kullanım:

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)

1

C ++, 339 bayt

Bu, CImg'yi kullanır ve diğer formatlardaki dosyaları da alabilir. Sonuç bir pencerede görüntülenir.

#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();}}

İle derleyin g++ chromakey.cpp -g -L/usr/lib/i386-linux-gnu -lX11 -o chromakey -pthread.


1

R, 135 bayt

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

Anonim işlev, bağımsız değişken olarak 2 png dosya yolunu alır ve adı verilen bir png resmi çıkarır a.png.

Açıklamaları ile biraz ungolfed:

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

1

SmileBASIC, 90 bayt anahtar nedir

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ön ve çıktı, Jarka plan. Her ikisi de 32 bit ARGB biçimindeki tamsayı piksel dizileridir.

Ungolfed

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

Açıklama:

ARYOP, bir dizideki her öğeye basit bir işlem uygulayan bir işlevdir.
Buna denirARYOP mode, output_array, input_array_1, input_array_2, ...

İlk olarak, görüntüdeki hangi piksellerin yeşil olduğunu belirlemek için -16711936 (yeşil rengin RGBA gösterimi), ön plan görüntüsündeki her pikselden çıkarılır. Bu bir dizi verir0 yeşil pikselleri temsil eden ve diğer herhangi bir sayı yeşil olmayan pikselleri temsil eder.

Sıfır olmayan tüm değerleri dönüştürmek 1için kareler kesilir (negatif sayıları kaldırmak için), sonra0 ve1 .

Bu, yalnızca 0s ve 1s olan bir diziyle sonuçlanır .
0s ön plan görüntüsündeki yeşil pikselleri temsil eder ve arka plandaki piksellerle değiştirilmelidir.
1s yeşil olmayan pikselleri temsil eder ve bunların ön plandaki piksellerle değiştirilmesi gerekir.

Bu, doğrusal enterpolasyon kullanılarak kolayca yapılabilir.


0

PHP, 187 bayt

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

24bit PNG dosyalarını varsayar; dosya isimlerini komut satırı argümanlarından alır, stdout'a yazar.
İle koş-r .

Yıkmak

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

0

JavaScript (ES6), 290 bayt

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

Girdiyi Imagebir HTML <image>öğesiyle oluşturulabilen iki nesne olarak (körleme sözdiziminde) alır . Uygulanabilecek sonuçta elde edilen görüntünün Base64 veri URL'sine çözümlenen bir Sözü verir.src bir arasında <image>.

Buradaki fikir, her biri için alfa değerini ayarlamaktı. #00FF00 piksel için0 ve sonra arkaplanı arka planın üstüne tuşlayarak ön planı boyamaktı.

Test Parçacığı

Ön plan ve arkaplanın veri URL'lerine dahil edilmesi buraya gönderilemeyecek kadar büyüktü, bu yüzden CodePen'e taşındı:

Çevrimiçi deneyin!


0

OSL , 83 bayt

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

İki giriş alır. Birincisi ön ve ikincisi arka plan.

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.