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

收入囊中

  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也讲过



  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值