简介
本篇是对实现复制粘贴的笔记记录。
注:本篇使用的所有图像皆来源自网络,如有侵权,请联系本人删除。
基本原理
这里分为两步:1、从第一张图像中抠出感兴趣区域。
2、将感兴趣区域粘贴到第二张图片中。
分别可以参考前面文档:1、opencv实现图像分割,分离前景和背景(2)
2、残差金字塔实现
抠图部分
参考前面的提到的文档:《opencv实现图像分割,分离前景和背景(2)》,最后将扣出来的感兴趣图像复制到resCopy,并将对应图像掩码保存到
binMask中。
对应结果显示如下:
手动抠图操作 扣去图像的掩码 抠出的图像
掩码处理
在直接根据掩码进行图像粘贴融合之前,需要先对掩码进行处理,否则会导致融合图像的边缘很模糊。
具体的操作,可以参考前面提到的文档:《残差金字塔实现》
大致代码如下:
GaussianBlur(pySrc[0], pyDst[0], Size(g_nGaussianBlurValue*2+1,g_nGaussianBlurValue*2+1), 0, 0);
pyWidth[1] = pyWidth[0] / 2;
pyHeight[1] = pyHeight[0] / 2;
resize(pyDst[0], pySrc[1], Size(pyHeight[1], pyWidth[1]));
GaussianBlur(pySrc[1], pyDst[1], Size(g_nGaussianBlurValue*2+1,g_nGaussianBlurValue*2+1), 0, 0);
pyWidth[2] = pyWidth[1] / 2;
pyHeight[2] = pyHeight[1] / 2;
resize(pyDst[1], pySrc[2], Size(pyHeight[2], pyWidth[2]));
GaussianBlur(pySrc[2], pyDst[2], Size(g_nGaussianBlurValue*2+1,g_nGaussianBlurValue*2+1), 0, 0);
pyWidth[3] = pyWidth[2] / 2;
pyHeight[3] = pyHeight[2] / 2;
resize(pyDst[2], pySrc[3], Size(pyHeight[3], pyWidth[3]));
resize(pySrc[3], tmp, Size(pyHeight[2], pyWidth[2]));
pyDst[2] = tmp;
resize(pyDst[2], tmp, Size(pyHeight[1], pyWidth[1]));
pyDst[1] = tmp;
resize(pyDst[1], tmp, Size(pyHeight[0], pyWidth[0]));
pyDst[0] = tmp;
imshow("mask22", pyDst[0]);
binMask = pyDst[0];
最开始的pySrc[0]就是之前的掩码图像binMask,先建立该图像的高斯金字塔,接着对图像进行恢复。注意这里并没有使用残差金字塔,所以恢复后的
图像将会是原图像的边缘模糊处理后图像。
对应的效果显示如下:
原始掩码图像 处理后掩码图像
图像粘贴
获得了处理之后的掩码,接着就是进行最后的图像粘贴融合操作。
1、计算出掩码对应感兴趣区域,在原图中的坐标位置,保存到rectResCopy中。
void getResCopyAddr(Mat src){
int i, j;
IplImage ipI = src;
int width = src.rows;
int height = src.cols;
int minWidth,maxWidth, minHeight, maxHeight;
CvScalar s1;
for(i=0; i<width; i++){
for(j=0; j<height; j++){
s1 = cvGet2D(&ipI, i, j);
if(s1.val[0] > 0){
if(maxWidth == 0){
minWidth = i;
maxWidth = i;
minHeight = j;
maxHeight = j;
}
if(minWidth > i)
minWidth = i;
if(maxWidth < i)
maxWidth = i;
if(minHeight > j)
minHeight = j;
if(maxHeight < j)
maxHeight = j;
}
}
}
rectResCopy.x = minWidth;
rectResCopy.y = minHeight;
rectResCopy.width = maxWidth - minWidth;
rectResCopy.height = maxHeight - minHeight;
}
2、根据掩码图像像素值,进行融合图像权重计算计算:如果掩码值为0,则新像素值全部为被粘贴图像;如果掩码值为[1, 254],则新
像素值为:(被粘贴图像 * (1 - (掩码值 / 255))) + (感兴趣区域 * (掩码值 / 255));如果掩码值为255,则新像素值为感兴趣区域。
void getPaste(Mat src1, Mat src2, Rect rectAddr){
int i, j;
IplImage ip1 = src1;
IplImage ip2 = src2;
IplImage ip3 = binMask;
CvScalar s1, s2, s3;
int dstWidth = src1.rows;
int dstHeight = src1.cols;
int addrX = 70, addrY = 70;
double scale;
if(addrX + rectAddr.width > dstWidth){
printf("pic Size is too big in Width!\n");
return;
}
if(addrY + rectAddr.height > dstHeight){
printf("pic Size is too big in Height!\n");
return;
}
for(i=rectAddr.x; i<rectAddr.x + rectAddr.width; i++){
for(j=rectAddr.y; j<rectAddr.y + rectAddr.height; j++){
s1 = cvGet2D(&ip1, addrX + i - rectAddr.x, addrY + j -rectAddr.y);
s2 = cvGet2D(&ip2, i, j);
s3 = cvGet2D(&ip3, i, j);
if(s3.val[0] > 0){
scale = s3.val[0] / 255;
s1.val[0] = (s1.val[0] * (1 - scale)) + (s2.val[0] * scale);
s1.val[1] = (s1.val[1] * (1 - scale)) + (s2.val[1] * scale);
s1.val[2] = (s1.val[2] * (1 - scale)) + (s2.val[2] * scale);
cvSet2D(&ip1, addrX + i - rectAddr.x, addrY + j -rectAddr.y, s1);
}
}
}
}
结果显示
显示的结果如下:
直接融合 处理掩码后融合
代码下载:http://download.csdn.net/detail/u011630458/9424343