OpenCV2马拉松第3圈——改变对比度和亮度

来源:互联网 发布:网络草花机 编辑:程序博客网 时间:2024/05/18 01:46

收入囊中

  1. 访问每个像素点
  2. 了解saturate_cast如何防溢出
  3. 初步懂得像素变换


初识API

在这之前先介绍点数据结构和方法。

首先是定义在core.hpp中的

typedef Vec<uchar, 2> Vec2b;typedef Vec<uchar, 3> Vec3b;typedef Vec<uchar, 4> Vec4b;typedef Vec<short, 2> Vec2s;typedef Vec<short, 3> Vec3s;typedef Vec<short, 4> Vec4s;typedef Vec<ushort, 2> Vec2w;typedef Vec<ushort, 3> Vec3w;typedef Vec<ushort, 4> Vec4w;        typedef Vec<int, 2> Vec2i;typedef Vec<int, 3> Vec3i;typedef Vec<int, 4> Vec4i;typedef Vec<int, 6> Vec6i;typedef Vec<int, 8> Vec8i;typedef Vec<float, 2> Vec2f;typedef Vec<float, 3> Vec3f;typedef Vec<float, 4> Vec4f;typedef Vec<float, 6> Vec6f;typedef Vec<double, 2> Vec2d;typedef Vec<double, 3> Vec3d;typedef Vec<double, 4> Vec4d;typedef Vec<double, 6> Vec6d;
Vec类就先不要管了,这是个模板类,特别要关注这里的Vec3b,为什么呢,因为他特别适合放三通道RGB,每一个都是uchar,也就是0-255


下面我们来看Mat.hpp文件

有个很重要的方法叫at

C++: template<typename T> T& Mat::at(int i) const
C++: template<typename T> const T& Mat::at(int i) const
C++: template<typename T> T& Mat::at(int i, int j)
C++: template<typename T> const T& Mat::at(int i, int j) const
C++: template<typename T> T& Mat::at(Point pt)
C++: template<typename T> const T& Mat::at(Point pt) const
C++: template<typename T> T& Mat::at(int i, int j, int k)
C++: template<typename T> const T& Mat::at(int i, int j, int k) const
C++: template<typename T> T& Mat::at(const int* idx)
C++: template<typename T> const T& Mat::at(const int* idx) const
Parameters:
  • i – Index along the dimension 0
  • j – Index along the dimension 1
  • k – Index along the dimension 2
  • pt – Element position specified as Point(j,i) .
  • idx – Array of Mat::dims indices.



最重要的还是根据row和column来访问

template<typename _Tp> inline _Tp& Mat::at(int i0, int i1){    CV_DbgAssert( dims <= 2 && data && (unsigned)i0 < (unsigned)size.p[0] &&        (unsigned)(i1*DataType<_Tp>::channels) < (unsigned)(size.p[1]*channels()) &&        CV_ELEM_SIZE1(DataType<_Tp>::depth) == elemSize1());    return ((_Tp*)(data + step.p[0]*i0))[i1];}
image.at<Vec3b>(y,x)[0] 就可以访问y行x列的red值 

image.at<Vec3b>(y,x)[1] 就可以访问y行x列的green值 

image.at<Vec3b>(y,x)[2] 就可以访问y行x列的blue值 


另外Mat还有类似MATLAB和Octave的初始化方法

  • Use MATLAB-style array initializers, zeros(), ones(), eye(), for example:

    // create a double-precision identity martix and add it to M.M += Mat::eye(M.rows, M.cols, CV_64F);
下面要用到zeros,就介绍下zeros的接口
C++: static MatExpr Mat::zeros(int rows, int cols, int type)
C++: static MatExpr Mat::zeros(Size size, int type)
C++: static MatExpr Mat::zeros(int ndims, const int* sz, int type)
Parameters:
  • ndims – Array dimensionality.
  • rows – Number of rows.
  • cols – Number of columns.
  • size – Alternative to the matrix size specification Size(cols, rows) .
  • sz – Array of integers specifying the array shape.
  • type – Created matrix type.

The method returns a Matlab-style zero array initializer. It can be used to quickly form a constant array as a function parameter, part of a matrix expression, or as a matrix initializer.

Mat A;A = Mat::zeros(3, 3, CV_32F);

比如我要用第二种方法,就可以这样来写

Mat image = imread( argv[1] );Mat new_image = Mat::zeros( image.size(), image.type() );

另外一个很有用的模板函数是saturate_cast,可以有效防止溢出

uchar a = saturate_cast<uchar>(-100); // a = 0 (UCHAR_MIN)short b = saturate_cast<short>(33333.33333); // b = 32767 (SHORT_MAX)
下面,我们就可以来看这个代码了#include "opencv2/highgui/highgui.hpp"
#include <iostream>using namespace cv;double alpha; /**< Simple contrast control */int beta;  /**< Simple brightness control */int main( int, char** argv ){   /// Read image given by user   Mat image = imread( argv[1] );   Mat new_image = Mat::zeros( image.size(), image.type() );   std::cout<<" Basic Linear Transforms "<<std::endl;   std::cout<<"-------------------------"<<std::endl;   std::cout<<"* Enter the alpha value [1.0-3.0]: ";std::cin>>alpha;   std::cout<<"* Enter the beta value [0-100]: "; std::cin>>beta;   /// Do the operation new_image(i,j) = alpha*image(i,j) + beta   /// Instead of these 'for' loops we could have used simply:   /// image.convertTo(new_image, -1, alpha, beta);   /// but we wanted to show you how to access the pixels :)   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 );                }       }      }   namedWindow("Original Image", 1);   namedWindow("New Image", 1);   imshow("Original Image", image);   imshow("New Image", new_image);   waitKey();   return 0;}
有了上面的知识打底,是不是感觉一下子就看懂了~~

如同注释说的,我们有函数可以直接达到目的,不需要我们去遍历。

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

这儿的const就是说这个函数操作不会对变量或是对象之类的值有影响

rtype为-1表示input和output的类型一致,非常方便。

变换公式:m(x,y) = saturate \_ cast<rType>( \alpha (*this)(x,y) +  \beta )


下面是一个有控制条的对比度变换

#include "opencv2/highgui/highgui.hpp"#include <iostream>using namespace cv;int alpha = 50;Mat image,new_image;static void change_color(int, void*){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/50.0 *( image.at<Vec3b>(y,x)[c] ));    imshow("Image", new_image);}int main( int, char** argv ){   image = imread( argv[1] );   new_image = Mat::zeros( image.size(), image.type() );   namedWindow("Image", 1);createTrackbar( "pick:", "Image", &alpha, 100, change_color);change_color(0, 0);waitKey();return 0;}
关于控制条,你可以暂时不管(其实非常简单),相信你能非常容易看懂

举一反三

公式:

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

Computer Vision: Algorithms and Applications 有介绍

alpha可以认为是控制contrast,beta控制brightness,alpha和beta也可以是空间的函数而不是固定的,我在image processing也讲过



5 1
原创粉丝点击