OpenCV(3).图像操作-图像选取与图像标注

536 阅读3分钟
  1. 选取图像区域
  2. Mat_类
  3. Mat类的内存管理
  4. 图像标注
选取图像局部区域
  • Mat类提供了多种方法选取图像局部区域
  • 需要注意的是,这些方法并不进行内存的复制操作,新对象只是与原始对象共享 - 相同的数据区域,而不新申请内存,这也是这些方法执行速度比较快的原因 选取单行或单列
Mat::row(int y) const
Mat::col(int x) const
参数 y 和 x 分别是行索引和列索引。
    Mat img = imread(".../opencv/sources/samples/data/HappyFish.jpg");
    // 259 -194
    cout << img.cols<<" - " << img.rows << endl;
    imshow("mat", img);
    //获取图像矩阵的第100行数据
    Mat line = img.row(100);
    cout << line << endl;
  • 选取多行或多列
通过使用 Range 类,可以选取矩阵的多行或多列。
Range 类是 OpenCV 的一个基本数据类型,其定义如下:
1.它有两个重要变量 star 和 end,表示的范围为从 startend,包含 start 但不包含 end2.Range类还有一个静态方法 all(),可直接选取所有行或者所有列,作用类似 Matlab 中的“:”。
​
    //一次获取图像矩阵的多行和多列
    //获取全部行,获取列100149数据
    Mat range = img(Range::all(), Range(100, 150));
    //cout << range << endl;
    imshow("range", range);

原图 截取部分图像

  • 选取感兴趣区域
有两种方法可以从图像中选取感兴趣区域(ROI,Region of Interest)
1. 使用构造函数,如以下代码所示:
    //3.选取感兴趣区域
    //通过在原图中设置截取区域
    //3.1.构造函数中设置
    Mat roi1(img, Rect(80, 60, 160, 120));
    imshow("roi1", roi1);
    Mat roi2(img, Range(80,160),Range(60,120));
    imshow("roi2", roi2);
​
2. 使用括号运算符,如以下代码所示:
    //上面的代码也可以这样写法
    Mat roi3 = img(Rect(80, 60, 160, 120));
    Mat roi4 = img(Range(80, 160), Range(60, 120));

原图与感兴趣区域

  • 选取对角线
    //4.选取对角线 diag()函数
    Mat M = (Mat_<int>(4, 4) <<
        1, 2, 3, 0,
        4, 5, 6, 0,
        7, 8, 9, 0,
        10, 11, 12, 13);
    //取主对角线
    Mat d0 = M.diag(0);
    cout << "d0" << endl<<" " << d0 << endl;
    //取主对角线上方第2条对角线
    Mat d2 = M.diag(2);
    cout << "d2" << endl << " " << d2 << endl;
    //取主对角线下方第1条对角线
    Mat d1 = M.diag(-1);
    cout << "d1" << endl << " " << d1 << endl;
​
打印结果:
d0
 [1;
 5;
 9;
 13]
​
d2
 [3;
 0]
​
d1
 [4;
 8;
 12]
  • 输出 重载符: "<<"
Mat_类
  • Mat_类是对Mat类的一个轻量级包装,它是一个模板类,使得访问元素时可以不需要指定元素类型,使得代码简洁,又减少了出错的可能性
  • 将之间图像元素遍历的代码使用Mat_类进行改造如下
    //Mat_ 类使用
        //指针方式遍历像素
    Mat grayImg(480, 640, CV_8UC1);
    Mat_<uchar> grayImg_ = grayImg;
    for (int i = 0; i < grayImg.rows; i++)
    {
        //获取指针对象,不用设置泛型
        uchar* p = grayImg_.ptr(i);
        //比较
        uchar* p2 = grayImg.ptr<uchar>(i);
        for (int j = 0; j < grayImg.cols; j++)
        {
            grayImg_(i, j) = (i + j) % 255;
            //grayImg(i, j) = 100; 不能使用
        }
    }
    imshow("grayImg_", grayImg_);

Mat类的内存管理

Mat类由两个数据部分组成
  • 矩阵头:矩阵头的尺寸时常数值
  • 存储所有像素值的内存指针uchar* data
复制矩阵数据往往要花费较多时间,尤其是大矩阵。为了解决矩阵数据的传递,OpenCV使用了引用计数机制。
  • 思路是让每个Mat对象有自己的矩阵头信息,但多个Mat对象可以共享同一个矩阵数据,即让多个矩阵指针data指向同一个地址
  • 所以当一个Mat对象中的data改变了,其他的Mat对象的数据内容也跟着改变

标注图像

  • 在图像上进行标记或标注,方便显示算法的结果
  • 常见场景为:识别原始图像中的人脸或物体,在图像上用矩形框框出物体显示物体位置,并表示出物体的类别及其他信息
OpenCV 中常用的绘制函数有:
1.绘制直线
void cv::line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, int thickness=1, 
int lineType=LINE_8, int shift=0)
img 为需要绘制标记的图像;pt1 和 pt2 分别为直线起点和终点的坐标;
color 为直线的颜色;thickness 为直线的宽度;lineType 为直线的类型
​
2.绘制圆
void cv::circle(InputOutputArray img, Point center, int radius, const Scalar& color, int
thickness=1, int lineType=LINE_8, int shift=0)
img 为需要绘制标记的图像;center 为圆心坐标;radius 为圆半径;color 为圆的颜色;
thickness 为圆的线条宽度;lineType 为圆的线条类型
​
3.绘制矩形
void cv::rectangle(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, int
thickness=1, int lineType=LINE_8, int shift=0)
img 为需要绘制标记的图像;pt1 为矩形左上角坐标, pt2 为矩形右下角坐标;color 为
矩形边颜色;thickness 为矩形边的宽度;lineType 为矩形边的类型;shift 为坐标小数位数。
void cv::rectangle(InputOutputArray img, Rect rect, const Scalar& color, int thickness=1, int 
lineType=LINE_8, int shift=0)
img 为需要绘制标记的图像;rect 为所要绘制的矩形;color 为矩形边颜色;thickness
为矩形边的宽度;lineType 为矩形边的类型
​
4.绘制文字
void cv::putText(InputOutputArray img, const String& text, Point org, int fontFace, double 
fontScale, Scalar color, int thickness=1, int lineType=LINE_8, bool bottomLeftOrigin=false)
img 为需要绘制标记的图像;text 为要显示的文字;org 为文字左下角的坐标;fontFace
为字体;fontScale 为相对于字体基础大小的缩放比例;color 为文字的颜色;thickness 为文
字线条的宽度;lineType 为文字线条的类型;bottomLeftOrigin 为 true 时,图像坐标的原点
在左下角,bottomLeftOrigin 为 false 时,图像坐标的原点在左上角。
例子
    Mat img = imread(".../opencv/sources/samples/data/lena.jpg");
    //图像标记
    //1.绘制绿色直线
    line(img, Point(300, 300), Point(450, 100), Scalar(0, 255, 0), 3);
    //绘制黄色园
    circle(img, Point(200, 200), 100, Scalar(0, 255, 255), 3);
    //绘制红色矩形
    rectangle(img, Point(20, 20), Point(50, 100), Scalar(0, 0, 255), 3);
    //绘制蓝色矩形
    rectangle(img, Rect(30,30,40,100), Scalar(255, 0, 0), 3);
    //绘制白色文字
    putText(img, "Beautiful girl", Point(50, 50), FONT_HERSHEY_COMPLEX,
        1.0, Scalar(255, 255, 255), 3);
    imshow("img", img);