c++ - 在 OpenCV 中合并两个 Mat 对象

标签 c++ arrays image opencv mat

我写了一个小函数,以便能够将图像的像素“粘贴”在另一个图像的顶部,但不知何故它不起作用:虽然我“粘贴”图像的“形状”是正确的,但颜色是不是。 enter image description here

示例花是第一张图片,第二张图片是黑色梯形 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 对象的像素阵列实际上是如何组织的?我想如果我知道其中的内容,我将更容易操作这些数组。

最佳答案

因为你正在迭代 mat2类型错误。更改 Vec3b intensity2 = mat2.at<Vec3b>(j, i);到:

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

并且消除了奇怪的条纹。并使用 intensity2[3]处理 alpha channel 。


假设您正在使用 -1 读取黑色梯形 png 文件标志:

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

哪里-1 flag指定读取 alpha channel 。然后 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) 强度。

接下来,您应该定义如何处理 alpha channel 。您可以混合两个 Mat 或覆盖另一个,无论如何。一种简单的方法是覆盖 mat1仅当 mat2 中的 alpha channel 时足够大:

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。或者通过混合两个 Mat 进一步扩展规则:

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

关于c++ - 在 OpenCV 中合并两个 Mat 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28781931/

相关文章:

c++ - 使用 C++ 查找与文本匹配的行号

c++ - 对象成员的迭代器 "pointing"

arrays - 遍历两个数组删除perl中的重叠

c++ - 通过 CMake 将外部库包含到 CLion 项目中

c++ - 不断收到错误 ' no match for ' operator>>' ;

javascript - 简化我的函数(循环、数组)?

javascript - HTML 选择元素中对象数组的多个 Angular 过滤器

python - OpenCV - imread()、imwrite() 增加了 png 的大小?

java - 这两种图片加载代码有什么区别?

jquery - onclick 在三个图像之间切换?