收入囊中
- 访问每个像素点
- 了解saturate_cast如何防溢出
- 初步懂得像素变换
在这之前先介绍点数据结构和方法。
首先是定义在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.
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:
-
下面要用到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 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的类型一致,非常方便。
变换公式:
下面是一个有控制条的对比度变换
#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;
}
关于控制条,你可以暂时不管(其实非常简单),相信你能非常容易看懂
举一反三
公式:
Computer Vision: Algorithms and Applications 有介绍
alpha可以认为是控制contrast,beta控制brightness,alpha和beta也可以是空间的函数而不是固定的,我在image processing也讲过