若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/101351444
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究
红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中...(点击传送门)
上一篇:《OpenCV开发笔记(八):OpenCV常用操作之计时、缩放、旋转、镜像》
下一篇:《OpenCV开发笔记(十):OpenCV图像颜色通道分离和图像颜色多通道混合》
图像操作常常需要获取指定区域的图像,对于OpenCV提供了ROI(感兴趣区域)支持;
图像的叠加和混合也是常用的操作之一。
在图像处理领域中,专业名词感兴趣的区域其实就是选取指定区域的图像。
图像中提取感兴趣区域(Region of interest)有两种方法:
//创建宽度为 320,高度为 240 的 3 通道图像
Mat img(Size(320, 240), CV_8UC3);
//roi 是表示 img 中 Rect(10, 10, 100, 100)区域的对象
Mat roi(img, Rect(10, 10, 100, 100));
Mat roi2 = img(Rect(10, 10, 100, 100));
// 用括号运算符
Mat roi3 = img(Range(10, 100), Range(10, 100));
// 用构造函数
Mat roi4(img, Range(10, 100), Range(10, 100));
cv::Mat srcMat;
QString fileName = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/1.jpg";
srcMat = cv::imread(fileName.toStdString());
if(!srcMat.data)
{
qDebug() << __FILE__ << __LINE__ << "Failed to load image:" << fileName;
return;
}
cv::imshow("orgin mat", srcMat);
cv::Mat roiMat = srcMat(cv::Range(srcMat.rows/2 - 50, srcMat.rows/2 + 50),
cv::Range(srcMat.cols/2 - 30, srcMat.cols/2 + 30));
cv::imshow("roi mat", roiMat);
cv::waitKey(0);
图像混合有多种方式。
线性混合操作是一种典型的二元(两个输入)的像素操作,它的理论公式如下:
G(x) = (1-a)F1(x) + aF2(x)
a代表透明度的值(0.0~1.0)对两幅图像(F1和F2)活两段视频产生时间上的画面叠化效果,前面页面切换至后面页面的一个切换过程。
线性混合过程主要使用addWeighted函数。
这个函数的作用是计算两个mat的加权和,当然读者可以自己遍历像素计算。该函数的原型如下:
CV_EXPORTS_W void addWeighted(InputArray src1,
double alpha,
InputArray src2,
double beta,
double gamma,
OutputArray dst,
int dtype = -1);
以上函数的计算公式如下:
dst = src1[I] * alpha + src2[I] * beta + gamma;
其中I为元素位置的索引值,当遇到多通道mat的时候,每个通道都需要独立的进行处理。
注意:当输出mat的深度为CV_32S时,这个函数不使用,会导致内存溢出或者算出的结果错误。
// 测试线性混合: 正向 与 x轴翻转后的线性混合
cv::Mat mat1;
cv::Mat mat2;
cv::Mat mat3;
QString fileName1 = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/1.jpg";
QString fileName2 = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/1.bmp";
mat1 = cv::imread(fileName1.toStdString());
mat2 = cv::imread(fileName2.toStdString());
if(!mat1.data || !mat2.data)
{
qDebug() << __FILE__ << __LINE__
<< "Failed to load image:" << fileName1 << "or" << fileName2;
return;
}
// 对mat2进行缩放,缩放至mat1的大小,否则会报错
cv::resize(mat2, mat2, cv::Size(mat1.cols, mat1.rows));
// 然后进行混合
double a = 0.0;
while(true)
{
cv::addWeighted(mat1, a, mat2, (1.0-a), 0.0, mat3);
cv::imshow("mat3", mat3);
int key = cv::waitKey(0);
if(key == 27)
{
break;
}else if(key == '1')
{
a += 0.05;
if(a >= 1.0)
{
a = 1.0;
}
}else if(key == '2')
{
a -= 0.05;
if(a < 0.0)
{
a = 0.0;
}
}
}
原理和方法参照图像混合(整体混合)。
局部混合可以理解对感兴趣的区域进行混合,这里特别要注意一下:
// 测试线性混合: 正向 与 x轴翻转后的线性混合
cv::Mat mat1;
cv::Mat mat2;
cv::Mat mat3;
QString fileName1 = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/1.jpg";
QString fileName2 = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/1.bmp";
mat1 = cv::imread(fileName1.toStdString());
mat2 = cv::imread(fileName2.toStdString());
if(!mat1.data || !mat2.data)
{
qDebug() << __FILE__ << __LINE__
<< "Failed to load image:" << fileName1 << "or" << fileName2;
return;
}
// 对mat2进行缩放,缩放至mat1的1/4的大小
cv::resize(mat2, mat2, cv::Size(mat1.cols/2, mat1.rows/2));
double a = 0.0;
while(true)
{
// mat4只是mat1的副本
// cv::Mat mat4 = mat1;
cv::Mat mat4 = mat1.clone();
qDebug() << __FILE__ << __LINE__
<< mat1.cols/2 - mat1.cols/4
<< mat1.cols/2 + mat1.cols/4
<< mat1.rows/2 - mat1.rows/4
<< mat1.rows/2 + mat1.rows/4;
cv::Mat mat5 = mat4(cv::Range(mat1.rows/2 - mat1.rows/4, mat1.rows/2 + mat1.rows/4),
cv::Range(mat1.cols/2 - mat1.cols/4, mat1.cols/2 + mat1.cols/4));
qDebug() <<__FILE__<<__LINE__;
cv::addWeighted(mat5, a, mat2, (1.0-a), 0.0, mat5);
qDebug() <<__FILE__<<__LINE__;
cv::imshow("mat4", mat4);
int key = cv::waitKey(0);
if(key == 27)
{
break;
}else if(key == '1')
{
a += 0.05;
if(a >= 1.0)
{
a = 1.0;
}
}else if(key == '2')
{
a -= 0.05;
if(a < 0.0)
{
a = 0.0;
}
}
}
void OpenCVManager::testROIAndBlend()
{
#define TEST_ROI (0) // roi
#define TEST_BLEND (0) // 图像加权混合(全部区域)
#define TEST_BLEND_ROI (1) // 图像加权混合(roi区域)
#if TEST_ROI
// 测试提取
cv::Mat srcMat;
QString fileName = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/1.jpg";
srcMat = cv::imread(fileName.toStdString());
if(!srcMat.data)
{
qDebug() << __FILE__ << __LINE__ << "Failed to load image:" << fileName;
return;
}
cv::imshow("orgin mat", srcMat);
cv::Mat roiMat = srcMat(cv::Range(srcMat.rows/2 - 50, srcMat.rows/2 + 50),
cv::Range(srcMat.cols/2 - 30, srcMat.cols/2 + 30));
cv::imshow("roi mat", roiMat);
cv::waitKey(0);
#endif
#if TEST_BLEND
// 测试线性混合: 正向 与 x轴翻转后的线性混合
cv::Mat mat1;
cv::Mat mat2;
cv::Mat mat3;
QString fileName1 = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/1.jpg";
QString fileName2 = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/1.bmp";
mat1 = cv::imread(fileName1.toStdString());
mat2 = cv::imread(fileName2.toStdString());
if(!mat1.data || !mat2.data)
{
qDebug() << __FILE__ << __LINE__
<< "Failed to load image:" << fileName1 << "or" << fileName2;
return;
}
// 对mat2进行缩放,缩放至mat1的大小,否则会报错
cv::resize(mat2, mat2, cv::Size(mat1.cols, mat1.rows));
// 然后进行混合
double a = 0.0;
while(true)
{
cv::addWeighted(mat1, a, mat2, (1.0-a), 0.0, mat3);
cv::imshow("mat3", mat3);
int key = cv::waitKey(0);
if(key == 27)
{
break;
}else if(key == '1')
{
a += 0.05;
if(a >= 1.0)
{
a = 1.0;
}
}else if(key == '2')
{
a -= 0.05;
if(a < 0.0)
{
a = 0.0;
}
}
}
#endif
#if TEST_BLEND_ROI
// 测试线性混合: 正向 与 x轴翻转后的线性混合
cv::Mat mat1;
cv::Mat mat2;
cv::Mat mat3;
QString fileName1 = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/1.jpg";
QString fileName2 = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/1.bmp";
mat1 = cv::imread(fileName1.toStdString());
mat2 = cv::imread(fileName2.toStdString());
if(!mat1.data || !mat2.data)
{
qDebug() << __FILE__ << __LINE__
<< "Failed to load image:" << fileName1 << "or" << fileName2;
return;
}
// 对mat2进行缩放,缩放至mat1的1/4的大小
cv::resize(mat2, mat2, cv::Size(mat1.cols/2, mat1.rows/2));
double a = 0.0;
while(true)
{
// mat4只是mat1的副本
// cv::Mat mat4 = mat1;
cv::Mat mat4 = mat1.clone();
qDebug() << __FILE__ << __LINE__
<< mat1.cols/2 - mat1.cols/4
<< mat1.cols/2 + mat1.cols/4
<< mat1.rows/2 - mat1.rows/4
<< mat1.rows/2 + mat1.rows/4;
cv::Mat mat5 = mat4(cv::Range(mat1.rows/2 - mat1.rows/4, mat1.rows/2 + mat1.rows/4),
cv::Range(mat1.cols/2 - mat1.cols/4, mat1.cols/2 + mat1.cols/4));
qDebug() <<__FILE__<<__LINE__;
cv::addWeighted(mat5, a, mat2, (1.0-a), 0.0, mat5);
qDebug() <<__FILE__<<__LINE__;
cv::imshow("mat4", mat4);
int key = cv::waitKey(0);
if(key == 27)
{
break;
}else if(key == '1')
{
a += 0.05;
if(a >= 1.0)
{
a = 1.0;
}
}else if(key == '2')
{
a -= 0.05;
if(a < 0.0)
{
a = 0.0;
}
}
}
#endif
}
对应版本号v1.6.0
上一篇:《OpenCV开发笔记(八):OpenCV常用操作之计时、缩放、旋转、镜像》
下一篇:《OpenCV开发笔记(十):OpenCV图像颜色通道分离和图像颜色多通道混合》
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/101351444