若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/105191466
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究
目录
OpenCV开发专栏
OpenCV开发笔记(三十六):红胖子8分钟带你深入了解缩放与图像金字塔(图文并茂+浅显易懂+程序源码)
前言
红胖子来也!!!
图像缩放使用cv::resize函数,与其类似的还有图像金字塔也可对图像进行缩放。
Demo
由Demo效果可以看出,resize能很大程度上保证质量,但是多次操作还是会有失真,不仅如此,在其他ide也会有这个现象。
技术点
在缩放图像里面,原始图像需要缓存一份,多次操作缩放最终是由原始图像乘以比例系数得到结果图像。
图像缩放
概述
图像缩放直接提供了函数,通过测试,其实际的缩放效果对原图像的保存是优于金字塔相关操作的,具体可以查看前面Demo运行效果的对比。
此处有一点要注意,使用resize进行图像缩放,线性差值方式是默认的方式,如果对图像进行放大,那么最好使用CV_INTER_AREA区域差值来做。
函数原型
void resize( InputArray src,
OutputArray dst,
Size dsize,
double fx = 0,
double fy = 0,
int interpolation = INTER_LINEAR );
- 参数一:InputArray类型的src,一般是cv::Mat;
- 参数二:OutputArray类型的dst;它具有大小dsize(当它为非零时)或从src.size()、fx和fy获得;dst的类型与src相同。即:当参数三传入空,则fx和fy为系数计算输出的图像尺寸;
- 参数三:Size类型的dsize,缩放后输出的图像尺寸;
- 参数四:double类型的fx,默认为0,为0时,参数三生效;
- 参数五:double类型的fx,默认为0,为0时,参数三生效;
- 参数六:缩放时,采用的实现方式;
图像金字塔
概述
图像金字塔是图像多尺度表达的一种,最主要用于图像的分割。
拉普拉斯金字塔是用来向上采样的(放大),原理如下图:
高斯金字塔是用来向下采样的(缩小),原理如下图:
向上采样(放大)函数原型
void pyrUp( InputArray src,
OutputArray dst,
const Size& dstsize = Size(),
int borderType = BORDER_DEFAULT );
- 参数一:InputArray类型的src,为cv::Mat;
- 参数二:OutPutArray类型的dst,为cv::Mat;
- 参数三:Size类型的dsize,缩放后输出的图像尺寸;
- 参数四:int类型的borderType,边界处理类型;
向下采样(缩小)函数原型
void pyrDown( InputArray src,
OutputArray dst,
const Size& dstsize = Size(),
int borderType = BORDER_DEFAULT );
- 参数一:InputArray类型的src,为cv::Mat;
- 参数二:OutPutArray类型的dst,为cv::Mat;
- 参数三:Size类型的dsize,缩放后输出的图像尺寸;
- 参数四:int类型的borderType,边界处理类型;
Demo源码
void OpenCVManager::testResizeAndPyrUpAndPyrDown()
{
QString fileName1 = "E:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/1.jpg";
cv::Mat srcMat = cv::imread(fileName1.toStdString());
#define FIRST_ZOOM_IN (1) // 先放大还是先缩小
#if !FIRST_ZOOM_IN
int width = 300;
int height = 200;
cv::resize(srcMat, srcMat, cv::Size(width, height));
cv::String windowName = _windowTitle.toStdString();
cvui::init(windowName);
cv::Mat windowMat = cv::Mat(cv::Size(srcMat.cols * 6, srcMat.rows * 4),
srcMat.type());
#else
int width = 300;
int height = 200;
cv::resize(srcMat, srcMat, cv::Size(width * 2, height * 2));
cv::String windowName = _windowTitle.toStdString();
cvui::init(windowName);
cv::Mat windowMat = cv::Mat(cv::Size(srcMat.cols * 3, srcMat.rows * 2),
srcMat.type());
#endif
while(true)
{
windowMat = cv::Scalar(0, 0, 0);
cv::Mat mat;
cv::Mat dstMat;
#if !FIRST_ZOOM_IN
// 原图先copy到左边
cv::Mat leftMat = windowMat(cv::Range(0, srcMat.rows),
cv::Range(0, srcMat.cols));
cv::addWeighted(leftMat, 0.0f, srcMat, 1.0f, 0.0f, leftMat);
cvui::printf(windowMat, srcMat.cols * 0, srcMat.rows * 1, "1 ->resize 2 -> resize 0.5 -> resize 2");
cvui::printf(windowMat, srcMat.cols * 0, srcMat.rows * 3, "1 ->pyrUp 2 -> pyrDown 0.5 -> pyrUp 2");
{
// 使用resize放大
cv::resize(srcMat, dstMat, cv::Size(), 2.0, 2.0);
// copy
mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 2),
cv::Range(srcMat.cols * 1, srcMat.cols * 3));
qDebug() << __FILE__<<__LINE__<<dstMat.cols << dstMat.rows << mat.cols << mat.rows;
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
// 使用resize缩小
cv::resize(dstMat, dstMat, cv::Size(), 0.5, 0.5);
// copy
mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1),
cv::Range(srcMat.cols * 3, srcMat.cols * 4));
qDebug() << __FILE__<<__LINE__<<dstMat.cols << dstMat.rows << mat.cols << mat.rows;
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
// 使用resize放大
cv::resize(dstMat, dstMat, cv::Size(), 2.0, 2.0);
// copy
mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 2),
cv::Range(srcMat.cols * 4, srcMat.cols * 6));
qDebug() << __FILE__<<__LINE__<<dstMat.cols << dstMat.rows << mat.cols << mat.rows;
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
}
{
// 使用pyrUp放大
cv::pyrUp(srcMat, dstMat);
// copy
mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 4),
cv::Range(srcMat.cols * 1, srcMat.cols * 3));
qDebug() << __FILE__<<__LINE__<<dstMat.cols << dstMat.rows << mat.cols << mat.rows;
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
// 使用pyrDown缩小
cv::pyrDown(dstMat, dstMat);
// copy
mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
cv::Range(srcMat.cols * 3, srcMat.cols * 4));
qDebug() << __FILE__<<__LINE__<<dstMat.cols << dstMat.rows << mat.cols << mat.rows;
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
// 使用pyrUp放大
cv::pyrUp(dstMat, dstMat);
// copy
mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 4),
cv::Range(srcMat.cols * 4, srcMat.cols * 6));
qDebug() << __FILE__<<__LINE__<<dstMat.cols << dstMat.rows << mat.cols << mat.rows;
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
}
#else
// 先恢复到600*400
// 原图先copy到左边
cv::Mat leftMat = windowMat(cv::Range(0, srcMat.rows),
cv::Range(0, srcMat.cols));
cv::addWeighted(leftMat, 0.0f, srcMat, 1.0f, 0.0f, leftMat);
cvui::printf(windowMat, srcMat.cols * 1, srcMat.rows * 0.5, "1 ->resize 0.5 -> resize 2 -> resize 0.5");
cvui::printf(windowMat, srcMat.cols * 1, srcMat.rows * 1.5, "1 ->pyrDown 0.5 -> pyrUp 2 -> pyrDown 0.5");
{
// 使用resize缩小
cv::resize(srcMat, dstMat, cv::Size(), 0.5, 0.5);
// copy
mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 0.5),
cv::Range(srcMat.cols * 1, srcMat.cols * 1.5));
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
// 使用resize放大
cv::resize(dstMat, dstMat, cv::Size(), 2.0, 2.0);
// copy
mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1),
cv::Range(srcMat.cols * 1.5, srcMat.cols * 2.5));
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
// 使用resize缩小
cv::resize(dstMat, dstMat, cv::Size(), 0.5, 0.5);
// copy
mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 0.5),
cv::Range(srcMat.cols * 2.5, srcMat.cols * 3));
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
}
{
// 使用pyrDown缩小
cv::pyrDown(srcMat, dstMat);
// copy
mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 1.5),
cv::Range(srcMat.cols * 1, srcMat.cols * 1.5));
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
// 使用pyrUp放大
cv::pyrUp(dstMat, dstMat);
// copy
mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
cv::Range(srcMat.cols * 1.5, srcMat.cols * 2.5));
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
// 使用pyrDown缩小
cv::pyrDown(dstMat, dstMat);
// copy
mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 1.5),
cv::Range(srcMat.cols * 2.5, srcMat.cols * 3));
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
}
#endif
// 更新
cvui::update();
// 显示
cv::imshow(windowName, windowMat);
// esc键退出
if(cv::waitKey(25) == 27)
{
break;
}
}
}
工程模板:对应版本号v1.31.0
对应版本号v1.31.0
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/105191466