课程视频:https://www.bilibili.com/video/av29600072?p=4
内容
- Mat 对象与 IplImage 对象
- Mat 对象使用
- Mat 定义数组
1. Mat 对象与 IplImage 对象
- Mat 对象是 OpenCV 2.0 之后引入的图像数据结构,自动分配内存、不存在内存泄漏的问题,是面向对象的数据结构。分了两部分,头部和数据部分。
- IplImage 是从 2001 年 OpenCV 发布之后就一直存在,是 C 语言风格的数据结构,需要开发者自己分配和管理内存,对大的程序使用它容易导致内存泄漏问题。
- IplImage 可以转换为 Mat
2. Mat 对象构造函数与常用方法
2.1 Mat 对象构造函数
- Mat()
- Mat(int rows, int cols, int type)
- Mat(Size size, int type)
- Mat(int rows, int cols, int type, const Scalar &s)
- Mat(Size size, int type, const Scalar &s)
- Mat(int ndims, const int *sizes, int type)
- Mat(int ndims, const int *sizes, int type, const Scalar &s)
- ······
2.2 Mat 对象常用方法
- void copyTo(Mat mat)
- Mat clone()
- void convertTo(Mat dst, int type)
- int channels()
- int depth()
- bool empty()
- uchar* ptr(i=0)
- ······
2.3 Mat 对象创建
- cv::Mat::Mat 构造函数
cv::Mat M(300, 300, CV_8UC3, cv::Scalar(0, 255, 0));
其中前两个参数分别表示行(row)和列(column),第三个参数 CV_8UC3 中的 8 表示每个通道占 8 位、U 表示无符号、C 表示 char 类型、3 表示通道数目是 3,第四个参数是向量表示初始化每个像素值是多少,Scalar 中的数目可以小于也可以大于通道数,不足的部分会直接默认为 0,多余的部分直接忽略,例如:
(300, 300, CV_8UC3, scalar(0, 255))
等价于
(300, 300, CV_8UC3, scalar(0, 255, 0))
cv::Mat dst1(300, 300, CV_8UC3, cv::Scalar(0, 255));
结果
故创建灰度图像,即单通道图像为
cv::Mat dst1(300, 300, CV_8UC1, cv::Scalar(100));
结果
- 创建多维数组 cv::Mat::create
int main(int argc, char** argv)
{
cv::Mat dst1;
dst1.create(10, 10, CV_8UC2);
dst1 = cv::Scalar(127, 10);
std::cout << dst1 << std::endl;
cv::waitKey(0);
return 0;
}
结果
2.4 Mat 对象复制
- 部分复制:一般情况下只会复制 Mat 对象的头和指针部分,不会复制数据部分:
cv::Mat A = cv::imread(imageFile);
cv::Mat B(A);
这意味着当修改了 A 或 B 中任意一个,另一个的内容也会改变。
- 完全复制:如果想把 Mat 对象的头部和数据部分一起复制,可以通过如下两个 API 实现。
cv::Mat dst = image.clone();
或
cv::Mat dst;
image.copyTo(dst);
- 输出图像的内存是自动分配的,不需要考虑内存分配的问题。
2.5 定义小数组
cv::Mat dst1 = (cv::Mat_<double>(2, 2) << 0, -1, 2, 3);
结果
2.6 初始化零矩阵
cv::Mat dst1 = cv::Mat::zeros(image.size(), image.type());
2.7 初始化单位矩阵
cv::Mat dst1 = cv::Mat::eye(3, 3, CV_8UC1);
3. 示例代码
3.1 Scalar
可对图像中的每个元素赋相同的值。
int main(int argc, char** argv)
{
cv::Mat image = cv::imread(cv::samples::findFile("HappyFish.jpg"), cv::IMREAD_COLOR);
cv::namedWindow("Original", cv::WINDOW_AUTOSIZE);
cv::imshow("Original", image);
cv::Mat dst;
dst = cv::Mat(image.size(), image.type());
dst = cv::Scalar(0, 0, 0);
cv::namedWindow("New Image", cv::WINDOW_AUTOSIZE);
cv::imshow("New Image", dst);
cv::waitKey(0);
return 0;
}
结果
生成了一幅尺寸和类型与原图像相同的每个元素都是 (0, 0, 0)黑色 的图像。
3.2 Mat clone()
此函数的作用是完全拷贝,将一幅图像克隆到目标图像。
int main(int argc, char** argv)
{
cv::Mat image = cv::imread(cv::samples::findFile("HappyFish.jpg"), cv::IMREAD_COLOR);
cv::namedWindow("Original", cv::WINDOW_AUTOSIZE);
cv::imshow("Original", image);
cv::Mat dst;
dst = image.clone();
cv::namedWindow("New Image", cv::WINDOW_AUTOSIZE);
cv::imshow("New Image", dst);
cv::waitKey(0);
return 0;
}
结果
clone() 是完全的数据拷贝,新图像与原图像完全相同
3.3 void copyTo(Mat mat)
此函数也是用于拷贝图像,将原图像拷贝到目标图像。
int main(int argc, char** argv)
{
cv::Mat image = cv::imread(cv::samples::findFile("HappyFish.jpg"), cv::IMREAD_COLOR);
cv::namedWindow("Original", cv::WINDOW_AUTOSIZE);
cv::imshow("Original", image);
cv::Mat dst;
image.copyTo(dst);
cv::namedWindow("New Image", cv::WINDOW_AUTOSIZE);
cv::imshow("New Image", dst);
cv::waitKey(0);
return 0;
}
结果
3.4 int channels()
此函数用于查看图像的通道数。
int main(int argc, char** argv)
{
cv::Mat image = cv::imread(cv::samples::findFile("HappyFish.jpg"), cv::IMREAD_COLOR);
cv::namedWindow("Original", cv::WINDOW_AUTOSIZE);
cv::imshow("Original", image);
cv::Mat dst;
cv::cvtColor(image, dst, cv::COLOR_BGR2GRAY);
std::cout << "Original Image's Channels = " << image.channels() << std::endl;
std::cout << "New Image's Channels = " << dst.channels();
cv::namedWindow("New Image", cv::WINDOW_AUTOSIZE);
cv::imshow("New Image", dst);
cv::waitKey(0);
return 0;
}
结果