在OpenCV C++中对彩色图像进行掩蔽

3
我是一名有用的助手,可以为您翻译文本。

我有一张黑白图像和一张同样大小的彩色图像。我想将它们合并成一张图像,在黑白图像为黑色的地方显示黑色,在黑白图像为白色的地方显示与彩色图像相同的颜色。

以下是C++代码:

#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main(){
    Mat img1 = imread("frame1.jpg"); //coloured image
    Mat img2 = imread("framePr.jpg", 0); //grayscale image

    imshow("Oreginal", img1);

    //preform AND
    Mat r;
    bitwise_and(img1, img2, r);

    imshow("Result", r);

    waitKey(0);
    return 0;

}

这是错误信息:


OpenCV Error: Sizes of input arguments do not match (The operation is neither 'array op array' (where arrays have the same size and type), nor 'array op scalar', nor 'scalar op array') in binary_op, file /home/voja/src/opencv-2.4.10/modules/core/src/arithm.cpp, line 1021
terminate called after throwing an instance of 'cv::Exception'
  what():  /home/voja/src/opencv-2.4.10/modules/core/src/arithm.cpp:1021: error: (-209) The operation is neither 'array op array' (where arrays have the same size and type), nor 'array op scalar', nor 'scalar op array' in function binary_op

Aborted (core dumped)
2个回答

2
首先,黑白(二进制)图像与灰度图像不同。两者都是类型为CV_8U的Mat。但是,灰度图像中的每个像素可以取0到255之间的任何值。而二进制图像只能有两个值 - 零和非零数。
其次,不同类型的Mat无法应用于bitwise_and。灰度图像是一种单通道图像,类型为CV_8U(每像素8位),而彩色图像则是一种类型为CV_BGRA(每像素32位)的三通道图像。
看起来你想做的事情可以通过掩码实现。
//threshold grayscale to binary image 
cv::threshold(img2 , img2 , 100, 255, cv::THRESH_BINARY);
//copy the color image with binary image as mask
img1.copyTo(r, img2);

阈值处理是多余的。copyTo将复制掩码中所有值!=0的像素。我认为你需要将r初始化为零。 - Antonio
@Antonio 初始化为零可能不是必要的,因为copyTorealloc时将所有元素设置为零。但是,出于清晰起见,我也更喜欢将其初始化为零 :) - kiranpradeep
@Antonio,我现在更倾向于使用阈值处理,因为我怀疑OP所说的黑/白图像的含义。它很可能是灰度图像。 - kiranpradeep
让我们在聊天中继续这个讨论。点击此处进入聊天室 - Antonio
我是那个下投票的人,很抱歉。当你按照我们在聊天中承诺的进行修改后,我会撤回我的投票。 - Antonio
显示剩余4条评论

2

实际上,使用img1作为掩模在copyTo中相当简单:

//Create a black colored image, with same size and type of the input color image
cv::Mat r = zeros(img2.size(),img2.type()); 
img1.copyTo(r, img2); //Only copies pixels which are !=0 in the mask

正如Kiran所说,您会遇到错误,因为bitwise_and不能对不同类型的图像进行操作。
正如Kiran指出的那样,初始分配和清零并不是必需的(但是预先做事情对性能没有影响)。从文档中可以看到:

当指定操作掩码时,如果Mat::create调用重新分配矩阵,则新分配的矩阵在复制数据之前将初始化为全零。

因此,整个操作可以使用简单的方式完成:
img1.copyTo(r, img2); //Only copies pixels which are !=0 in the mask

“zeros” 也不是多余的吗?因为 “copyTo” 如果需要的话会重新分配内存。我们之所以加上它,是为了更清晰、易懂和可读性 :) - kiranpradeep
@Kiran 它重新分配内存,但(我相信)它不会初始化数据!在copyTo未触及的像素中,你会发现垃圾值。 - Antonio
1
copyTo 的清零操作在这里有文档记录:http://docs.opencv.org/modules/core/doc/basic_structures.html#mat-copyto - kiranpradeep

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接