Konwertuj kolor RGBA na RGB

79

Jak przekonwertować krotkę kolorów RGBA, na przykład (96, 96, 96, 202), na odpowiednią krotkę kolorów RGB?

Edytować:

To, czego chcę, to uzyskać wartość RGB, która jest najbardziej podobna do krotki RGBA wizualnie na białym tle.

Jacek
źródło
3
Czy to nie byłoby po prostu (96,96,96)?
Lazarus
24
To zależy od koloru piksela tła.
Frank Bollack,
5
Czy chcesz tylko usunąć kanał alfa? A może chcesz, aby wynik RGB nałożył RGBA na (np.) Białe tło?
Ben James,
1
Możesz przeczytać słynny artykuł „Compositing digital images” (autorstwa Portera i Duffa), aby uzyskać pełne informacje o składzie alfa: keithp.com/~keithp/porterduff
kusma
Odpowiedzi Andrasa Zoltana i hkurabko są również przydatne do obliczenia odwrotnego, to znaczy, jeśli masz różne mieszane kolory alfa i masz oryginalne tła (maty), możesz obliczyć oryginalny kolor RGBA, którego szukałem while;)
nacho4d

Odpowiedzi:

90

Głosowałem za odpowiedzią Johannesa, ponieważ ma rację.

* Pojawiło się kilka komentarzy, że moja pierwotna odpowiedź była nieprawidłowa. Działało, jeśli wartości alfa zostały odwrócone od normalnych. Jednak z definicji to nie zadziała w większości przypadków. Dlatego zaktualizowałem poniższy wzór, aby był poprawny dla normalnego przypadku. To kończy się na równi z odpowiedzią @ hkurabko poniżej *

Bardziej szczegółowa odpowiedź polega jednak na włączeniu wartości alfa do rzeczywistego wyniku koloru na podstawie nieprzezroczystego koloru tła (lub „matowego”, jak to się nazywa).

Jest na to algorytm (z tego linku wikipedii):

  • Normalizuj wartości RGBA, aby wszystkie znajdowały się w przedziale od 0 do 1 - po prostu podziel każdą wartość przez 255, aby to zrobić. Nazwiemy wynik Source.
  • Normalizuj również matowy kolor (czarny, biały cokolwiek). Nazwiemy wynik BGColor Uwaga - jeśli kolor tła jest również przezroczysty, to najpierw będziesz musiał powtórzyć ten proces (ponownie, wybierając matę), aby uzyskać źródło RGB dla tej operacji.
  • Teraz konwersja jest zdefiniowana jako (w pełnym kodzie pseudo tutaj!):

    Source => Target = (BGColor + Source) =
    Target.R = ((1 - Source.A) * BGColor.R) + (Source.A * Source.R)
    Target.G = ((1 - Source.A) * BGColor.G) + (Source.A * Source.G)
    Target.B = ((1 - Source.A) * BGColor.B) + (Source.A * Source.B)
    

Aby uzyskać ostateczne wartości 0-255 Target, po prostu pomnóż wszystkie znormalizowane wartości z powrotem przez 255, upewniając się, że ograniczasz do 255, jeśli którakolwiek z połączonych wartości przekracza 1,0 (jest to nadmierna ekspozycja i istnieją bardziej złożone algorytmy radzące sobie z tym które obejmują przetwarzanie całego obrazu itp.).

EDYCJA: W swoim pytaniu powiedziałeś, że chcesz mieć białe tło - w takim przypadku po prostu ustaw BGColor na 255,255,255.

Andras Zoltan
źródło
9
W świetle edycji pytania jest to bardzo trafna i dobra odpowiedź. Usunąłem moje i mam nadzieję, że się rozwiniesz, ponieważ wyjaśniłeś sprawy o wiele lepiej :)
Joey
Myślę, że ta odpowiedź zakłada, że ​​kolor tła to rgb, a nie rgba.
Leo
Jest to niezwykłe, biorąc pod uwagę, że RGBA (0,0,0,1) jest całkowicie nieprzezroczystą czernią. Ale przy podanym algorytmie byłaby to całkowicie przezroczysta czerń. Myślę, że zmiana kolejności algorytmu, aby to odzwierciedlić, uczyniłaby go bardziej pomocnym źródłem i lepszą odpowiedzią na pytanie.
Bryan Rayner
1
@BryanRayner dodał kilka zmian do mojej odpowiedzi. Regularnie zdobywam głosy za tę odpowiedź i możliwe, że niektórzy ją znajdują, ponieważ sami muszą odwrócić algorytm. Byłoby lepiej, gdyby było pełniejsze. Dzięki.
Andras Zoltan
2
Jeśli ktoś jest nadal zainteresowany, ten JSBin pozwala obserwować transformację koloru. Jest również gotowy do użycia jako funkcja javacript. Użyłem BGColor jako białego, ponieważ po prostu nie rozumiem koncepcji matowej (przepraszam!). Link jest następujący: jsbin.com/qocixeh/edit?html,js,console,output, a także sedno: gist.github.com/vladimirbrasil/bd139851ff757a1c8cb46fac93e733eb Mam nadzieję, że to też pomoże. Milion dzięki za odpowiedź!
Vladimir Brasil
40

hm ... w odniesieniu do

http://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending

rozwiązanie dostarczone przez Andrasa Zoltana należy nieznacznie zmienić na:

Source => Target = (BGColor + Source) =
Target.R = ((1 - Source.A) * BGColor.R) + (Source.A * Source.R)
Target.G = ((1 - Source.A) * BGColor.G) + (Source.A * Source.G)
Target.B = ((1 - Source.A) * BGColor.B) + (Source.A * Source.B)

U mnie ta zmieniona wersja działa dobrze, ponieważ w poprzedniej wersji. wersja rgba (0,0,0,0) z matowym rgb (ff, ff, ff) zostanie zmieniona na rgb (0,0,0).

hkurabko
źródło
Wierzę, że masz rację. Wikipedia i Andras Zoltan odpowiadają nieco inaczej.
nacho4d
1
Zgadzam się, używaj tej wersji, a nie @Andras Zoltan's. W przypadku scenariusza testowego przekonwertuj rgba (0,0,0, .7) na rgb w tle (255,255,255), używając obu formuł; forumala hkurabko wyraźnie daje poprawną odpowiedź.
Ryre
4
Andras definiuje alfa 0 jako nieprzezroczyste i 255 jako przezroczyste, podczas gdy CSS definiuje to w odwrotny sposób. Ta odpowiedź działa z definicją alfa w CSS.
Casey Chu
1
+1 Działa z najpopularniejszą definicją alfa (0 = przezroczysta), taką jak OpenGL, SDL, edytory graficzne.
DLight
+1 - i zaktualizowałem swoją odpowiedź, aby działała z alfą jako `` właściwą drogą '', jak również w tym przypadku. Jak na ironię, po prostu spróbowałem użyć mojego rozwiązania, aby to zrobić, zgadzam się, że moja pierwotna odpowiedź, chociaż miała swój własny sens, tak naprawdę nie działała w większości aplikacji.
Andras Zoltan
8

W moim przypadku chciałem przekonwertować obraz RGBA na RGB, a poniższe działały zgodnie z oczekiwaniami:

rgbImage = cv2.cvtColor(npimage, cv2.COLOR_RGBA2RGB)
SulabhMatele
źródło
5

Zależy to od używanej przestrzeni kolorów. Jeśli RGBA jest we wstępnie zwielokrotnionej przestrzeni kolorów i jest półprzezroczyste, należy podzielić alfa, aby uzyskać prawidłowy kolor RGB. Jeśli kolor jest w niezmnożonej przestrzeni kolorów, możesz po prostu odrzucić kanał alfa.

kusma
źródło
1

Oto wygodna funkcja SASS zgodna z odpowiedziami Andrasa i hkurabko.

@function rgba_blend($fore, $back) {
  $ored: ((1 - alpha($fore)) * red($back) ) + (alpha($fore) * red($fore));
  $ogreen: ((1 - alpha($fore)) * green($back) ) + (alpha($fore) * green($fore));
  $oblue: ((1 - alpha($fore)) * blue($back) ) + (alpha($fore) * blue($fore));
  @return rgb($ored, $ogreen, $oblue);
}

Stosowanie:

$my_color: rgba(red, 0.5); // build a color with alpha for below

#a_div {
  background-color: rgba_blend($my_color, white);
}
Rohanthewiz
źródło
w sass, możemy użyć:mix($color, white, $alpha*100)
S.Serpooshan
1

Oto kod java (działa na Android API 24):

        //int rgb_background = Color.parseColor("#ffffff"); //white background
        //int rgba_color = Color.parseColor("#8a000000"); //textViewColor 

        int defaultTextViewColor = textView.getTextColors().getDefaultColor();

        int argb = defaultTextViewColor;
        int alpha = 0xFF & (argb >> 24);
        int red = 0xFF & (argb >> 16);
        int green = 0xFF & (argb >> 8);
        int blue = 0xFF & (argb >> 0);
        float alphaFloat = (float)alpha / 255;

        String colorStr = rgbaToRGB(255, 255, 255, red, green, blue, alphaFloat);

funkcjonować:

protected String rgbaToRGB(int rgb_background_red, int rgb_background_green, int rgb_background_blue,
                        int rgba_color_red, int rgba_color_green, int rgba_color_blue, float alpha) {

    float red = (1 - alpha) * rgb_background_red + alpha * rgba_color_red;
    float green = (1 - alpha) * rgb_background_green + alpha * rgba_color_green;
    float blue = (1 - alpha) * rgb_background_blue + alpha * rgba_color_blue;

    String redStr = Integer.toHexString((int) red);
    String greenStr = Integer.toHexString((int) green);
    String blueStr = Integer.toHexString((int) blue);

    String colorHex = "#" + redStr + greenStr + blueStr;

    //return Color.parseColor(colorHex);
    return colorHex;
}
miłość na żywo
źródło