https://blog.csdn.net/u013139259/article/details/52145377

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013139259/article/details/52145377
问题介绍
理论介绍
代码介绍
优化方式与实验结果
问题介绍

图像处理中改变亮度和对比度是很基础的需求,算法也相对简单。博主的工作是要模拟待处理视频的不同光照下的效果。博主想到的方式就是
利用Opencv读取视频的每一帧,然后进行处理成不同亮度和对比度的图像,然后在写进去。

理论介绍

Opencv提供了强大的图像处理算法接口,关于改变图像的亮度和对比度,也提供了官方的教程。链接如下。

官方介绍

一般这类工作叫做图像处理算子,或者图像变换,图像变换分为两种。

点算子(像素变换)
领域算子(基于区域的)
其中改变图像的亮度和对比度是通过像素交换实现的,属于点算子。
至于,怎么改变原图的单个像素点。公式如下。

代码介绍

cv::Mat new_Mat = cv::Mat::zeros( from_mat.size(), from_mat.type());
for( int y = 0; y < from_mat.rows; y++)
{
for( int x = 0; x < from_mat.cols; x++ )
{
for(int c = 0; c < 3; c++)
{
new_Mat.at<cv::Vec3b>(y , x)[c] = cv::saturate_cast<uchar>(ip.alpha*(from_mat.at<cv::Vec3b>(y , x)[c]) + ip.beta);
}
}
}
return new_Mat ;
1
2
3
4
5
6
7
8
9
10
11
12
注意1:为了访问图像的每一个像素,我们使用这一语法: new_Mat.at(y,x)[c] 其中, y 是像素所在的行, x 是像素所在的列, c 是R、G、B(0、1、2)之一。
因为 运算结果可能超出像素取值范围,还可能是非整数(如果 alpha 是浮点数的话),所以我们要用 saturate_cast 对结果进行转换,以确保它为有效值。
优化方式与实验结果

通过以上的方式,在进行对每一帧的视频处理的时间(视频帧的大小是1920x1080),大概是3s左右,很明显,这太慢了。所以,实验了几个其他的方式,来进行算法优化。算法的优化思路如下。

原算法慢很明显是因为循环次数过大,因为有3层循环。所以,通过改变mat帧数据的遍历方式,逐渐减少循环层数。

优化方式一

对于一个像素点,它的RGB的数据存储是连续的,所以,有以下公式。

每一行的数据点(uchar数据) = 每一行的像素点 X 通道数。

而且,mat的帧使用指针的方式进行遍历。

代码如下。

cv::Mat new_Mat = cv::Mat::zeros( from_mat.size(), from_mat.type());

int nl = from_mat.rows ;
int nc = from_mat.cols*from_mat.channels();

/*传入参数行数nl*/

for(int j= 0 ; j < nl ; j++)
{
uchar * data = from_mat.ptr<uchar>(j);

uchar * output = new_Mat.ptr<uchar>(j);

for(int i = 0 ; i < nc ; i++)
{
output[i] = cv::saturate_cast<uchar>(data[i] + ip.beta);
}

}

return new_Mat;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
算法名称 一帧图像处理时间
算法优化第一步 0.148778s
优化方式二
每一行的数据都是连续存储的,但是不同行之间就不一定了。以为有时处于效率的原因,每行都会填补一些额外的像素。主要是当行的长度是4或者8的倍数,一些多媒体处理芯片可以更高效地处理像素,这些额外的像素不会被显示或者保存,填补的值会被忽略。 Opencv提供了接口(isContinuous)判断是否图像进行了内存填补。如果函数返回为true的话,那么代表图像没有进行填补,因此我们可以通过利用存储的连续性,在一个循环中进行mat数据遍历。

int nl = from_mat.rows ;
int nc = from_mat.cols*from_mat.channels();

if(from_mat.isContinuous())
{
nc = nc*nl;
nl = 1 ;

uchar * data = from_mat.ptr<uchar>(0);
for(int i = 0 ; i < nc ; i++)
{

data[i] = cv::saturate_cast<uchar>(data[i] + ip.beta);
}

}

return from_mat;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
算法名称 一帧图像处理时间
算法优化第二步 0.149215s
从时间上来说,这种方式并没有加速,所以,相对第一种方式,真正能做到优化的原因,可能是和改成指针遍历有关。

优化方式三
从代码中可以看出主要的耗时操作是二维的加法运算。那么因此我们可以通过利用多核CPU来进行并行加速。本文利用的并行加速的第三方库,是TBB。关于TBB和使用方式,本文不做介绍。主要是使用了其中的
parallel_for函数。

int nl = from_mat.rows ;
int nc = from_mat.cols*from_mat.channels();

if(from_mat.isContinuous())
{
nc = nc*nl;
nl = 1 ;

uchar * data = from_mat.ptr<uchar>(0);
parallel_for(blocked_range<size_t>(0 , nc) , AddClass(data , ip.beta));

}

return from_mat;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
算法名称 一帧图像处理时间
算法优化第三步 0.074073s
利用TBB进行并行加速第二种方式,时间又缩小了一般,可见并发处理的有效性。当然,TBB的学习资料并不是很多,这个也不是很容易使用的。
还有就是TBB并不定对所有算法加速,也是和程序,运行环境相关的,使用不当会适得其反。

直接调用Opencv库函数

Opencv提供了convertTo() 可以进行相同的操作。

cv::Mat new_Mat =cv::Mat::zeros( from_mat.size(), from_mat.type());
from_mat.convertTo(new_Mat , -1 , ip.alpha , ip.beta);
return new_Mat ;
1
2
3
算法名称 一帧图像处理时间
算法优化第四步 0.015003s
处理一帧又快了3倍。本人不知道Opencv该函数的实现,所以并不能解释为什么这么快。但是你可以去下载Opencv的源码,查看该方法的具体实现方式。

总结

Opencv也集成了TBB和cuda,但是默认的并没有编译到源码中,要利用TBB或者cuda加速的方式,可以通过cmake进行重新编译其中,当然,利用TBB并发或者cuda利用GPU加速并不定能理想,具体问题具体分析。而且,利用cuda,需要有NVIDIA的显卡硬件支持的。
---------------------
作者:张骞晖2
来源:CSDN
原文:https://blog.csdn.net/u013139259/article/details/52145377
版权声明:本文为博主原创文章,转载请附上博文链接!

Opencv改变图像亮度和对比度以及优化的更多相关文章

  1. opencv::调整图像亮度与对比度

    图像变换可以看作如下: - 像素变换 – 点操作 - 邻域操作 – 区域 调整图像亮度和对比度属于像素变换-点操作 //创建一张跟原图像大小和类型一致的空白图像.像素值初始化为0 Mat new_im ...

  2. OpenCV 改变图像的对比度和亮度

    #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <ios ...

  3. 跟我一起学opencv 第五课之调整图像亮度和对比度

    一.调整图像亮度与对比度 1.图像变换 ---像素变换-点操作 ---邻域操作-区域操作 调整图像亮度和对比度属于像素变换-点操作 公式为:g(i,j) = αf(i,j) + β 其中α>0 ...

  4. OpenCV学习:改变图像的对比度和亮度

    本实例演示简单地改变图像的对比度和亮度,使用了如下线性变换来实现像素值的遍历操作: The parameters α > 0 and β often called the gain and bi ...

  5. openCV - 5~7 图像混合、调整图像亮度与对比度、绘制形状与文字

    5. 图像混合 理论-线性混合操作.相关API(addWeighted) 理论-线性混合操作 用到的公式 (其中 α 的取值范围为0~1之间) 相关API(addWeighted) 参数1:输入图像M ...

  6. OpenCV中的SVM參数优化

    SVM(支持向量机)是机器学习算法里用得最多的一种算法.SVM最经常使用的是用于分类,只是SVM也能够用于回归,我的实验中就是用SVM来实现SVR(支持向量回归). 对于功能这么强的算法,opencv ...

  7. OpenCV --- 修改图像的对比度、亮度 、RGB转Gray图像、修改图像的尺寸

    #include <opencv2/core.hpp> #include <opencv2/imgcodecs.hpp> #include <opencv2/highgu ...

  8. opencv调整图像亮度对比度

    图像处理 图像变换就是找到一个函数,把原始图像矩阵经过函数处理后,转换为目标图像矩阵. 可以分为两种方式,即像素级别的变换和区域级别的变换 Point operators (pixel transfo ...

  9. [OpenCV] 图像亮度和对比度调整

    对比度调整的原理参考这篇博客 以下是代码实现: #include <iostream> #include "opencv2/core.hpp" #include &qu ...

随机推荐

  1. [django]drf知识点梳理-权限

    用户 - 权限 - 资源 (拥有) (绑定) django权限机制能够约束用户行为,控制页面的显示内容,也能使API更加安全和灵活:用好权限机制,能让系统更加强大和健壮 django权限控制 Djan ...

  2. Linux 环境配置 网络端口进程命令

    网络通信命令ping 命令路径:/bin/ping 执行权限:所有用户作用:测试网络的连通性语法:ping 选项 IP地址  -c 指定发送次数    ping 命令使用的是icmp协议,不占用端口e ...

  3. 16-Python3 条件控制

    2018-11-20 11:41:15 print('狗狗的年龄兑换*********************************************************') age = ...

  4. centos7安装Amber16 && AmberTools

    Centos7 安装amber16 1.准备下载好的amber(Amber16.tar.bz2)及tools(AmberTools16.tar.bz2)安装包: $ cd MySoftware_hom ...

  5. MySQL报错

    1,使用mysqldump导出数据报错: mysqldump: Error 2020: Got packet bigger than 'max_allowed_packet' bytes when d ...

  6. JS引擎的执行机制

    深入理解JS引擎的执行机制 1.灵魂三问 : JS为什么是单线程的? 为什么需要异步? 单线程又是如何实现异步的呢? 2.JS中的event loop(1) 3.JS中的event loop(2) 4 ...

  7. JavaScript原型规则和实例

    var arr = [] // var arr = new Array() var obj = {} // var obj = new Object() function fn() {} // var ...

  8. MongoDB下,启动服务

    D:\MongoDB>mongod --dbpath D:\MongoDB\Data --logpath D:\MongoDB\Log\MongoDB.log --logappend --ser ...

  9. Unity shader学习之屏幕后期处理效果之高斯模糊

    高斯模糊,见 百度百科. 也使用卷积来实现,每个卷积元素的公式为: 其中б是标准方差,一般取值为1. x和y分别对应当前位置到卷积中心的整数距离. 由于需要对高斯核中的权重进行归一化,即使所有权重相加 ...

  10. Debug常用命令

    R命令 查看.修改CPU中寄存器的值 -r ;查看寄存器的值 -r cs ;修改cs寄存器的值 D命令 查看内存中的内容 ;d 段地址:偏移地址 -d 1000:01 ;查看内存100001处的内容 ...