Opencv改变图像亮度和对比度以及优化
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改变图像亮度和对比度以及优化的更多相关文章
- opencv::调整图像亮度与对比度
图像变换可以看作如下: - 像素变换 – 点操作 - 邻域操作 – 区域 调整图像亮度和对比度属于像素变换-点操作 //创建一张跟原图像大小和类型一致的空白图像.像素值初始化为0 Mat new_im ...
- OpenCV 改变图像的对比度和亮度
#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <ios ...
- 跟我一起学opencv 第五课之调整图像亮度和对比度
一.调整图像亮度与对比度 1.图像变换 ---像素变换-点操作 ---邻域操作-区域操作 调整图像亮度和对比度属于像素变换-点操作 公式为:g(i,j) = αf(i,j) + β 其中α>0 ...
- OpenCV学习:改变图像的对比度和亮度
本实例演示简单地改变图像的对比度和亮度,使用了如下线性变换来实现像素值的遍历操作: The parameters α > 0 and β often called the gain and bi ...
- openCV - 5~7 图像混合、调整图像亮度与对比度、绘制形状与文字
5. 图像混合 理论-线性混合操作.相关API(addWeighted) 理论-线性混合操作 用到的公式 (其中 α 的取值范围为0~1之间) 相关API(addWeighted) 参数1:输入图像M ...
- OpenCV中的SVM參数优化
SVM(支持向量机)是机器学习算法里用得最多的一种算法.SVM最经常使用的是用于分类,只是SVM也能够用于回归,我的实验中就是用SVM来实现SVR(支持向量回归). 对于功能这么强的算法,opencv ...
- OpenCV --- 修改图像的对比度、亮度 、RGB转Gray图像、修改图像的尺寸
#include <opencv2/core.hpp> #include <opencv2/imgcodecs.hpp> #include <opencv2/highgu ...
- opencv调整图像亮度对比度
图像处理 图像变换就是找到一个函数,把原始图像矩阵经过函数处理后,转换为目标图像矩阵. 可以分为两种方式,即像素级别的变换和区域级别的变换 Point operators (pixel transfo ...
- [OpenCV] 图像亮度和对比度调整
对比度调整的原理参考这篇博客 以下是代码实现: #include <iostream> #include "opencv2/core.hpp" #include &qu ...
随机推荐
- node—基础命令
1.安装node,在任意文件夹下按shift键选中“在此处打开PowerShell窗口”或者直接在开始菜单输入cmd启动 2.常用命令: c: 如果我们想访问c盘,那么我们需要在命令行中输入c:就行了 ...
- vue watch 监听element upload组件上传成功返回的url列表
因为 on-success 上传成功返回的是一个异步的结果....如果父组件需要这个结果的话 必须用watch 监听 然后里面建立一个 save()方法 save方法里面再调用接口 传需要的上传之后的 ...
- websocket协议的思考
同过wireshark抓包,都是TCP的连接,省了好多的HTTP的头部请求 Ping Pong,TCP keep alive,双方没有数据来往的时候,通过发空白报文,侦测的报文来决定看这个链接是否还存 ...
- 家庭记账本之GitHub账号注册与安装(一)
账号注册 1.github是世纪上最大的开源代码托管网站.因为是国外网站,很多人在注册的时候因为不熟悉英语而犯了难. 2.百度搜索github进入官网.如果你已经有账号密码,那么点击右上角的sign ...
- MyBatis基础入门《十六》缓存
MyBatis基础入门<十六>缓存 >> 一级缓存 >> 二级缓存 >> MyBatis的全局cache配置 >> 在Mapper XML文 ...
- HTML/HTML5 Input类型&&表单
1.HTML 中"不常用"input类型中的属性值: disabled:输入字段禁用: maxlength:输入字段的最大字符长度: readonly:输入字符只读,无法修改: s ...
- HighCharts学习笔记(一)
HighChars基本概述 Highcharts是一个纯js写成的插件库,很好的外观表现可以满足任何图标需求. 开始使用chart之前进行配置 全局配置: Highcharts.setOptions( ...
- 编写python的程序
执行python程序有两种方式: 1.交互式环境:输入代码立即执行 优点:调试程序方便 缺点:无法永久保存程序 2.代码写入文件 ...
- Helter Skelter (扫描线 + 离散化 + 树状数组)
扫描线:按照其中一个区间的标记为pos,然后左区间标记d为正影响,有区间标记d为负影响,然后根据所有的pos排序.pos从小扫到大,那么对于某一个区间一定会被扫过2次,那么经过2次之后就只剩下中间那一 ...
- tcp_协议基础
具体7层 数据格式 功能与连接方式 典型设备 应用层 Application 数据Data 网络服务与使用者应用程序间的一个接口 终端设备(PC.手机.平板等) 表示层 Presentation ...