我的网站

耀世注册

联系我们

地址:海南省海口市

邮编:570521

电话:0898-08980898

传真:0898-1230-5678

公司动态

当前位置: 首页 > 耀世资讯 > 公司动态

OpenCV常见的优化方法和技巧总结

添加时间:2024-07-08 14:17:48

? ? 【尊重原创,转载请注明出处】http://blog.csdn.net/guyuealian/article/details/78540206


目录

OpenCV常见的优化方法和技巧总结

?一、OpenCV常见的优化方法总结

1.1 cv::imread()设置reduce模式:

1.2 查表法:LUT,

1.3 像素遍历

1.4 openCL加速:使用UMat结构代替Mat

1.5 release内存释放

1.6 多线程加速处理OpenMP

1.7 使用积分图:integral

二、OpenCV常用技巧总结

释放Mat图像内存空间:

Mat多通道合并和分割

释放图像通道分割的图像空间

计算运行时间

关于vector内存释放的问题:

OpenCV LUT:

opencv多通道的使用?

opencv中Mat与数组之间值传递的快速方法

图像的遍历的快速方法

图像遍历优化和加速的常用方法:

防止图像Rect区域越界的好方法

获取OpenCV版本

读写XML或者yml文件数据的

Mat矩阵的运算,易错的问题

Mat和IplImage相互转换

Mat::data指针讲解

OpenCV Mat数据类型及位数总结

Mat矩阵插入新的矩阵

颜色空间缩减的方法

YUV444,YUV422,YUV420解释


? cv::imread()设置reduce模式,?读取缩放的低分辨率小图,或者直接读取灰度图,可以做到自适应,先用EXIF信息读取图像的分辨率,当分辨率大于一定阈值,则设置读取模式为:IMREAD_REDUCED_COLOR_2或者IMREAD_REDUCED_COLOR_4 ,避免内存过大以及编程resieze耗时

? ? 使用lut的方法法,远快于每个像素都计算的方法

? ? openCV像素遍历常用的是三种方法:ptr指针,迭代器(iterator)以及动态地址at

? ? 实现方式:?https://blog.csdn.net/keith_bb/article/details/53071133

? ? 使用Mat的ptr指针进行图像遍历更加高效,

特别的:一般图像行与行之间往往存储是不连续的,但是有些图像可以是连续的,Mat提供了一个检测图像是否连续的函数isContinuous()。当图像连通时,我们就可以把图像完全展开,看成是一行进行处理。

动态地址at不适合用于像素遍历,速度太慢了,比较适合随机访问的方式

? ? 高性能:OpenCL的相关用法:UMat

? ? 在OpenCV3中,OCL module已经被舍弃。而是使用更易上手的Transparent API来替代 OCL module。因此只需要使用 UMat来替换Mat,而其余的代码保持不变,即可实现加速.

? ? Mat转换成UMat可以使用Mat::copyTo(OutputArray dst),也可以使用Mat::getUMat(int access_flags)

 

image size:[2000,3008]
CPU:18.039ms
GPU:9.623ms?

? ? 说明:图像越大,计算越复杂时,使用OpenCL加速的效果更明显,如果使用分辨率小图,其GPU的计算速度未必比CPU的快!!?

? ?参考资料:?https://blog.csdn.net/amusi1994/article/details/79529870

《OpenCV3.x中UMat对象介绍与使用》https://blog.csdn.net/jia20003/article/details/69802932

?

举个例子:并行化for语句

 

第一句中[]的部分是可选的,由自己的程序并行特点而定。大家先不要把精力放到这里面。后面的文章中会继续讲解的。

编写规则
1、index的值必须是整数,一个简单的for形式:for(int i = start; i < end; i++){…} 。

2、start和end可以是任意的数值表达式,但是它在并行化的执行过程中值不能改变,也就是说在for并行化执行之前,编译器必须事先知道你的程序执行多少次,因为编译器要把这些计算分配到不同的线程中执行。

3、循环语句只能是单入口但出口的。这里只要你避免使用跳转语句就行了。具体说就是不能使用goto、break、return。但是可以使用continue,因为它并不会减少循环次数。另外exit语句也是可以用的,因为它的能力太大,他一来,程序就结束了。

openMP参考资料:

https://www.cnblogs.com/ospider/p/5265975.html?

《openMP编程探索1——编程基础》https://blog.csdn.net/bendanban/article/details/6302857?

《openMP编程探索2——循环并行化》:https://blog.csdn.net/bendanban/article/details/6303100

? 积分图定义为:积分图中坐P(x,y)的值为其左上角的所有像素之和

如上图所示,为了求该矩形区域的灰度之和。我们可以用以下公式表示:?
S=S(A)+S(D)-S(B)-S(C)
需要注意的是,这里的总和并不包含点A,B,C的像素值。如上图所示的小像素点,A,B,C所在的像素点不在矩形区域以内。

另外,有的时候不一定只是像素灰度值和,只要符合积分图这一种计算思想的,均可以用积分图来简化计算。?
如果是求矩形区域的像素点平方和,也可以用

 

 

 

 

?

 

?

? ? 由于vector的内存占用空间只增不减,比如你首先分配了10,000个字节,然后erase掉后面9,999个,留下一个有效元素,但是内存占用仍为10,000个。所有内存空间是在vector析构时候才能被系统回收。empty()用来检测容器是否为空的,clear()可以清空所有元素。但是即使clear(),vector所占用的内存空间依然如故,无法保证内存的回收。

? ? 如果需要空间动态缩小,可以考虑使用deque。如果是vector类型,可以考虑用swap()来帮助你释放内存。具体方法如下:
标准模板:

 

?swap()是交换函数,使vector离开其自身的作用域,从而强制释放vector所占的内存空间,总而言之,释放vector内存最简单的方法是vector<Point>().swap(pointVec)。当时如果pointVec是一个类的成员,不能把vector<Point>().swap(pointVec)写进类的析构函数中,否则会导致double free or corruption (fasttop)的错误,原因可能是重复释放内存。(前面的pointVec.swap(vector<Point> ())用G++编译没有通过)
?如果vector中存放的是指针,那么当vector销毁时,这些指针指向的对象不会被销毁,那么内存就不会被释放。如下面这种情况,vector中的元素时由new操作动态申请出来的对象指针:

 

? ? 每次new之后调用v.push_back()该指针,在程序退出或者根据需要,用以下代码进行内存的释放:

 

? ?多用LUT可以大大降低处理时间:比如下面是实现图像Gamma矫正的函数,其中使用了LUT,这比使用for循环遍历每个像素值,快很多,特别是图片很大的时候:

 

 

? ? ? ?利用Mat来存储数据,避免使用数组等操作

 

? ? ? ?将数组内容传递给Mat,示例代码:

 

? ? ? ?将Mat中的内容传递给数组,如果Mat中的数据是连续的,那么对于传递到一维vector我们可以这样:

 

? ? ? ?同样的,传递到一维数组我们可以这样

 

? ? ? ? 对于二维vector的传值,我们可以这样处理

 

? ? ? OpenCV图像遍历最高效的方法是指针遍历方法。因为图像在OpenCV里的存储机制问题,行与行之间可能有空白单元(一般是补够4的倍数或8的倍数,有些地方也称作“位对齐”,目前我用到的FreeImage和c#中的bitmap中的存储机制也是这样的)。这些空白单元对图像来说是没有意思的,只是为了在某些架构上能够更有效率,比如intel MMX可以更有效的处理那种个数是4或8倍数的行。Mat提供了一个检测图像是否连续的函数isContinuous()。当图像连通时,我们就可以把图像完全展开,看成是一行。因此最高效的遍历方法如下:

 

? ? ?PS:一般经过裁剪的Mat图像,都不再连续了,如cv::Mat crop_img = src(rect);crop_img 是不连续的Mat图像,如果想转为连续的,最简单的方法,就是将不连续的crop_img?重新clone()一份给新的Mat就是连续的了。关于Mat连续存储的问题,可见:http://blog.csdn.net/guyuealian/article/details/78614662


1、加减法比乘除法快,因此应避免使用乘除法

2、不能避免乘除法时,考虑使用“移位运算”

3、像素查表法LUT,远快于每个像素都计算的方法

4、使用常量,会比使用变量快:如:

 
 

? ?PS:特别是在for循环中,能用常量表示的,就不要用变量表示,所以“多使用宏定义define,准没错

?实例代码:第四种的fast_ergodic4遍历方法是最快的

 

?


? ? ?OpenCV的cv::Rect提供了很多实用的方法,可参考:http://blog.csdn.net/da_yuan8421/article/details/60959419:

? ? ?在对图像进行处理时,经常需要截取图像中的某一区域进行处理,如果截取的区域越界时,就容易导致图像崩溃。

 

? ?利用两个Rect的交集,我们可以很轻松的避免图像裁剪区域越界的情况,如下:

 

? ? 上例子,原图src的大小=200*200,需要裁剪为rect=[-10,-10,10000,20000],为了避免裁剪Rect越界,需要特殊的保护,最简单的方法就是,加入这句话:rect &= Rect(0, 0, src.cols, src.rows),这个交集的Rect肯定是不会越界。


 

? ?read.xml文本内容:

 

OpenCV读写方法:

 

? ? ?保存Vector数据的方法

 

若不未知结点名称,可以直接遍历文件的结点,访问元素,如:

 

? ? ? ?注意Mat矩阵可以进行加减乘除的基本运算,但一个int型的常数和一个Scalar类型的常数进行运算是有区别的,以“+”为例子(也可以用cv::add()代替)

 

? ? ?Mat 是OpenCV和C++的接口矩阵类,ImlImage是OpenCV和C语言的接口的结构体,但是C++程序有时候时候还是要用到ImlImage,例如在MFC中的Picture Control显示图片。Mat和IplImage相互转换方法:

 

? ? ? ?https://blog.csdn.net/lijiayu2015/article/details/52438160


? ? ? ?http://lib.csdn.net/article/opencv/24030


 

float:4字节,6-7位有效数字 -3.4E-38 到 3.4E38
double: 8字节,15~16位有效数字 -1.7E-308 到 1.7E308

在OpenCV里面,许多数据结构为了达到內存使用的最优化,通常都会用它最小上限的空间来分配变量,有的数据结构也会因为图像文件格式的关系而给予适当的变量,因此需要知道它们声明的空间大小来配置适当的变量。一 般标准的图片,为RGB格式它们的大小为8bits格式,范围为0~255,对一个int空间的类型来说实在是太小,整整浪费了24bits的空间,假设有个640*480的BMP文件空间存储內存,那整整浪费了640*480*3*(32-8)bits的內存空间,总共浪费了2.6MB!,也就是那 2.6MB内什么东西都没存储,如果今天以8bits的格式来存储则只使用到0.6MB的內存而已(640*480*3*(8)+54 bits),因此,对于文件格式的对应是一件很重要的事。
在这边除了要考虑bits的空间大小外,还要考虑使用类型的正负号的问题,一般的图像文件是不存在负号的,如果今天即使选则正确的空间大小,可是出现的结果却是负的,那就功亏一篑了。这里除了Float及double类型,char,int,short int都是用二的补数表示法,它们不具正负号bit,而Float,double则是用IEEE 754,在第32bit,64bit上有一个正负号bit.

cvCreateImage()及cvCreateMat()对应

1.Unsigned 8bits(一般的图像文件格式使用的大小)
IplImage数据结构参数:IPL_DEPTH_8U
CvMat数据结构参数:CV_8UC1,CV_8UC2,CV_8UC3,CV_8UC4

变量类型空间大小范围其他
uchar8bits0~255(OpenCV缺省变量,同等unsigned char)
unsigned char8bits0~255?

?

2.Signed 8bits
IplImage数据结构参数:IPL_DEPTH_8S
CvMat数据结构参数:CV_8SC1,CV_8SC2,CV_8SC3,CV_8SC4

?

变量类型空间大小范围其他
char8bits-128~127?

?

3.Unsigned 16bits
IplImage数据结构参数:IPL_DEPTH_16U
CvMat数据结构参数:CV_16UC1,CV_16UC2,CV_16UC3,CV_16UC4
?

变量类型空间大小范围其他
ushort16bits0~65535(OpenCV缺省变量,同等unsigned short int)
unsigned short int16bits0~65535(unsigned short)

?

4.Signed 16bits
IplImage数据结构参数:IPL_DEPTH_16S
CvMat数据结构参数:CV_16SC1,CV_16SC2,CV_16SC3,CV_16SC4
?

变量类型空间大小范围其他
short int16bits-32768~32767(short)

?

5.Signed 32bits
IplImage数据结构参数:IPL_DEPTH_32S
CvMat数据结构参数:CV_32SC1,CV_32SC2,CV_32SC3,CV_32SC4
?

变量类型空间大小范围其他
int32bits-2147483648~2147483647(long)

?

6.Float 32bits

IplImage数据结构参数:IPL_DEPTH_32F
CvMat数据结构参数:CV_32FC1,CV_32FC2,CV_32FC3,CV_32FC4
?

变量类型空间大小范围其他
float32bits1.18*10-38~3.40*1038?

?

7.Double 64bits

CvMat数据结构参数:CV_64FC1,CV_64FC2,CV_64FC3,CV_64FC4
?

变量类型空间大小范围其他
double64bits2.23*10-308~1.79*10308?

?

8.Unsigned 1bit

IplImage数据结构参数:IPL_DEPTH_1U

变量类型空间大小范围其他
bool1bit0~1?

?

其他变量对应

1.Signed 64bits

int64

long long

2.Unsigned 64 bits

uint64

unsigned long long


 

 

https://blog.csdn.net/mandagod/article/details/78605586

? ? ?通常我们用RGB表示一种彩色。计算机系统里的LCD显示的数据就是RGB来表示每个像素的颜色。
而在我们生活里,有黑白电视机与彩色电视机两种,拍摄节目源时不可以用两种不同的摄像机来存放两种图像数据。
所以为了兼容两种电视机,专家就引入YUV格式代替RGB,其中Y表示亮度, U和V表示色差。 黑白电视机只用Y信号, 而彩色电视机可由YUV转换成RGB再显示颜色。

? ? ?通常我们所用的YUV格式是 ITU-R 的标准 , 也叫YCbCr。YUV是由RGB格式的数据转换得来。

 

YUV4:4:4?
? ? ?其实就是YUV的数据各占用8位, 每个像素都由YUV组成

YUV4:2:2
? ? ?其实绝大部分相邻的两个像素,数据差异应不大。所以为了节点空间便于存储,丢失每个像素的部分数据。
? ? ?专家研究表明我们人对亮度比较敏感,而对色彩不怎么敏感。所以每个像素的亮度Y数据是绝对不动的,而色差数据可以进行丢弃。

YUV4:2:0
? ? ?专家们进一步研究表示,每一行的相邻两个像素与下一行同位置的两个像素数据差异不大,可以进一步的丢数据。

  1. ?
  2. ?

? ? ?yuv数据还分成打包的,平面的。
? ? ?打包的意思是: yuv数据是顺序存放Y,接着U,再接着V数据存放。
? ? ?平面的意思是: yuv数据是分成三个地方存放, 一个地方只存Y数据, 一个只存U数据, 一个只存V数据

地址:海南省海口市电话:0898-08980898传真:0898-1230-5678

Copyright © 2012-2018 耀世娱乐-耀世注册登录入口 版权所有ICP备案编号:琼ICP备xxxxxxxx号

平台注册入口