第一章_图像编程入门

1 篇文章 0 订阅
1 篇文章 0 订阅
这篇博客介绍了OpenCV的基础操作,包括如何使用OpenCV在C++环境中配置环境,加载、显示和存储图像。文章详细解释了cv::Mat数据结构,包括其属性、引用计数机制以及如何创建。还提到了图像处理的基本操作,如图像翻转,并展示了如何在图像上进行绘制。最后,通过实例展示了cv::Mat的不同创建方法。
摘要由CSDN通过智能技术生成

1.1 openCv简介

  • 官方文档地址:https://docs.opencv.org/master/index.html

    其中包含C++,python等多种语言版本的文档

  • opencv+visual studio环境配置:https://docs.opencv.org/master/dd/d6e/tutorial_windows_visual_studio_opencv.html(官方)

1.2 装载、显示和存储图像

  • 实现过程
//引入所需类和函数的头文件
#include <opencv2/core.hpp>  //core.hpp包含图像数据结构的核心头文件
#include <opencv2/highgui.hpp> //highgui.hpp包含了所有图形接口函数头文件
#include<iostream> //标准输入输出头文件

int main() {
	cv::Mat image; // 定义一个Mat类对象
	std::cout << "This image is " << image.rows << " x "
		      << image.cols << std::endl; //访问Mat类对象的属性
	image = cv::imread("壁纸1.jpg"); //读取输入图像

	//判断图像读取是否正确
	if (image.empty()) {
		return -1;
	}

	cv::namedWindow("original image"); //定义一个窗口
	cv::imshow("original image", image); //让图像在指定的窗口中显示出来

	cv::Mat result; //创建另外一个空的图像
	cv::flip(image, result, 0); //对图像进行翻转// 正数表示水平
												// 0 表示垂直
												// 负数表示水平和垂直
	cv::namedWindow("Output Image"); // 输出窗口
	cv::imshow("Output Image", result);
	cv::waitKey(0); //0 表示永远地等待按键, 键入的正数表示等待的毫秒数

    cv::imwrite("output.bmp", result); // 保存结果
	return 0;
}
  • 实现原理

命名空间 cv:

在OpenCV 的C++ API 中,所有类和函数都在命名空间cv 内定义。

访问它们的方法共有两种,第一种是在定义main 函数前使用如下声明:using namespace cv;

第二种方法是根据命名空间规范给所有OpenCV 的类和函数加上前缀:cv::

图像读入:

// 读入一个图像文件并将其转换为灰度图像
image= cv::imread("puppy.bmp", CV::IMREAD_GRAYSCALE);

// 读取图像,并将其转换为三通道彩色图像
image= cv::imread("puppy.bmp", CV::IMREAD_COLOR);

std::cout << "This image has "
<< image.channels() << " channel(s)"; //可用channels 方法检查图像的通道数
  • 在图像上点击、在图像上绘图(具体查阅官方文档)

通过编程,你可以让鼠标在置于图像窗口上时运行特定的指令。要实现这个功能,需定义一个合适的回调函数??

OpenCV 还提供了几个用于在图像上绘制形状和写入文本的函数。基本的形状绘制函数有circle、ellipse、line 、rectangle??

1.3 cv::Mat数据结构

  • cv::Mat数据结构的不同属性

.cols.rows

  • cv::Mat 类的组成

矩阵头:包括矩阵尺寸、存储方法、存储地址等信息

指针:指向存储所有像素值的矩阵,矩阵的维度取决于选择的存储方法

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

  • 引用计数机制

每个 Mat 对象都有自己的信息头,但是通过让矩阵指针指向相同的地址,可以在两个Mat对象之间共享矩阵。此外,拷贝构造函数和赋值运算符只会复制信息头和指向大矩阵的指针而不是数据本身

cv::Mat A, C; //只创建信息头部分
A = cv::imread("壁纸1.jpg", cv::IMREAD_COLOR); //分配矩阵
cv::Mat B(A); //使用拷贝构造函数
C = A; //使用赋值运算符

以上代码所有对象都最终指向同一个数据矩阵,使用它们中的任何一个进行修改也会影响所有其他对象。 实际上,不同的对象只是为相同的底层数据提供了不同的访问方法,尽管它们的信息头是不同的。真正有趣的部分是您可以创建仅引用完整数据的一部分的信息头,比如想要创建一个感兴趣区域(ROI),只需要创建包含边界信息的信息头:

Mat D (A, Rect(10, 10, 100, 100) ); // 使用矩阵来界定 using a rectangle
Mat E = A(Range::all(), Range(1,3)); //使用行和列来界定 using row and column boundarie

**引用计数机制概念:**无论什么时候复制一个Mat对象的信息头,计数器将会加1;当一个信息头被释放时,计数器将会减1;当计数值为0时,矩阵将会被清理。

有时你也想复制矩阵本身,所以 OpenCV 提供了 **cv::Mat::clone() **和 **cv::Mat::copyTo() **函数,如下所示:

cv::Mat F = A.clone(); //复制A给F,包含矩阵本身
cv::Mat G;
A.copyTo(G);//复制A给G,包含矩阵本身

现在修改 F 或 G 不会影响 A信息头指向的矩阵。 你需要记住的是:

  • OpenCV 函数中输出图像的内存分配是自动的(除非另有说明)。

  • 您无需考虑使用 OpenCV 的 C++ 接口进行内存管理。

  • 赋值运算符和复制构造函数只复制信息头和矩阵指针。

  • 可以使用 cv::Mat::clone() 和 cv::Mat::copyTo() 函数复制图像的底层矩阵。

1.4 cv::Mat的创建

  • cv::Mat的显式创建
#include <opencv2/core.hpp>  //core.hpp包含图像数据结构的核心头文件
#include <opencv2/highgui.hpp> //highgui.hpp包含了所有图形接口函数头文件
//引入所需类和函数的头文件

int main() {
	cv::Mat image1(240, 320, CV_8U, 100);
	//创建一个240行x320列的新图像
	// CV_8U指定每个矩阵元素的类型
	// 100表示灰度值

	cv::Mat image2(240, 320, CV_8UC3, cv::Scalar(0, 0, 255));
	// 创建一个红色图像,通道次序是BGR
	// CV_8UC3,表示8位,无符号,通道数为3
	//初始化灰度图像可这样使用这个数据结构:cv::Scalar(100)

	cv::Mat image3(cv::Size(320, 240), CV_8UC3);
	// 创建一个未初始化的彩色图像
	// cv::Size()结构包含了矩阵的高度和宽度

	image1.create(200, 200, CV_8U);//使用create方法分配或重新分配图像的数据
	//(仅在大小或类型不同时)重新分配

	cv::Mat image4(image3);  //拷贝构造函数
	image1 = image3; //赋值运算符
	// 所有图像都指向同一个数据块

	image3.copyTo(image2);
	cv::Mat image5 = image3.clone();
	// 这些图像是原始图像的新副本

	image1.convertTo(image2, CV_32F, 1 / 255.0, 0.0);
	//将image1转换为浮点型图像[0,1],image2为转换的结果

	return 0;
}
  • OpenCV中还有几个与cv::Mat相关的类

输入和输出数组

在OpenCV 的文档中,很多方法和函数都使用cv::InputArray 类型作为输入参数。因为它是一个输入数组,所以你必须确保函数不会修改这个数据结构。

此外还有一个代理类cv::OutputArray,用来指定某些方法或函数的返回数组。

处理小矩阵

开发应用程序时,你可能会遇到需要处理小矩阵的情况,这时就可以使用模板类cv::Matx和它的子类

// // 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;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值