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. 多线程——实现Runnable接口实现一个多线程

    实现Runnable接口实现一个多线程 Runnable接口源码: package java.lang; //Runnable接口源码只有一个run方法 public interface Runnab ...

  2. 模仿以太坊 ERC20 规范的 Hyperledger Fabric 实现 Token 通证

    合约: package main /* -------------------------------------------------- Author: netkiller <netkill ...

  3. 【LeetCode每天一题】Reverse Linked List(链表反转)

    Reverse a singly linked list. Example:           Input: 1->2->3->4->5->NULL          ...

  4. git-代码同步至github

    代码同步到github上 Last login: Wed Mar 27 13:53:06 on ttys001localhost:~ ligaijiang$ gitusage: git [--vers ...

  5. webpack1.0--图片

  6. export,import ,export default 彻底弄痛

    ES6模块主要有两个功能:export和import 说白了就是一个淡出一个导入,就相当于以前的公共js样,哪个页面要用,就script 引入这个js  ,然后  无耻的调用这个js中的方法了. ex ...

  7. 部署一个不依赖tomcat容器的应用

    一个task项目,应用里边都是一些定时任务.我和新入职的高开商定程序部署不依赖于tomcat. 计划赶不上变化,任务开发完成还没等上线呢,哥们要离职了.工作交接时大概说了一下上线怎么部署. 结果呢,当 ...

  8. js的基本包装类型

    基本包装类型(包装对象): 先看下以下代码: var s1 = "helloworld"; var s2 = s1.substr(4); 上面我们说到字符串是基本数据类型,不应该有 ...

  9. hdu5125 树状数组+dp

     hdu5125 他说的是n个人每个人都有两个气球a,b,气球各自都有相应的体积,现在让他们按照序号排列好来,对他们的a气球体积值计算最长上升子序列,对于这整个排列来说有m次机会让你将a气球替换成b气 ...

  10. SiteCore Experience Analytics-体验分析

    体验分析   Sitecore Experience Analytics为营销人员和营销分析师提供仪表板和报告,以识别从其网站和可能的其他外部数据源收集的体验数据的模式和趋势. 体验分析报告示例:   ...