@nrailgun
2016-11-11T18:10:31.000000Z
字数 1788
阅读 2519
程序设计
大四时候选修了图形学的课程,然而当时正沉迷于电子游戏,没有认真学习,程序写得乱七八糟,OpenCV 也没有认真看。这两天正好有空,赶紧补习。
Mat
是 OpenCV 的基本图像容器,本质是矩阵。构造函数定义如下:
C++: Mat::Mat();
C++: Mat::Mat(int rows, int cols, int type);
C++: Mat::Mat(Size size, int type);
一般通过 imread
方法读入图像:
cv::Mat imread(const char *filename, int imgtype);
例子:
Mat A, B;
A = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
B = A.clone();
容器数据类型通过 CV_MAKE_TYPE(depth, channel)
来定义。channel
是指矩阵 channel 数量(举例,对于 RGB 图像,channel
为 3)。depth
是指数据类型长度,宏定义如下:
type | size | cvtype |
---|---|---|
unsigned | 1 | CV_8U |
unsigned | 2 | CV_16U |
unsigned | 4 | CV_32U |
signed | 1 | CV_8S |
signed | 2 | CV_16S |
signed | 4 | CV_32S |
float | 4 | CV_32f |
float | 8 | CV_64f |
例如,构造一个 的浮点矩阵:
Mat M(2, 2, CV_MAKE_TYPE(CV_32F, 3));
OpenCV 为常用类型提供了宏定义,形式为 CV_${NBIT}${TYPE}${CHN}
。比如,定义 的浮点为 CV_32F3
。
通过 convertTo
方法实现数据类型转换:
void convertTo(OutputArray m, int rtype, double alpha=?, double beta=?);
这很重要,因为可以通过转换数据类型来适配某些不能适用于当前数据类型的操作或者函数。
这是我最喜欢的粗暴直接的方法。OpenCV 提供了 at
和 ptr
方法用于直接访问 Mat
内部数据结构:
Mat I;
I.at<uchar>(0, 0) = 0;
for(int i = 0; i < I.rows; ++i) {
uchar *p = I.ptr<uchar>(i);
for (int j = 0; j < I.cols; ++j) {
p[j] = rand() % 256;
}
}
OpenCV 提供了模板方法 begin
和 end
来实现类似 STL 的迭代器:
MatIterator_<Vec3b> it;
for(it = I.begin<Vec3b>(); it != I.end<Vec3b>(); ++it) {
(*it)[0] = 2;
(*it)[1] = 1;
(*it)[2] = 0;
}
OpenCV 提供了 2D 滤波操作 filter2D
,所以只要实现核函数就可以了。
void filter2D(InputArray src, OutputArray dst, int ddepth, InputArray kernel,
Point anchor=?, double delta=?, int borderType=?) ;
一个拉普拉斯算子的例子:
Mat kern = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
Mat oimg;
filter2D(cvimg, oimg, cvimg.depth(), kern);
cv::Mat cvimg(cv::Size(w, h), CV_32FC1, (void *) data, cv::Mat::AUTO_STEP);
cv::imshow("", cvimg);
cv::waitKey(0);
注意:并不是 clone
。
J = I(Rect(x, y, w, h));
Mat C = (Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
cv::Mat m;
m = (m != 0);
m = cv::min(m, 1);
resize(I, I, Size(w, h), alpha, beta, CV_INTER_NN);
cv::cvtColor(im, rv, CV_BGR2GRAY);