关闭

core组件之基本数据结构和绘图函数

78人阅读 评论(0) 收藏 举报
分类:

在本节中,总结了以下内容:

  • Mat类的基本用法
  • 常用的数据结构(如Point,Size等)
  • 基本的绘图操作(rectangle(),circle(),ellipse())

【Mat类的基本介绍】

Mat类是一个图像容器类,同时也是一个通用的矩阵类,可以用它来创建和操作多维矩阵。

创建一个Mat对象的方法有多种,以下仅介绍我比较常用的一些。

方法一、使用Mat()构造函数(最常用)

如:Mat M(3, 2, CV_8UC3,Scalar(0,0,255));

对于二维多通道图像,分别定义其尺寸,即行数(rows)和列数(cols);然后指定存储元素的数据类型和通道数(如CV_8UC3)以及初始化的值(如Scalar(0,0,255))。
行数和列数自然很好理解,那么这里的CV_8UC3是什么意思呢?
OpenCV规定了存储元素的数据类型和每个矩阵点的通道数,规则如下:
CV_[the number of bits of per item][signed or unsigned][type prefix]C[the channel number]
即,CV_[位数][带符号与否][类型前缀]C[通道数](前缀类型是什么我还不理解。。。)
因此,CV_8UC3则表示使用8位的unsigned char型,每个像素由三个元素组成三通道。

而初始值Scalar(0,0,255)又表示什么意思呢?
首先要知道Scalar是一个类,表示具有4个元素的数组,它在OpenCV中常用于表示像素值(如RGB颜色值,通常只写三个参数,最后一个不用写),如Scalar(0,0,255)表示蓝色分量为0,绿色分量为0,红色分量为255。(注意:我这里是写错了吗?用Scalar(0,0,255)表示一个RGB颜色值怎么是”蓝色分量为0,绿色分量为0,红色分量为255“呢?——其实没有写错,因为OpenCV默认的图片通道存储顺序是BGR!)
其次,在Mat的构造函数中,就是用Scalar(0,0,255)来初始化每一个像素点。

如果直接cout << "M=" << endl << M << endl;
可以看到:

M=
[  0,   0, 255,   0,   0, 255;
   0,   0, 255,   0,   0, 255;
   0,   0, 255,   0,   0, 255]
方法二、采用Matlab式的初始化方式

zeros()(全0矩阵),ones()(全1矩阵),eye()(正对角线为1的矩阵)这三个函数。需要指定尺寸和数据类型,比较简单,直接上例子了。

Mat M1 = Mat::zeros(3, 2, CV_8UC1);
Mat M2 = Mat::ones(3, 2, CV_8UC1);
Mat M3 = Mat::eye(3, 2, CV_8UC1);

M1=
[  0,   0;
   0,   0;
   0,   0]
M2=
[  1,   1;
   1,   1;
   1,   1]
M3=
[  1,   0;
   0,   1;
   0,   0]
方法三、对小矩阵使用逗号分隔式初始化函数

Mat M4 = (Mat_<float>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);

M4=
[1, 2, 3;
4, 5, 6;
7, 8, 9]
方法四、使用成员函数clone()copyTo()

在介绍clone()copyTo()函数之前,先来看下面一段代码。

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
       Mat img(300, 300, CV_8UC3, Scalar(155, 155, 0));
       Mat copyImg1(img);//拷贝构造函数,浅拷贝

       putText(copyImg1, "test", Point(10, 30), FONT_HERSHEY_SIMPLEX, 1, Scalar::all(0));
       imshow("srcImg", img);
       imshow("copyImg1", copyImg1);
       waitKey(0);
       return 0;
}

以上这段代码,我们通过Mat的拷贝构造函数把原图img复制给copyImg1,然后再对copyImg1做一些操作(此处,用putText()函数在copyImg1上写一行字),最后显示出来,结果如下:
这里写图片描述

可以看到,明明只是对copyImg1进行了操作,但是原图显示的结果也输出了一行文字,可见copyImg1和img其实共享同一个矩阵,这是因为OpenCV中使用了引用计数机制。

那么,如果把拷贝构造函数替换成clone()copyTo()函数,即

把 Mat copyImg1(img);//拷贝构造函数,浅拷贝
替换成为
Mat copyImg1 = img.clone();
或
Mat copyImg1;
img.copyTo(copyImg1);

测试结果如下:
这里写图片描述

可见,对copyImg1的操作不影响原img,也就是说,clone()和copyTo()函数是对原图像的深拷贝。

【常用的数据结构和函数】

1、点的表示:Point类

Point类表示二维坐标系下的点,用法如下:

Point pt(3, 4);

Point pt;
pt.x = 3;
pt.y = 4;

初学者需要理解的是,在OpenCV中,有如下定义:

typedef Point_<int> Point2i;
typedef Point2i Point;
typedef Point_<float> Point2f;
...

所以,Point_<int>Point2iPoint是等价的…

2、颜色的表示:Scalar类

上面有讲,不再赘述。

3、尺寸的表示:Size类

常用的方法如下:

Size sz(100,50);//width为100,height为50

cout << "sz = " << sz <<endl;
打印的结果为:
sz = [100 x 50]

需要了解的是,Size类的定义是这样子的:

typedef Size_<int> Size2i;
typedef Size2i Size;
...

其中,Size_是一个模板类,这个Size_类里面又重载了一些构造函数,定义了一些方法(如计算尺寸面积的函数area())。

4、矩形的表示:Rect类

Rect类的成员变量有x,y,width,height,分别表示左上角点的坐标和矩形的宽和高,如图:
这里写图片描述
Rect类的构造方法有

Rect() 
Rect(double[] vals) 
Rect(int x, int y, int width, int height) //常用 
Rect(Point p1, Point p2) //常用
Rect(Point p, Size s) 

Rect类常用的方法有:

double area() //面积
Point br() //bottom-right右下角
Rect clone() 
boolean contains(Point p) //判断点p是否在矩形内
boolean inside(Rect rect) //判断矩形rect是否在矩形内 
Size size() //格式为[width*height]
Point tl() //top-left左上角

此外,神奇的是:如果想求两个矩形的交集和并集,可以用如下形式:

Rect rect3 = rect1 & rect2;
Rect rect4 = rect1 | rect2;

如果想让矩形进行平移或缩放操作,可以这样写:

rect1 = rect1 + Point(20,20);
rect1 = rect1 + Size(35,70);

示例:

#include <opencv2/core/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace std;
int main()
{
       cv::Mat image = cv::imread("E:/image/dog.jpg");
       cv::imshow("result1", image);
       cout << "image.size() = " << image.size() << endl;
       cv::Rect rect1(100, 50, 300, 150);
       //cv::Rect rect1(cv::Point(100, 50), cv::Point(400, 200));
       cout << "rect1 = " << rect1 << endl;
       cout << "rect1.area() = " << rect1.area() << endl;
       cout << "rect1.br() = " << rect1.br() << endl;//右下角
       cout << "rect1.tl() = " << rect1.tl() << endl;//左上角
       cout << "rect1.size() = " << rect1.size() << endl;
       cv::Mat roi;
       //roi = image(rect1);
       image(rect1).copyTo(roi);
       cv::imshow("result2", roi);
       cv::waitKey(0);
       return 0;
}

结果:
这里写图片描述

【基本绘图函数】

1、画矩形
void cv::rectangle
(
InputOutputArray img,
Point pt1,              //左上角
Point pt2,              //右下角
const Scalar & color,
int thickness = 1,
int lineType = LINE_8,
int shift = 0 
)
或
void cv::rectangle
(
Mat & img,
Rect rec,
const Scalar & color,
int thickness = 1,
int lineType = LINE_8,
int shift = 0 
)
2、画圆形
void cv::circle
(
InputOutputArray img,
Point center,
int radius,
const Scalar & color,
int thickness = 1,
int lineType = LINE_8,
int shift = 0 
)
3、画椭圆官方文档
void cv::ellipse
(
InputOutputArray img,          
Point center,            //椭圆的中心点
Size axes,               //椭圆对应的矩形的大小
double angle,            //椭圆主轴相对于x轴的角度
double startAngle,       //椭圆线的起点
double endAngle,         //椭圆线的终点
const Scalar & color,    //线条的颜色
int thickness = 1,       //线条宽度
int lineType = LINE_8,   //线条类型(不用管)
int shift = 0 
)

对应下图来理解个参数的含义(图片来自官方文档)
这里写图片描述

示例:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
const int WIN_WIDTH = 400;
int main()
{
       Mat img(WIN_WIDTH, WIN_WIDTH, CV_8UC3, Scalar(255, 255, 255));

       double angle = 30;
       int thickness = 2;
       int lineType = 8;
       ellipse(img, Point(WIN_WIDTH / 2, WIN_WIDTH / 2), Size(WIN_WIDTH / 4, WIN_WIDTH / 8), angle, 0, 360, Scalar(0, 0, 0), thickness, lineType);

       Rect rect(100, 100, 200, 200);
       rectangle(img, rect, Scalar(0, 0, 0), thickness, lineType);
       int r = WIN_WIDTH / 20;
       circle(img, Point(WIN_WIDTH / 2, WIN_WIDTH / 2), r, Scalar(0, 0, 0), thickness, lineType);
       imshow("img", img);
       waitKey(0);
       return 0;
}

结果:
这里写图片描述

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:2464次
    • 积分:252
    • 等级:
    • 排名:千里之外
    • 原创:24篇
    • 转载:1篇
    • 译文:0篇
    • 评论:0条