OpenCV-基本数据类型

OpenCV的基本数据类型

  1. 点(Point)
  2. 尺寸(Size)
  3. 矩形(Rect)
  4. 颜色(Scalar)
  5. 向量(Vec)
  6. 范围(Range)
  7. 矩阵(Mat)

点(Point)

Point 是图像中的点,其中Point_为2d(x,y),Point3_为3d(x,y,z)

类模板

1
2
template<typename _Tp       //类型
> class Point_, Point3_

成员函数

  1. dot()与ddot() - 点乘与高精度点乘
  2. cross()
    • 二维:a.cross(b) = a.x * b.y - a.y * b.x
    • 三维:a.cross(b) = Point3_(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.y)
  3. inside(m) - 仅用于二维点,判断是否在矩形m内

特性

二维 Point 可以强转为二维 Vec,三维 Point 可以强转为三维 Vec

尺寸(Size)

Size 是图像或者矩阵的宽和高

类模板

1
2
template<typename _Tp       //类型
> class Size_

成员函数

  1. area() - 面积
  2. aspectRatio() - 计算斜率(width / height)
  3. empty() - 是否为空

矩形(Rect)

Rect 构造一个矩形,设置位置以及宽高

类模板

1
2
template<typename _Tp       //类型
> class Rect_

成员函数

  1. area() - 矩形面积
  2. size() - 返回 Size(width, height)
  3. tl() - 返回左上的点
  4. br() - 返回右上的点
  5. empty() - 是否为空

颜色(Scalar)

Scalar 为画布的颜色通道值

类模板

1
2
template<typename _Tp
> class Scalar_ : public Vec<_Tp, 4>

特性

其中颜色顺序为 Blue,Green,Red

向量(Vec)

Vec 是多通道 Mat 的基础

类模板

1
2
3
template<typename _Tp,      //类型
int cn //长度
> class Vec

元素访问

(g) 与 [g] 访问 g 处的元素

通道分离与合并

分离(split)

1
2
3
4
5
6
/*
* m 多通道mat
* mv 接收分离的mat数组
*/
void split(InputArray m,
OutputArrayOfArrays mv);

实例

1
2
3
Mat mat = (Mat_<Vec3f>(2, 2) << Vec3f(1,11,111),Vec3f(2,22,222),Vec3f(3,33,333), Vec3f(4,44,444));
vector<Mat> v;
split(mat, v);

分离后的三个通道为[1, 2; 3, 4] [11, 22; 33, 44] [111, 222; 333, 444]

合并(merge)

1
2
3
4
5
6
/*
* mv 单通道通道mat数组
* dst 接收合并的多通道mat
*/
void merge(InputArrayOfArrays mv,
OutputArray dst);

实例

1
2
3
4
5
6
Mat mat1 = (Mat_<int>(2, 2) << 1, 11, 111, 1111);
Mat mat2 = (Mat_<int>(2, 2) << 2, 22, 222, 2222);
Mat mat3 = (Mat_<int>(2, 2) << 3, 33, 333, 3333);
vector<Mat> v = { mat1,mat2,mat3 };
Mat mat;
merge(v, mat);

合并后的 mat 为 [1, 2, 3; 11, 22, 33;
111, 222, 333; 1111, 2222, 3333]

范围(Range)

Range 可以用来表示矩阵多个连续的列或者行

Range表示的范围为一个从 start 到 end 的左闭右开的空间

且提供一个静态方法 all() 来表示所有的行和列

矩阵(Mat)

特点

1. 不再需要手动分配其内存,并在不需要时立即释放它

虽然这样做仍然是可能的,但大多数 OpenCV 函数会自动分配其输出数据。如果你传递一个已经存在的 Mat 对象,它已经为矩阵分配了所需的空间,这将是一个很好的奖励,它将被重用。换句话说,我们始终只使用执行任务所需的内存。

2. Mat 基本上是一个包含两个数据部分的类

1. 矩阵头(包含矩阵的大小、用于存储的方法、存储矩阵的地址等信息)
2. 指向包含矩阵的指针像素值(取任何维度取决于选择的存储方法)

矩阵头的大小是恒定的,但是矩阵本身的大小可能因图像而异,并且通常会大几个数量级。

3. 通过制作不必要的可能的大图像副本进一步降低程序的速度

为解决这个问题,OpenCV 使用引用计数系统。这个想法是每个 Mat 对象都有自己的头,但是通过使它们的矩阵指针指向相同的地址,矩阵可以在它们的两个实例之间共享。 此外,复制运算符只会复制头和指向大矩阵的指针,而不是数据本身

1
2
3
4
Mat A,C;
A = imread("fish.jpg");
Mat B(A); //使用复制构造函数
C = A; //赋值运算符

所有上述对象都指向同一个数据矩阵,使用它们中的任何一个进行修改也会影响所有其他对象。 在实践中,不同的对象只是向相同的底层数据提供不同的访问方法。然而,他们的头部不一样。真正有趣的部分是您可以创建仅引用完整数据的小节的标题。例如,要在图像中创建感兴趣区域(ROI),您只需创建一个新边界的新标题:

1
2
Mat D (A, Rect(10, 10, 100, 100));  //使用矩形构造
Mat E = A(Range::all(), Range(1,3));//使用行和列边界

每当一个对象复制Mat对象的头部时,矩阵的计数器就会增加。每当清理该对象时,此计数器就会减少。当计数器达到零时,矩阵被释放。

当想要复制矩阵本身时,就要用到 cv::Mat::clone() 和 cv::Mat::copyTo()

1
2
3
Mat F = A.clone();
Mat G;
A.copyTo(G);

现在修改F或G不会影响A的标题指向的矩阵。但需谨记:

  1. OpenCV 函数的输出图像分配是自动的(除非另有说明);
  2. 无需考虑使用 OpenCV 的 C++ 接口的内存管理;
  3. 赋值运算符和复制构造函数只复制标头;
  4. 可以使用cv::Mat::clone()和cv::Mat::copyTo()函数复制图像的底层矩阵。

成员变量及函数

  1. rows - 矩阵行数
  2. cols - 矩阵列数
  3. dims - 矩阵维数
  4. step - step[0]表示一行的长度,step[1]表示每一个数值的长度
  5. size() - 矩阵尺寸
  6. channels() - 矩阵通道数
  7. total() - 矩阵面积
  8. at()
    • 单通道:at<类型>(r,c),访问r行c列的值
    • 多通道:at(r,c),访问r行c列处的向量
  9. ptr() - 可以获得每一行地址的指针
  10. isContinuous() - 矩阵在存储时如果每一行在内存中没有间隔则返回true
  11. data() - 返回第一个数值的指针
  12. row() - 取某行
  13. col() - 取某列
  14. rowRange() - 取某个范围内的行
  15. colRange() - 取某个范围内的列