头文件:
定义了图像数据结构的核心头文件和包含了所有图形接口函数的 highgui 头文件:
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
cv::Mat image; // 创建一个空图像
//这个定义创建了一个尺寸为 0×0 的图像,
//可以通过访问 cv::Mat 的 size 属性来验证这一点:
image= cv::imread("puppy.bmp"); // 读取输入图像
图像行数:image.rows
图像列数:image.cols
检查图像是否读入:
if (image.empty()) {
// 未创建图像……
// 并退出程序
...
}
如果没有分配图像数据, empty 方法将返回 true。
// 定义窗口(可选)
cv::namedWindow("Original Image");
// 显示图像
cv::imshow("Original Image", image);
水平翻转图像的简单函数:flip
cv::Mat result; // 创建另一个空的图像
cv::flip(image,result,1);
// 正数表示水平
// 0 表示垂直
// 负数表示水平和垂直
在另一个窗口显示结果:
cv::namedWindow("Output Image"); // 输出窗口
cv::imshow("Output Image", result);
等待函数:cv::waitKey(0); // 0 表示永远地等待按键 // 键入的正数表示等待的毫秒数
保存图像:cv::imwrite("output.bmp", result); // 保存结果
imread函数可以直接导入一张灰色图像。
// 读入一个图像文件并将其转换为灰度图像
image= cv::imread("puppy.bmp", CV::IMREAD_GRAYSCALE);
// 读取图像,并将其转换为三通道彩色图像
image= cv::imread("puppy.bmp", CV::IMREAD_COLOR);
在这样创建的图像中,每个像素有 3 字节, OpenCV 中用 CV_8UC3 表示。当然了,如果输入的图像文件是灰度图像,这三个通道的值就是相同的。
通道数:image.channels()
当你用 imshow 显示由整数( CV_16U 表示 16 位无符号整数, CV_32S 表示 32 位有符号整数)构成的图像时,图像每个像素的值会被除以 256,以便能够在 256 级灰度中显示。同样,在显示由浮点数构成的图像时,值的范围会被假设为 0.0(显示黑色) ~1.0(显示白色)。超出这个范围的值会显示为白色(大于 1.0 的值)或黑色(小于 0.0 的值)。
1图像上点击,需要重新学
在这里插入代码片
- 在图像上绘图
cv::putText(image, // 目标图像
"This is a dog.", // 文本
cv::Point(40,200), // 文本位置
cv::FONT_HERSHEY_PLAIN, // 字体类型
2.0, // 字体大小
255, // 字体颜色(这里用白色)
2); // 文本厚度
画⚪
cv::circle(image, // 目标图像
cv::Point(155,110), // 中心点坐标
65, // 半径
0, // 颜色(这里用黑色)
3); // 厚度
基本的形状绘制函数有 circle、 ellipse、 line 和 rectangle。
深入了解 cv::Mat
// 创建一个 240 行×320 列的新图像
cv::Mat image1(240,320,CV_8U,100);//CV_8UC1都是代表单通道
我们需要指定每个矩阵元素的类型,这里用 CV_8U 表示每个像素对应 1 字节(灰度图像),用字母 U 表示无符号;你也可用字母 S 表示有符号。对于彩色图像,你应该用三通道类型( CV_8UC3),也可以定义 16 位和 32 位的整数(有符号或无符号),例如 CV_16SC3。我们甚至可以使用 32 位和 64 位的浮点数(例如 CV_32F)。
图像(或矩阵)的每个元素都可以包含多个值(例如彩色图像中的三个通道),因此 OpenCV引入了一个简单的数据结构 cv::Scalar,用于在调用函数时传递像素值。该结构通常包含一个或三个值。如果要创建一个彩色图像并用红色像素初始化,可用如下代码:
// 创建一个红色图像
// 通道次序是 BGR
cv::Mat image2(240,320,CV_8UC3,cv::Scalar(0,0,255));
与之类似,初始化灰度图像可这样使用这个数据结构: cv::Scalar(100)
// 创建一个未初始化的彩色图像
cv::Mat image2(cv::Size(320,240),CV_8UC3);
总结:如何创建图像
cv::Mat image2(cv::size(100,100),......)
cv::Mat image2(100,100,.....);//和上一个一样
cv::Mat image2(.....,cv::scalar(0,0,255))
cv::Mat image2(.....,0,0,255)//和上一个效果一样
CV8U=CV8UC1//代表单通道
// 所有图像都指向同一个数据块
cv::Mat image4(image3);
image1= image3;
这些是浅复制,改变 image1的值 会影响image3
// 这些图像是原始图像的新副本
image3.copyTo(image2);
cv::Mat image5= image3.clone();
深复制,改变image2,不影响 image3
如果你需要把一幅图像复制到另一幅图像中,且两者的数据类型不一定相同,那就要使用convertTo 方法了:
```cpp
关于opencv中的浅拷贝与深拷贝大家众所周知,这里先赘述一下
(1)浅拷贝:
Mat B;
B = image // 第一种方式
Mat C(image); // 第二种方式
这两种方式称为浅copy,是由于它们有不同的矩阵头,但是它们共享内存空间,即指向一个矩阵。当图像矩阵发生变化时,两者相关联,都会变化。
(2)深拷贝
Mat B,C;
B = image.clone(); // 第一种方式
image.copyTo(C); // 第二种方式
深拷贝是真正的copy了一个新的图像矩阵,此时image,B,C三者相互没有影响
// 转换成浮点型图像[0,1]
image1.convertTo(image2,CV_32F,1/255.0,0.0);
注意的是,这两幅图像的通道数量必须相同
**处理小矩阵**
// // 3×3 双精度型矩阵
cv::Matx33d matrix(3.0, 2.0, 1.0,
2.0, 1.0, 3.0,
1.0, 2.0, 3.0);
// 3×1 矩阵(即向量)
cv::Matx31d vector(5.0, 1.0, 3.0);
// 相乘
cv::Matx31d result = matrix*vector;
这些矩阵可以进行常见的数学运算
定义感兴趣区域
cv::Mat imageROI(image,
cv::Rect(image.cols-logo.cols, // ROI 坐标
image.rows-logo.rows,
logo.cols,logo.rows)); // ROI 大小
注意:上个函数是浅复制
// 插入标志
logo.copyTo(imageROI);
ROI 还可以用行和列的值域来描述。值域是一个从开始索引到结束索引的连续序列(不含开
始值和结束值),可以用 cv::Range 结构来表示这个概念。因此,一个 ROI 可以用两个值域来
定义。本例中的 ROI 也可以定义为:
imageROI= image(cv::Range(image.rows-logo.rows,image.rows),
cv::Range(image.cols-logo.cols,image.cols));
MASK
// 在图像的右下角定义一个 ROI
imageROI= image(cv::Rect(image.cols-logo.cols,
image.rows-logo.rows,
logo.cols,logo.rows));
// 把标志作为掩码(必须是灰度图像)
cv::Mat mask(logo);
// 插入标志,只复制掩码不为 0 的位置
logo.copyTo(imageROI,mask);