关于OpenCV图像操作的默认参数问题
本系列文章由 @yhl_leo 出品,转载请注明出处。
文章链接: http://blog.csdn.net/yhl_leo/article/details/51559490
在使用OpenCV以及其他开源库时,往往一个容易忽略的问题就是使用默认参数,尤其是图像处理,会导致内存中的图像数据变换后被不同程度上被修改!
下面给出几个示例,帮助理解。
1. warpAffine
warpAffine是图像仿射变换函数,函数定义为:
C++: void warpAffine(
InputArray src,
OutputArray dst,
InputArray M,
Size dsize,
int flags=INTER_LINEAR,
int borderMode=BORDER_CONSTANT,
const Scalar& borderValue=Scalar())
其中,
- M是一个2x3的转换矩阵,关于获取方法,可使用getRotationMatrix2D()函数:

flags是一个标识符,结合了内插方法(interpolation methods)和可选项WARP_INVERSE_MAPINTER_LINEAR- a bilinear interpolation (used by default) 双线性插值INTER_NEAREST- a nearest-neighbor interpolation 最邻近插值INTER_AREA- resampling using pixel area relation. It may be a preferred method for image decimation, as it gives moire’-free results. But when the image is zoomed, it is similar to the INTER_NEAREST method. 基于区域像素关系重采样INTER_CUBIC- a bicubic interpolation over 4x4 pixel neighborhood 4x4邻域双三次插值INTER_LANCZOS4- a Lanczos interpolation over 8x8 pixel neighborhood 8x8邻域兰索斯插值WARP_INVERSE_MAP- M is the inverse transformation (
) 等价于CV_WARP_INVERSE_MAPfills all of the destination image pixels M是
的逆变换
borderMode: pixel extrapolation method 像素外推方法BORDER_CONSTANT- pad the image with a constant value (used by default) 补上定值,如果使用则补上的定值设置为borderValue的值(默认为0)BORDER_TRANSPARENT- the corresponding pixels in the destination image will not be modified at all 不做任何修改BORDER_REPLICATE- the row or column at the very edge of the original is replicated to the extra border 将原始数据的行方向/列方向的边缘像素值作为外推边界
因为图像是离散的整数格网,一旦对像素值或者其下标进行浮点位运算,得到的结果都是近似值!几种内插方法各有优劣,双线性插值可以视为一个折中选择,即计算量不算很大(比基于区域和邻域块的方法小很多),效果也过得去(一般比最邻近插值更好),源码编写者大概是基于此考虑,将其设置为默认参数,但是针对某些具体的应用,绝不是最佳选择,例如对二值图像进行旋转,我们希望旋转后的图像仍然是二值的,那选择最临近插值可能就更合适。关于边界外推模式,这里贴上OpenCV官方文档:Adding borders to your images。
2. imread & imwrite
以前写过一篇博客,讲述了OpenCV图像读取与存储的一些细节:Opencv 图像读取与保存问题, 其中有一些非常容易忽视的细节,例如使用imread()读取图像时,参数flags的值默认是1,也就是说默认读取的是3通道彩色图像,如果待读取的图像是单通道或者4通道的,也会被转成3通道图像,这样读取的数据就不是你真正想要的。
另外,使用imwrite()存储图像时,params参数也至关重要,其中包括特定图像存储编码参数设置,如果调用时缺省,就会使用默认参数,例如存储JPEG图像,图像压缩质量默认设置为95(范围为0~100,数值越大质量越好),存储为PNG时,压缩级别默认为3(0~9 越大压缩越厉害)。
3. Demo
生成一个简单的单通道200x200的二值图像127,255,之所以不使用0, 255,是为了使有些参数的使用对结果的影响更加明显:
局部放大图:
以下面这段代码为例,首先使用
cv::Mat image = cv::imread("test1.png", IMREAD_UNCHANGED);
const int cols = image.cols;
const int rows = image.rows;
cv::Mat R = cv::getRotationMatrix2D(
cv::Point2f(
static_cast<float>(cols/2),
static_cast<float>(rows/2)),
30.0,
1.0);
cv::Mat r_image/*(rows,cols,CV_8UC1, cv::Scalar(0))*/;
cv::warpAffine(
image,
r_image,
R,
image.size(),
INTER_LINEAR,
BORDER_CONSTANT);
// std::vector<int> compress_param;
// compress_param.push_back(CV_IMWRITE_PNG_COMPRESSION);
// compress_param.push_back(0);
cv::imwrite("test1-r-l_c.png", r_image/*, compress_param*/);
warpAffine()和imwrite()函数都先使用默认参数,并且旋转后的矩阵r_image在声明的时候,不进行初始化,即图像旋转后插值方式为双线性插值,边缘外推方式为自动补为0:
让我们放大局部:
将warpAffine()函数中默认参数修改INTER_LINEAR -> INTER_NEAREST, BORDER_CONSTANT -> BORDER_TRANSPARENT ,即插值方法为最临近插值,边界不做任何调整(保持Mat的初始值,若未初始化,则会先进行初始化):
同样放大局部:
可以看出两者之间的明显区别,后者在边缘部分会保留原始数据的数据数值,但是为什么边界外推的像素颜色值是那样的,前面已经讲过:边界不做任何调整(保持Mat的初始值,若未初始化,则会先进行初始化),其中初始化值并不是0或者黑色。作为验证,我们在声明r_image的时候,对其进行初始化cv::Mat r_image(rows,cols,CV_8UC1, cv::Scalar(0));:
最后,再把图像存储压缩参数进行设置,即取消掉对compress_param的注释,虽然两个结果视觉上已经看不出差异,但是从文件大小上可以发现,压缩级为默认值(3)的图片大小为1.31KB,而压缩级为0的图片大小为39.3KB~真的差了很多,当然如果存储的JPG文件,分别使用下面的命令:
// 1
cv::imwrite("test1-r-n_t.jpg", r_image);
// 2
std::vector<int> compress_param;
compress_param.push_back(IMWRITE_JPEG_QUALITY);
compress_param.push_back(100);
cv::imwrite("test1-r-n_t-2.jpg", r_input, compress_param);
让我们对比局部放大图:
明显可以看出,使用默认参数保存时,图像质量已经出现只管的下降,可以想象,如果不停地循环读取和保存同一幅图像,那么图像的质量将会以0.95的n次幂的速度降低。
4. Summary
讲述了那么多,还是回归到主题,很多时候为了方便大家使用,开源库的一些函数都会提供默认参数,而缺省参数的设置主要是基于能够适用大多数用户的基本需求,但是并不一定是性能或效果最佳,为了获得更好的结果,必须了解传入函数的各个参数的意义,针对现实的需求选择适合自己的,不然你的成果很有可能就失败在这些细小的边边角角上。
关于OpenCV图像操作的默认参数问题的更多相关文章
- opencv图像操作
cvAbs 计算数组中所有元素的绝对值 cvAbsDiff 计算两个数组差值的绝对值 cvAbsDiffs 计算数组和标量差值的绝对值 cvAdd 两个数组的元素级的加运算 cvAdds 一个数组 ...
- python进阶—OpenCV之常用图像操作函数说明(转)
文章目录cv2.thresholdcv2.bitwise_andcv2.bitwise_orcv2.bitwise_notcv2.inRangecv2.resizecv2.adaptiveThresh ...
- 关于图像读取函数imread()的一点使用经验,注意默认参数的赋值
读入数字图像到数组,用CNN进行训练,发现关于图像读取的一个问题. 问题描述:读取灰度数字图像,在验证时发现存在错误,从图像到数组中的值不完全一样? main code as follows: int ...
- OpenCV图像金字塔:高斯金字塔、拉普拉斯金字塔与图片尺寸缩放
这篇已经写得很好,真心给作者点个赞.题目都是直接转过来的,直接去看吧. Reference Link : http://blog.csdn.net/poem_qianmo/article/detail ...
- OPENCV形态学操作1
形态学操作是指基于形状的一系列图像处理操作,包括膨胀,腐蚀,二值化,开运算,闭运算,顶帽算法,黑帽算法,形态学梯度等,最基本的形态学操作就是膨胀和腐蚀. 一.膨胀 首先需要明确一个概念,膨胀和腐蚀都是 ...
- Python用Pillow(PIL)进行简单的图像操作
Python用Pillow(PIL)进行简单的图像操作 颜色与RGBA值 计算机通常将图像表示为RGB值,或者再加上alpha值(通透度,透明度),称为RGBA值.在Pillow中,RGBA的值表示为 ...
- 学习 opencv---(12)OpenCV 图像金字塔:高斯金字塔,拉普拉斯金字塔与图片尺寸缩放
在这篇文章里,我们一起学习下 图像金字塔 的一些基本概念,如何使用OpenCV函数pyrUp和pyrDown 对图像进行向上和向下采样,以及了解专门用于缩放图像尺寸的resize函数的用法.此博文一共 ...
- opencv 矩阵操作
OpenCv矩阵操作 有很多函数有mask,代表掩码,如果某位mask是0,那么对应的src的那一位就不计算,mask要和矩阵/ROI/的大小相等 大多数函数支持ROI,如果图像ROI被设置,那么只处 ...
- Imagelab-0-QT label显示 opencv 图像
Imagelab-0-QT label显示 opencv 图像 opencvc++qtimagelab 开始之前 这其实也是opencv 处理图像的系列, 只是想我们在进一步复杂化我们的代码之前, 每 ...
随机推荐
- 洛谷[USACO06JAN]把牛Corral the Cows
题目描述 约翰打算建一个围栏来圈养他的奶牛.作为最挑剔的兽类,奶牛们要求这个围栏必须是正方 形的,而且围栏里至少要有C< 500)个草场,来供应她们的午餐. 约翰的土地上共有C<=N< ...
- SmartDispatcher 类
UI线程中使用 public class SmartDispatcher { public static void BeginInvoke(Action action) { if (Deploymen ...
- IDEA maven不能下载源码:" can not download source"问题
用IDEA无法下载源码,可以在命令行项目根目录下,执行如下命令 :mvn dependency:resolve -Dclassifier=sources下载 也可以在idea设置中设置为自动下载源码
- [Swift通天遁地]五、高级扩展-(14)扩展String快速计算字符串中的各种数学表达式
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...
- [转]Android ListView的Item高亮显示的办法
本文转自:http://www.cnblogs.com/dyllove98/archive/2013/07/31/3228601.html 在我们使用ListView的时候,经常会遇到某一项(Item ...
- JS——delete
1.对象属性删除 <script> function fun(){ this.name = 'mm'; } var obj = new fun(); console.log(obj.nam ...
- JS——arguments
1.只在函数中使用 2.返回的是实参的数组 <script> getNum(1, 2);//(2) [1, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ ...
- [Windows Server 2003] 服务器安全加固
★ 欢迎来到[护卫神·V课堂],网站地址:http://v.huweishen.com★ 护卫神·V课堂 是护卫神旗下专业提供服务器教学视频的网站,每周更新视频.★ 本节我们将带领大家:服务器安全加固 ...
- atom 插件安装【转载】
http://www.cnblogs.com/20145221GQ/p/5334762.html 问题: 输入apm install后,可能一直没有响应,要强行退. 不知道安装的时候可不可以打开ato ...
- 【sqli-labs】 less60 GET -Challenge -Double Query -5 queries allowed -Variation3 (GET型 挑战 双查询 只允许5次查询 变化3)
http://192.168.136.128/sqli-labs-master/Less-60/?id=1")%23 http://192.168.136.128/sqli-labs-mas ...
test1.png
test1-local
l_c
l_c-local
n_t
n_t-local
n_t-2
1
2