Конвертировать цвета RGBA в RGB
Как преобразовать цветовой кортеж RGBA, например (96, 96, 96, 202), в соответствующий кортеж RGBA?
Редактировать:
Я хочу получить значение RGB, которое наиболее похоже на кортеж RGBA визуально на белом фоне.
9 ответов
Я проголосовал за ответ Йоханнеса, потому что он прав в этом.
* Было высказано несколько замечаний, что мой первоначальный ответ был неверным. Это работало, если значения альфа были инвертированы от нормального. Однако по определению это не сработает в большинстве случаев. Поэтому я обновил приведенную ниже формулу, чтобы она соответствовала обычному случаю. В итоге получается, что ответ @ hkurabko ниже *
Более конкретный ответ, однако, включает альфа-значение в фактический цветовой результат, основанный на непрозрачном цвете фона (или "матовом", как его называют).
Для этого есть алгоритм (по этой ссылке в википедии):
- Нормализуйте значения RGBA так, чтобы они все были между 0 и 1 - просто разделите каждое значение на 255, чтобы сделать это. Мы назовем результат
Source
, - Нормализовать также матовый цвет (черный, белый любой). Мы назовем результат
BGColor
Примечание. Если фоновый цвет также прозрачен, вам придется сначала повторить процесс (опять же, выбирая подложку), чтобы получить исходный RGB для этой операции. Теперь преобразование определяется как (в полном коде psuedo здесь!):
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)
Чтобы получить окончательные значения 0-255 для Target
вы просто умножаете все нормализованные значения обратно на 255, гарантируя, что вы превысите 255, если какое-либо из комбинированных значений превысит 1,0 (это чрезмерная экспозиция, и есть более сложные алгоритмы, связанные с этим, которые включают обработку всего изображения и т. д.),
РЕДАКТИРОВАТЬ: В своем вопросе вы сказали, что вы хотите белый фон - в этом случае просто установите BGColor 255,255,255.
Хм... относительно
http://en.wikipedia.org/wiki/Alpha_compositing
Решение, предоставленное Андрасом Золтаном, должно быть слегка изменено на:
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)
Эта измененная версия прекрасно работает для меня, потому что в пред. версия rgba(0,0,0,0) с матовым rgb(ff,ff,ff) будет изменена на rgb(0,0,0).
В моем случае я хотел преобразовать изображение RGBA в RGB, и следующее работало так, как ожидалось:
rgbImage = cv2.cvtColor(npimage, cv2.COLOR_RGBA2RGB)
Это зависит от используемого вами цветового пространства. Если RGBA находится в предварительно умноженном цветовом пространстве и полупрозрачен, вам нужно разделить альфа-канал, чтобы получить правильный цвет RGB. Если цвет находится в предварительно не умноженном цветовом пространстве, то вы можете просто отбросить альфа-канал.
Вот некоторый код Java (работает на 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);
функция:
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;
}
Функция Python в соответствии с ответом Хкурабко.
def rgba2rgb(rgba: tuple[int, int, int, float], background: tuple[int, int, int] = (255, 255, 255)):
return (
round(((1 - rgba[3]) * background[0]) + (rgba[3] * rgba[0])),
round(((1 - rgba[3]) * background[1]) + (rgba[3] * rgba[1])),
round(((1 - rgba[3]) * background[2]) + (rgba[3] * rgba[2])),
)
Вот удобная функция SASS в соответствии с ответами Андраса и Хкурабко.
@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);
}
Использование:
$my_color: rgba(red, 0.5); // build a color with alpha for below
#a_div {
background-color: rgba_blend($my_color, white);
}
В моем случае я хотел, чтобы изображение RGB выглядело так, как будто это изображение RGBA на белом фоне. Поскольку типичные методы преобразования просто удаляют канал A, это может привести к тому, что пиксели в каналах RGB станут видимыми, которые ранее были сделаны прозрачными с помощью альфа-канала.
Для меня работало следующее:
import numpy as np
def convert_RGBA_to_RGB(input_image):
# Takes an RGBA image as input
# Based on the following chat with user Andras Deak
## https://chat.stackoverflow.com/transcript/message/55060299#55060299
input_image_normed = input_image / 255 # shape (nx, ny, 4), dtype float
alpha = input_image_normed[..., -1:] # shape (nx, ny, 1) for broadcasting
input_image_normed_rgb = input_image_normed[..., :-1] # shape (nx, ny, 3)
#bg_normed = np.zeros_like(red_normed_rgb) # shape (nx, ny, 3) <-- black background
bg_normed = np.ones_like(input_image_normed_rgb) # shape (nx, ny, 3) <-- white background
composite_normed = (1 - alpha) * bg_normed + alpha * input_image_normed_rgb
composite = (composite_normed * 255).round().astype(np.uint8)
return composite
Функция Typescript в соответствии с ответом hkurabko.
type RgbType = { red: number; green: number; blue: number; };
type RgbaType = { alpha: number; } & RgbType;
export const blendAlphaToBackground = (
rgba: RgbaType,
background: RgbaType = {red: 255, green: 255, blue: 255, alpha: 1},
): RgbaType => {
const red = Math.round((1 - rgba.alpha) * background.red + rgba.alpha * rgba.red);
const green = Math.round((1 - rgba.alpha) * background.green + rgba.alpha * rgba.green);
const blue = Math.round((1 - rgba.alpha) * background.blue + rgba.alpha * rgba.blue);
return {red, green, blue, alpha: 1};
};