OpenCV3.0 Examples学习笔记(4)-demhist.cpp

这个系列的目的是通过对OpenCV示例,进一步了解OpenCV函数的使用,不涉及具体原理。

目录
简介
Example运行截图
Example分析
1.调节亮度和对比度
    1.1源码
    1.2源码分析-使用convertTo调节图像亮度和对比度
2.绘制图像直方图
    2.1源码
    2.2源码分析
        2.2.1使用calcHist计算直方图
        2.2.2使用Mat::ones创建Mat
        2.2.3使用normalize函数归一化
        2.2.4使用cvRound四舍五入
3.创建滚动条调整参数
Example代码

简介
本文记录了对OpenCV示例 dedmhist.cpp 的分析。
资料地址: http://docs.opencv.org/3.0.0/d2/dcb/demhist_8cpp-example.html

首先这个示例非常有意义,因为OpenCV和很多图像库不同,并未明确提供对亮度和对比度操作的接口,看了
这个示例后就可以搞定。

整个示例可以总结为
(1) 调节图像亮度对比度;
(2)绘制图像直方图;
(3)创建滚动条调整参数。

Example运行截图
brightness
contrast
image
histogram
100
100
200
100
100
200

Example分析
1.调节图像亮度对比度
1.1源码
image.convertTo(dst, CV_8U, a, b);
1.2源码分析-使用convertTo条件图像对比度和亮度
如之前所讲,在OpenCV中无法直接找到如Light(亮度)或Contrast(对比度)字样的接口,
其功能通过函数convertTo实现。
cv::Mat::convertTo
这个函数提供点算子(像素变换)能力,通过增益(alpha)和偏置(beta)参数对图像进行调整,我们也可以使用它完成亮度beta和对比度alpha的调整,其公式如下


函数原型:
void convertTo( OutputArray m, int rtype, double alpha=1, double beta=0 ) const;

参数说明:
m:
输出矩阵;如果在使用前没有声明或需要修改,会自行分配(需要赞美的能力!)。 
rtype:新的矩阵类型。因此也有人使用这个函数进行类型转换
alpha:增益参数,对比度
beta:偏置参数,亮度

PS:convertTo属于Mat的成员函数。
PS2:
saturate_cast用于防止溢出,结果小于0则转为0,大于255,则转为255。

2.绘制图像直方图
2.1源码
calcHist(&dst, 1, 0, Mat(), hist, 1, &histSize, 0);
Mat histImage = Mat::ones(200, 320, CV_8U)*255;
normalize(hist, hist, 0, histImage.rows, NORM_MINMAX, CV_32F);
histImage = Scalar::all(255);
int binW = cvRound((double)histImage.cols/histSize);
for( int i = 0; i < histSize; i++ )
    rectangle( histImage, Point(i*binW, histImage.rows),
                   Point((i+1)*binW, histImage.rows - cvRound(hist.at<float>(i))),
                   Scalar::all(0), -1, 8, 0 );

2.2源码分析
2.2.1使用calcHist计算直方图
OpenCV提供calcHist计算直方图
calcHist
函数原型:
void calcHist( const Mat* images, int nimages,
                          const int* channels, InputArray mask,
                          OutputArray hist, int dims, const int* histSize,
                          const float** ranges, bool uniform = true, bool accumulate = false );
参数说明:

arrays:输入的图像的指针,可以是多幅图像,所有的图像必须有同样的深度(CV_8U or CV  _32F)。

             同时一副图像可以有多个channes。

nimages:输入的图像的个数。

channels:用来计算直方图的channes的数组。比如输入是2副图像,第一副图像有0,1,2共三个cha

                   nnel,第二幅图像只有0一个channel,那么输入就一共有4个channes,如果int channels

                   [3] = {3, 2, 0},那么就表示是使用第二副图像的第一个通道和第一副图像的第2和第0个通

                   道来计算直方图。

mask:掩码。如果mask不为空,那么它必须是一个8位(CV_8U)的数组,并且它的大小的和arrays[i]

            的大小相同,值为1的点将用来计算直方图。

hist:计算出来的直方图

dims:计算出来的直方图的维数。

histSize:在每一维上直方图的个数。简单把直方图看作一个一个的竖条的话,就是每一维上竖条的个

                数。

ranges:用来进行统计的范围。比如

               float rang1[] = {0, 20};

               float rang2[] = {30, 40};

               const float *rangs[] = {rang1, rang2};那么就是对0,20和30,40范围的值进行统计。

uniform:每一个竖条的宽度是否相等。

accumulate:是否累加。如果为true,在下次计算的时候不会首先清空hist。


2.2.2使用Mat::ones创建Mat
示例中使用 Mat histImage = Mat::ones(200, 320, CV_8U)*255; 创建了一个Mat,
这个Mat的rows为200,cols为320,type为CV_8U(每一位使用一个字节);
并且为其每一个位置赋值为255;
这里就引入了一个重要的函数Mat::ones。
Mat::ones
返回指定大小和类型的的矩阵,并且所有元素值为1。(Matlab中常常使用)

函数原型:
MatExpr ones(int rows, int cols, int type);
参数说明:
rows:行数
cols:列数
type:类型

PS:常以类似 Mat  A =  Mat::ones (100, 100,  CV_8U )*3;的形式使用,直接将其元素赋值。

2.2.3使用normalize函数归一化
normalize

该函数归一化输入数组使它的范数或者数值范围在一定的范围内。


函数原型:
void normalize( InputArray src, 
                           InputOutputArray dst, 
                           double alpha = 1, 
                           double beta = 0,
                           int norm_type = NORM_L2, 
                           int dtype = -1, 
                           InputArray mask = noArray());
参数说明:
src:输入数组

dst :输出数组,支持原地运算

alpha:range normalization模式的最小值

beta:range normalization模式的最大值,不用于norm normalization(范数归一化)模式

normType:归一化的类型,可以有以下的取值:

                     NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化,

                     一般较常用。

                     NORM_INF: 此类型的定义没有查到,根据OpenCV 1的对应项,可能是归一化

                     数组的C-范数(绝对值的最大值)

                     NORM_L1 :  归一化数组的L1-范数(绝对值的和)

                     NORM_L2: 归一化数组的(欧几里德)L2-范数

dtype:dtype为负数时,输出数组的type与输入数组的type相同;否则,输出数组与输入数

             组只是通道数相同,而tpye=CV_MAT_DEPTH(dtype).

mask:操作掩膜,用于指示函数是否仅仅对指定的元素进行操作。


2.2.3使用常数为Mat赋值
源码中有一段代码histImage = Scalar::all(255);其实是多余的,将其注释掉也完全没有影响,因为
这段代码意味着使用255为Mat histImage所有元素赋值。
不过这也引入了一个很有意思的地方,Mat类型可以直接通过“=”用常熟为其所有元素赋值。
这很方便:)

2.2.4使用cvRound四舍五入

函数 cvRound, cvFloor, cvCeil 用一种舍入方法将输入浮点数转换成整数。 cvRound 返回和参数最接近的整数值。 cvFloor 返回不大于参数的最大整数值。cvCeil 返回不小于参数的最小整数值。在某些体系结构中该函数 工作起来比标准 C 操作起来还要快。


3.创建滑动条调整参数
为窗口添加滑动条,在OpenCV研发中非常普遍和实用,其大致步骤如下:
step1: 参数全局变量的声明与初始化;
step2:声明存储图像的全局变量;
step3:定义响应滑动条的回调函数,根据参数全局变量,和图像全局变量,以及图像算法进行处理,并显示
step4:创建显示图像的窗口;
step5:在函数中使用createTrackbar创建滑动条;
step6:在函数中手动调用回调函数一次,用于初始化。

Example代码

#include "opencv2/core/utility.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"

#include <iostream>

using namespace cv;
using namespace std;

int _brightness = 100;
int _contrast = 100;

Mat image;

/* brightness/contrast callback function */
static void updateBrightnessContrast( int /*arg*/, void* )
{
    int histSize = 64;
    int brightness = _brightness - 100;
    int contrast = _contrast - 100;

    /*
     * The algorithm is by Werner D. Streidt
     * (http://visca.com/ffactory/archives/5-99/msg00021.html)
     */
    double a, b;
    if( contrast > 0 )
    {
        double delta = 127.*contrast/100;
        a = 255./(255. - delta*2);
        b = a*(brightness - delta);
    }
    else
    {
        double delta = -128.*contrast/100;
        a = (256.-delta*2)/255.;
        b = a*brightness + delta;
    }

    Mat dst, hist;
    image.convertTo(dst, CV_8U, a, b);
    imshow("image", dst);

    calcHist(&dst, 1, 0, Mat(), hist, 1, &histSize, 0);
    Mat histImage = Mat::ones(200, 320, CV_8U)*255;

    normalize(hist, hist, 0, histImage.rows, NORM_MINMAX, CV_32F);

    histImage = Scalar::all(255);
    int binW = cvRound((double)histImage.cols/histSize);

    for( int i = 0; i < histSize; i++ )
        rectangle( histImage, Point(i*binW, histImage.rows),
                   Point((i+1)*binW, histImage.rows - cvRound(hist.at<float>(i))),
                   Scalar::all(0), -1, 8, 0 );
    imshow("histogram", histImage);
}
static void help()
{
    std::cout << "\nThis program demonstrates the use of calcHist() -- histogram creation.\n"
              << "Usage: \n" << "demhist [image_name -- Defaults to ../data/baboon.jpg]" << std::endl;
}

const char* keys =
{
    "{@image|../data/baboon.jpg|input image file}"
};

int main( int argc, const char** argv )
{
    help();

    CommandLineParser parser(argc, argv, keys);
    string inputImage = parser.get<string>(0);

    // Load the source image. HighGUI use.
    image = imread( inputImage, 0 );
    if(image.empty())
    {
        std::cerr << "Cannot read image file: " << inputImage << std::endl;
        return -1;
    }

    namedWindow("image", 0);
    namedWindow("histogram", 0);

    createTrackbar("brightness", "image", &_brightness, 200, updateBrightnessContrast);
    createTrackbar("contrast", "image", &_contrast, 200, updateBrightnessContrast);

    updateBrightnessContrast(0, 0);
    waitKey();

    return 0;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值