2015-02-28 4 views
0

Я написал небольшую функцию, чтобы иметь возможность «приклеивать» пиксели изображения поверх другого, но это как-то не работает: хотя «фигуры» моего «прилипания», изображение правильное, цвета нет. enter image description hereСлияние двух матовых объектов в OpenCV

Примерный цветок - это первое изображение, а в качестве второго изображения у меня был черный трапециевидный png. Как вы можете видеть, существует множество проблем: 1. Цвета отображаются странно. На самом деле нет цветов, только оттенков серого и некоторых странных полос в качестве наложения. 2. Значения альфа-диапазона не соблюдаются. Белая часть наложенного изображения прозрачна в png.

Вот мой код:

void mergeMats(Mat mat1, Mat mat2, int x, int y){ 
    //unsigned char * pixelPtr = (unsigned char *)mat2.data; 
    //unsigned char * pixelPtr2 = (unsigned char *)mat1.data; 
    //int cn = mat2.channels(); 
    //int cn2 = mat2.channels(); 
    //Scalar_<unsigned char> bgrPixel; 

    for (int i = 0; i < mat2.cols; i++){ 
     for (int j = 0; j < mat2.rows; j++){ 
      if (x + i < mat1.cols && y + j < mat1.rows){ 

       Vec3b &intensity = mat1.at<Vec3b>(j+y, i+x); 
       Vec3b intensity2 = mat2.at<Vec3b>(j, i); 
       for (int k = 0; k < mat1.channels(); k++) { 
        intensity.val[k] = saturate_cast<uchar>(intensity2.val[k]); 
       } 
       //pixelPtr2[(i + x)*mat1.cols*cn2 + (j + y)*cn2 + 0] = pixelPtr[(i + x)*mat2.cols*cn + (j + y)*cn + 0]; 
       //pixelPtr2[(i + x)*mat1.cols*cn2 + (j + y)*cn2 + 1] = pixelPtr[(i + x)*mat2.cols*cn + (j + y)*cn + 1]; 
       //pixelPtr2[(i + x)*mat1.cols*cn2 + (j + y)*cn2 + 2] = pixelPtr[(i + x)*mat2.cols*cn + (j + y)*cn + 2]; 
      } 
     } 
    } 
} 

Закомментированный код был другой подход, но имел те же результаты. Итак, вот мои вопросы: 1. Как решить проблемы 2 (1. цвета ..., 2. alpha ...) 2. Как на самом деле пиксельный массив любого Mat-Object, хорошо, организован? Думаю, мне было бы легче манипулировать этими массивами, если бы я знал, что в них.

ответ

2

Потому что вы повторяете mat2 с неправильным типом. Изменение Vec3b intensity2 = mat2.at<Vec3b>(j, i); на:

Vec4b intensity2 = mat2.at<Vec4b>(j, i); 

и странные полосы устраняются. И используйте intensity2[3] для работы с альфа-каналом.


Предположим, что вы читаете черной трапеции PNG файл, используя -1 флаг:

auto trapezoidImg = cv::imread("trapezoid.png", -1); 

где -1flag указывает, что альфа-канал для чтения. Затем trapezoidImg организован в следующем формате:

[B, G, R, A, B, G, R, A, ......; 
    B, G, R, A, B, G, R, A, ......; 
    ...... 
    B, G, R, A, B, G, R, A, ......] 

Вы можете распечатать trapezoidImg, например, с помощью std::cout, чтобы выяснить этот формат.

Если вы читали trapezoidImg с помощью at<Vec3b>, что вы получаете на самом деле (B, G, R), (A, B, G), (R, A, B), ......, и вот откуда пришли странные полосы. Поэтому используйте at<Vec4b> для правильной считывания (R, G, B, A).

Далее вы должны определить, что делать с альфа-каналом. Вы можете смешать два мата или переопределить другое, что угодно. Один простой способ переопределить mat1 только тогда, когда альфа-канал в mat2 достаточно велик:

cv::Vec3b &intensity = mat1.at<cv::Vec3b>(j + y, i + x); 
cv::Vec4b intensity2 = mat2.at<cv::Vec4b>(j, i); 
for (int k = 0; k < mat1.channels(); k++) { 
    if (intensity2.val[3] > 250){ //3 for alpha channel 
     intensity.val[k] = cv::saturate_cast<uchar>(intensity2.val[k]); 
    } 
} 

Этого достаточно, чтобы иметь дело с черной трапеции PNG с прозрачным фоном. Или дальнейшее расширение правила путем смешивания двух мат:

cv::Vec3b &intensity = mat1.at<cv::Vec3b>(j + y, i + x); 
cv::Vec4b intensity2 = mat2.at<cv::Vec4b>(j, i); 

auto alphaValue = cv::saturate_cast<uchar>(intensity2.val[3]); 
auto alpha = alphaValue/255.0; 

for (int k = 0; k < 2; k++) { //BGR channels only 
    intensity.val[k] = cv::saturate_cast<uchar>(
     intensity2.val[k] * alpha + intensity.val[k] * (1.0 - alpha)); 
} 
+0

Спасибо за ответ! Сейчас это работает. Моя единственная проблема - это альфа: мое фоновое изображение предоставляется с видео, поэтому не имеет альфа-канала. Я попытался решить это, добавив 'if (intensity2.val [3] == 0) continue;' перед циклом канала, а затем цикл mat1.channel() - раз, чтобы в конечном итоге соединить пиксели переднего и заднего фона вместе с 'uchar alpha = интенсивностью2.val [3];' и 'intensity.val [k] = saturate_cast ((intensity2.val [k] * alpha) + (intensity.val [k] * (1.0 - alpha))); '- что не работает, к сожалению ... – Fly

+0

' uchar alpha = intensity2.val [3]; 'значение от 0 до 255. Поэтому '(1.0 - alpha)', вероятно, не работает. – mcchu

+0

О, верно ... Странно, что он все еще не работает даже после того, как я его отредактировал ... – Fly

Смежные вопросы