OpenCV之cvAddWeighted直接C语言实现版addWeighted,应对上下平滑融合拼接
关于OpenCV中的cvAddWeighted的介绍可参见《opencv中的cvAddWeighted函数》
cvAddWeighted有个问题,它只能实现两张图片的直接融合,往往产生明显的融合边界,这在我的图像操作应用中不能满足要求,特别是那讨厌的边界,所以我准备改进之。下面直接贴上我的addWeighted
/************************************************************************/ // Author:xingrun // Description:addWeighted自动根据设定参数完成融合, // 一开始src1,src2的权值分别为1,0,最后权值分别变成0,1,融合效果较好,无明显边界 // Time:2014-1-6 20:50:03 // Param:暂未实现通道为1的图片融合处理 /************************************************************************/ void addWeighted(const IplImage *src1,const IplImage* src2,IplImage* dst,double gama = 0) { CV_Assert(src1->depth == src2->depth); CV_Assert(dst->depth == src2->depth); CV_Assert(src1->nChannels == src2->nChannels); CV_Assert(dst->nChannels == src2->nChannels); CvRect rect1 = cvGetImageROI(src1); CvRect rect2 = cvGetImageROI(src2); CvRect dstRect = cvGetImageROI(dst); CV_Assert(rect1.width == rect2.width && rect1.height == rect2.height); CV_Assert(rect2.width == dstRect.width && rect2.height == dstRect.height); int c,r,l;//c--Channel,r-Row,l-coLumn int val,val1,val2; double alpha = 0; double beta = 0; if(dst->nChannels==3) { for (c = 0; c < 3; c++) for (r = dstRect.y; r < dstRect.y+dstRect.height; r++) for (l = dstRect.x; l < dstRect.x+dstRect.width; l++) { val1 = ((uchar*)(src1->imageData + src1->widthStep*(rect1.y+r-dstRect.y)))[(rect1.x+l-dstRect.x)*3+c]; val2 = ((uchar*)(src2->imageData + src2->widthStep*(rect2.y+r-dstRect.y)))[(rect2.x+l-dstRect.x)*3+c]; alpha = (double)(dstRect.y+dstRect.height-1-r)/(dstRect.height-1); beta = 1 -alpha; val = (int)(val1*alpha + val2*beta + gama); if(val<0) val=0; else if(val>255) val=255; ((uchar*)(dst->imageData + dst->widthStep*r))[l*3+c] = (uchar)val; } } else if(dst->nChannels==1) { //留待实现 } }
上面代码中,参数alpha和beta是根据高度(或row)来自动调整的,所以我的这个函数适合上下融合图片,如果需要左右融合或者特定形状融合的话,可以增加传入参数来扩展功能。
下面分别使用cvAddWeighted和addWeighted对比一下上下融合的结果。
源图片:
21.jpg
22.jpg
在MFC中使用以下代码:
void CMytestDlg::OnBnClickedBtnAddWeightedComp() { IplImage *src1 = cvLoadImage("dataset\\21.jpg"); IplImage *src2 = cvLoadImage("dataset\\22.jpg"); IplImage *dst_cvAddWeighted = NULL; IplImage *dst_addWeighted = NULL; IplImage *weightImg = NULL; if (src1 && src2) { dst_cvAddWeighted = cvCreateImage(cvSize(src1->width,src1->height/2+src2->height),src1->depth,src1->nChannels); dst_addWeighted = cvCreateImage(cvSize(src1->width,src1->height/2+src2->height),src1->depth,src1->nChannels); weightImg = cvCreateImage(cvSize(src1->width,src1->height/2),src1->depth,src1->nChannels); if (dst_cvAddWeighted && dst_addWeighted) { cvNamedWindow("cvAddWeighted"); cvNamedWindow("addWeighted"); //融合中间部分 cvSetImageROI(src1,cvRect(0,src1->height/2,src1->width,src1->height/2)); cvSetImageROI(src2,cvRect(0,0,src1->width,src1->height/2)); cvSetImageROI(dst_cvAddWeighted,cvRect(0,src1->height/2,src1->width,src1->height/2)); cvSetImageROI(dst_addWeighted,cvRect(0,src1->height/2,src1->width,src1->height/2)); cvAddWeighted(src1,0.5,src2,0.5,0,dst_cvAddWeighted); addWeighted(src1,src2,dst_addWeighted); cvResetImageROI(src1); cvResetImageROI(src2); cvResetImageROI(dst_cvAddWeighted); cvResetImageROI(dst_addWeighted); //拷贝上部分 cvSetImageROI(src1,cvRect(0,0,src1->width,src1->height/2)); cvSetImageROI(dst_cvAddWeighted,cvRect(0,0,src1->width,src1->height/2)); cvSetImageROI(dst_addWeighted,cvRect(0,0,src1->width,src1->height/2)); cvCopy(src1,dst_cvAddWeighted); cvCopy(src1,dst_addWeighted); cvResetImageROI(src1); cvResetImageROI(dst_cvAddWeighted); cvResetImageROI(dst_addWeighted); //拷贝下面部分 cvSetImageROI(src2,cvRect(0,src1->height/2,src1->width,src2->height - src1->height/2)); cvSetImageROI(dst_cvAddWeighted,cvRect(0,src1->height,src1->width,src2->height - src1->height/2)); cvSetImageROI(dst_addWeighted,cvRect(0,src1->height,src1->width,src2->height - src1->height/2)); cvCopy(src2,dst_cvAddWeighted); cvCopy(src2,dst_addWeighted); cvResetImageROI(src2); cvResetImageROI(dst_cvAddWeighted); cvResetImageROI(dst_addWeighted); //显示 cvShowImage("cvAddWeighted",dst_cvAddWeighted); cvWaitKey(10); cvShowImage("addWeighted",dst_addWeighted); cvWaitKey(10); //保存 cvSaveImage("cvAddWeighted.jpg",dst_cvAddWeighted); cvSaveImage("addWeighted.jpg",dst_addWeighted); //释放内存 cvReleaseImage(&dst_cvAddWeighted); dst_cvAddWeighted = NULL; cvReleaseImage(&dst_addWeighted); dst_addWeighted = NULL; //cvDestroyAllWindows(); } cvReleaseImage(&src1); src1 = NULL; cvReleaseImage(&src2); src2 = NULL; } }
得到结果:
cvAddWeighted.jpg
addWeighted.jpg
细看结果,可发现cvAddWeighted.jpg中有明显的拼接痕迹,而在addWeighted.jpg不存在,效果明显。