zoukankan      html  css  js  c++  java
  • 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
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    childnodes 兼容性问题
    1,点我呜呜,不点哈哈 2,定时器
    js中的request
    变背景图片位置
    linq contain和orderby
    VueMusic-5首页-音乐榜单
    VueMusic-4首页-视图适配
    VueMusic-3.-今日推荐-视图适配
    lodash---1.使用实列
    VueMusic-2.今日推荐-数据获取
  • 原文地址:https://www.cnblogs.com/jukan/p/10096706.html
Copyright © 2011-2022 走看看