OpenCV学习之ROI区域图像叠加及ROI区域的设定imageROI

本文主要是对《OpenCV3编程入门》这本书中的5.2.1 感兴趣区域:ROI这一节的ROI_AddImage()函数进行改进,使得其通用性至少提高1.3倍嘻嘻!顺便在改进过程中,对相应参数知识了解更细致点,因为初学所以可能并没有多高深,大家看看就好了!

书中源码

bool ROI_AddImage()
{
// 【1】读入图像
Mat srcImage1= imread(“dota_pa.jpg”);
Mat logoImage= imread(“dota_logo.jpg”);
if( !srcImage1.data ) { printf(“读取srcImage1错误~! \n”); return false; }
if( !logoImage.data ) { printf(“读取logoImage错误~! \n”); return false; }
// 【2】定义一个Mat类型并给其设定ROI区域
Mat imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));
// 【3】加载掩模(必须是灰度图)
Mat mask= imread(“dota_logo.jpg”,0);
//【4】将掩膜拷贝到ROI
logoImage.copyTo(imageROI,mask);
// 【5】显示结果
namedWindow("<1>利用ROI实现图像叠加示例窗口");
imshow("<1>利用ROI实现图像叠加示例窗口",srcImage1);
return true;
}

这个函数的局限性在于,每次换不同的图片必须要在该函数中修改图片路径,同时还要根据不同的图片修改表示矩形区域的Rect()函数中的坐标参数。

Rect(int_x,int_y,int_width,int_height)

前两个参数指定矩形左上角坐标,后两个指定矩形的长宽

源码对后两个参数直接调用的是要叠加的logo图像的长宽,即直接在背景图中标记一块与logo图像同等大小的区域,这个可以不用专注。关键在于前两个参数,即区域坐标位置的设定,需要严格符合标准。假如你nbcs这个部分,直接修改个图像路径想试试你精心准备的其它图片的叠加效果,那结果只有大难淋头噜。

因为本人之前就是这样,随便选了两个看似差不多的图片就直接放上去,结果可想而知,又是搞opencv的最怕碰到的那个错误。
在这里插入图片描述
因为你很难搞懂这个到底是配置错误还是代码错误,因为两者都有可能报同样错误呕!结果就是你在网上查找130遍也不一定会有结果!

我分别查看了书中使用的两张图片与我使用的图片的像素大小,书中背景图为1024X576,logo图为200X200,我用的背景图为800X449,logo图为259X200.看似logo图都差不多大,但是结合源码中给的坐标参数就能发现问题之处了。Rect()函数中前两个参数为指定矩形左上角坐标,有源码可知坐标为(200,250),若用书中的logo图的话,那么矩形的右下角坐标为(400,450),即加上logo图的像素大小,发现依旧在背景图的范围里面。但是如果用我自己找的图,那么矩形右下角坐标为(459,450),可以发现纵坐标为450已经超过了背景图的高449,最终报错,改了下参数才成功。可见,哪怕是差一个像素都不行。

因此,结合这个问题,我在源码的基础上对ROI_AddImage()函数进行改进,使得其更具有通用性,而不是每次都得到该函数中换个图片路径,还得观察图片的像素大小来修改坐标参数,避免在这上面浪费个13分钟呕!

改进代码

bool ROI_AddImage(Mat srcImage,Mat logoImage)//输入原图,logo图
{
	//设定ROI区域
	Mat imageROI = srcImage(Rect(0, srcImage.rows-logoImage.rows, logoImage.cols, logoImage.rows));//左上角纵坐标(原图高度-logo高度)
	//加载掩膜(必须是灰度图)
	Mat mask;
	cvtColor(logoImage, mask, COLOR_RGB2GRAY);//用转换函数转换成灰度图
	//将掩膜复制到ROI
	logoImage.copyTo(imageROI, mask);
	imshow("【插入处掩膜化】", imageROI);
	//显示结果
	imshow("【叠加结果】", srcImage);
	return true;
}

简单来说就是在该函数中加了两个Mat类型的形数作为背景图与logo图的存储,同时将矩形参数的横坐标设为0,即矩形区域的左边与背景图左边重合,而纵坐标我设置的是原图高度-logo高度,这样的话,区域的最下面正好与背景图的底边重合,即logo图最终叠加在背景图的最左下角。结果如下图所示:
在这里插入图片描述
你只需要在主函数中读取两张图片,其中logo不要大于背景图就行了,不用管它的坐标,非常便利der嘻嘻!!!当然,为了使效果图像看起来更有融合性,可以使用线性混合相结合,即使用addWeighted()函数,具体就不多解释噜,篇幅有限嘻嘻!

全部代码如下所示,本人很大方的嘻嘻,不在乎那13积分惹!

#include<iostream>
#include<opencv2/core.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>
using namespace cv;
using namespace std;

//-------------自定义一个通用的叠加函数(叠加位置为左下角)----------
bool ROI_AddImage(Mat srcImage,Mat logoImage)//输入原图,logo图
{
	//设定ROI区域
	Mat imageROI = srcImage(Rect(0, srcImage.rows-logoImage.rows, logoImage.cols, logoImage.rows));//左上角纵坐标(原图高度-logo高度)
	//imshow("【ROI区域】", imageROI);

	/***************区域的线性混合******************/
	addWeighted(imageROI, 0.5, logoImage, 0.3, 0., imageROI);

	/***************ROI叠加算法********************/
	//加载掩膜(必须是灰度图)
	/*Mat mask;
	cvtColor(logoImage, mask, COLOR_RGB2GRAY);//用转换函数转换成灰度图
	//imshow("【掩膜图mask】", mask);
	//将掩膜复制到ROI
	logoImage.copyTo(imageROI, mask);
	imshow("【插入处掩膜化】", imageROI);*/
	//显示结果
	imshow("【叠加结果】", srcImage);
	return true;
}

void main()
{
	Mat image = imread("modao.bmp");
	Mat logo = imread("dnf_logo.jpg");
	//记录起始时间
	double time0 = static_cast<double>(getTickCount());
	if (ROI_AddImage(image, logo))
		cout << "运行成功,得出你所需的图像!" << endl;
	//计算运行时间并输出
	time0 = ((double)getTickCount() - time0) / getTickFrequency();
	cout << "此方法运行时间为:" << time0 << "秒" << endl;
	waitKey(0);
}

结果如下所示:
在这里插入图片描述

总结

emmm…其实没啥好总结的,其实也没多高级噜,只是发现了参数这个问题,顺便改进了一下下啦!其实还可以改的更好,比如有用户自己手动输入坐标,当然得设置一个相应的范围,这样可以实现自主选择想放置的位置。不过本博主flop,无人问津就不再折腾噜,欢迎大家再进一步改进,虽然照样可能NBCS嘻嘻!!!

发布了17 篇原创文章 · 获赞 3 · 访问量 1812

猜你喜欢

转载自blog.csdn.net/weixin_43350361/article/details/88226171