简介 本文介绍使用OpenCV在修改矩阵特定区域也就是ROI值的时候,需要注意的事项。如果类型错误,将得到错误的结果.
正式交代主题前,先看以下几个点.
我们主要是关注第二个参数,有以下四种:
1 2 3 4 CV_LOAD_IMAGE_ANYDEPTH - If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit. CV_LOAD_IMAGE_COLOR - If set, always convert image to the color one CV_LOAD_IMAGE_GRAYSCALE - If set, always convert image to the grayscale one >0 Return a 3-channel color image.
默认下传的是CV_LOAD_IMAGE_COLOR,得到的Mat type为CV_8UC3,如果传的是CV_LOAD_IMAGE_GRAYSCALE则表示加载的是灰度图像,type为CV_8UC1。
设置ROI 方式有大概有2种:
拷贝构造函数
1 Mat roi = Mat(gray, Rect(100, 0, 30, 30));
当然上面也完全等价于下面这句:
1 Mat roi(gray, Rect(100, 0, 30, 30));
可能是写Java多的原因,我更喜欢前面的那种写法. 2. 使用操作符
1 Mat srcROI = src(Rect(0,0,src.cols/2,src.rows/2));
最常见的一种构造方法是:
1 Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height);
其中x表示ROI区域的x坐标(横轴为X),也就是第几列的意思,y就不解释了。width表示ROI区域的宽度.
Mat元素访问 链接 列举了13种访问方法,这里 又精简到3种,如果对效率没什么太高要求那么还是第一种用起来比较顺手:
1 2 3 4 5 6 7 8 for (int i=0; i<ROWS ; i++) { for (int j=0; j<COLS ; j++) { img1.at<float>(i,j) = 3.2f; } }
这里的Mat.at(i, j),其中i表示第几行,j表示第几列.
修改特定区域的值 目的就是要将roi区域灰度值置为0:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <iostream> using namespace std; #include <opencv2/opencv.hpp> using namespace cv; using namespace std; void clearMat(Mat a){ if(a.empty()){ return; } for(int i = 0; i<a.rows; i++) for(int j = 0; j<a.cols; j++){ a.at<uchar>(i, j) = 0; } } int main(int argc, const char * argv[]) { // insert code here... cout << "Hello, World!\n"; string path = "/Users/yanzi/Pictures/lena.jpg"; Mat img = imread(path); //显示灰度图 Mat gray; cvtColor(img, gray, COLOR_RGBA2GRAY); Mat gray1 = imread(path, IMREAD_GRAYSCALE); // Mat roi = Mat(gray, Rect(100, 0, 30, 30)); Mat roi(gray, Rect(100, 0, 30, 30)); clearMat(roi); namedWindow("gray"); imshow("gray", gray); waitKey(0); return 0; }
我们将gray矩阵的那个rect区域弄成黑色,效果图如下: 可以看到运行的丝毫不差。注意我们在访问矩阵元素是是将其设为uchar,如果将其改为int看一下效果: 起点是对的,但是宽度变成了需求的四倍。这是因为uchar只占一个字节,而int为4个字节.当错误的将其转为int后,就会发生实际修改的区域越位的情况。所以当修改Mat时一定格外注意.
下面 是深度和取值范围的对应关系:
1 2 3 4 5 6 7 CV_8U - 8-bit unsigned integers ( 0..255 ) CV_8S - 8-bit signed integers ( -128..127 ) CV_16U - 16-bit unsigned integers ( 0..65535 ) CV_16S - 16-bit signed integers ( -32768..32767 ) CV_32S - 32-bit signed integers ( -2147483648..2147483647 ) CV_32F - 32-bit floating-point numbers ( -FLT_MAX..FLT_MAX, INF, NAN ) CV_64F - 64-bit floating-point numbers ( -DBL_MAX..DBL_MAX, INF, NAN )
我们还要清楚这个depth和数据类型的对应关系:
1 2 3 4 5 6 7 Mat_<uchar>---------CV_8U Mat<char>-----------CV_8S Nat_<short>---------CV_16S Mat_<ushort>--------CV_16U Mat_<int>-----------CV_32S Mat_<float>----------CV_32F Mat_<double>--------CV_64F
这样就不会出错了。 再贴一段如果是三通道时的访问方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 int ROWS = 100; // height 2 int COLS = 200; // width 3 Mat img1(ROWS , COLS , CV_8UC3); 4 5 for (int i=0; i<ROWS ; i++) 6 { 7 for (int j=0; j<COLS ; j++) 8 { 9 img1.at<vec3b>(i,j)[0]= 3.2f; // B 通道 10 img1.at<vec3b>(i,j)[1]= 3.2f; // G 通道 11 img1.at<vec3b>(i,j)[2]= 3.2f; // R 通道 12 } 13 }
参考
http://www.cnblogs.com/dupuleng/articles/4072736.html
opencv2.4.13官方文档