学习OpenCV范例(五)——改变图像的对比度和亮度

学习到范例五的时候,发觉虽然范例都很简单,但是做记录的时候,并且把程序里面使用过的类或方法都弄明白,也就不简单了,接下来介绍一下范例五吧。

1、图像处理

一般来说,图像处理算子是带有一幅或多幅输入图像、产生一幅输出图像的函数。

图像变换可分为以下两种:

点算子(像素变换):图像对比度和亮度,等等

邻域(基于区域的)算子:均值滤波,中值滤波,等等,也就是卷积运算

2、亮度和对比度调整

两种常用的点过程(即点算子),是用常数对点进行 乘法 和 加法 运算:

                                                                                                                      g(x) = \alpha f(x) + \beta

两个参数 \alpha > 0 和 \beta 一般称作 增益 和 偏置 参数。我们往往用这两个参数来分别控制 对比度 和 亮度 。

你可以把 f(x) 看成源图像像素,把 g(x) 看成输出图像像素。这样一来,上面的式子就能写得更清楚些:

                                                                                                                  g(i,j) = \alpha \cdot f(i,j) + \beta

其中, i 和 j 表示像素位于 第i行 和 第j列 。

3、运行代码如下:

程序使用三种方式来实现亮度和对比度的调整,并且输出了各自运算的时间。

#include "stdafx.h"
 
 
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
 
using namespace std;
using namespace cv;
 
double alpha; /**< 控制对比度 */
int beta;  /**< 控制亮度 */
 
int main( int argc, char** argv )
{
    double t;
    /// 读入用户提供的图像
    Mat image = imread( "Lena.jpg" );
    Mat new_image = Mat::zeros( image.size(), image.type() );
    Mat new_image1 = Mat::zeros( image.size(), image.type() );
    Mat new_image2 = Mat::zeros( image.size(), image.type() );
 
 
    /// 初始化
    cout << " Basic Linear Transforms " << endl;
    cout << "-------------------------" << endl;
    cout << "* Enter the alpha value [1.0-3.0]: ";
    cin >> alpha;
    cout << "* Enter the beta value [0-100]: ";
    cin >> beta;
 
    t = (double)getTickCount();
    /// 执行运算 new_image(i,j) = alpha*image(i,j) + beta
    for( int y = 0; y < image.rows; y++ )
    {
        for( int x = 0; x < image.cols; x++ )
        {
            for( int c = 0; c < 3; c++ )
            {
                new_image.at<Vec3b>(y,x)[c] = saturate_cast<uchar>( alpha*( image.at<Vec3b>(y,x)[c] ) + beta );
            }
        }
    }
    t = 1000*((double)getTickCount() - t)/getTickFrequency();
    cout << ".at+[] Times passed in milliseconds: " << t << endl;
 
 
    t = (double)getTickCount();
    int nr= image.rows; // number of rows  
    int nc= image.cols * image.channels(); // total number of elements per line  
    for (int y=0; y<nr; y++) 
    {  
        uchar* data= image.ptr<uchar>(y);  
        uchar* data1=new_image1.ptr<uchar>(y);
        for (int x=0; x<nc; x++) 
        {  
            data1[x]=saturate_cast<uchar>(alpha*data[x]+beta);
        }
    }
    t = 1000*((double)getTickCount() - t)/getTickFrequency();
    cout << ".ptr+[] Times passed in milliseconds: " << t << endl;
 
    t = (double)getTickCount();
    image.convertTo(new_image2, -1, alpha, beta);
    t = 1000*((double)getTickCount() - t)/getTickFrequency();
    cout << "convertTo Times passed in milliseconds: " << t << endl;
 
 
    /// 创建窗口
    namedWindow("Original Image", 1);
    namedWindow("New Image", 1);
    namedWindow("New Image1", 1);
    namedWindow("New Image2", 1);
 
    /// 显示图像
    imshow("Original Image", image);
    imshow("New Image", new_image);
    imshow("New Image1", new_image1);
    imshow("New Image2", new_image2);
 
    /// 等待用户按键
    waitKey();
    return 0;
}

5、结论

从运行时间可以看出,使用OpenCV自带的函数运行效率最高,而使用.ptr方法比.at方法好,这也印证了前面博客学习OpenCV范例(二)——OpenCV如何扫描图像、利用查找表和计时所说的。

6、用到的类

convertTo:

功能:通过缩放比例将数组变换成其他类型

结构:

void Mat::convertTo(OutputArray m, int rtype, double alpha=1, double beta=0 ) const

m:输出图像

rtype:输出图像的类型

alpha:比例因子α,决定对比度

beta:附加值β,决定亮度

函数原理如下:

                  m(x,y) = saturate \_ cast<rType>( \alpha (*this)(x,y) +  \beta )

saturate_cast:

功能:防止数据溢出

为什么上面的函数会用到saturate_cast呢,因为无论是加是减,乘除,都会超出一个像素灰度值的范围(0~255)所以,所以当运算完之后,结果为负,则转为0,结果超出255,则为255。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值