欢迎各位来到小白 p i a o 的学习空间! \color{red}{欢迎各位来到小白piao的学习空间!} 欢迎各位来到小白piao的学习空间!
持续更新,期待关注! \color{blue}{持续更新,期待关注!} 持续更新,期待关注!
目前已经为大家更新了: \color{green}{目前已经为大家更新了:} 目前已经为大家更新了:
Python基础、中级、高级;
C++数据结构和算法;
Python数据结构和算法;
OpenCV相关内容等重点内容(以前只有C++,现在同时为大家更新Python的相关内容)
我的主页: \color{purple}{我的主页:} 我的主页:我的主页
我的资源: \color{purple}{我的资源:} 我的资源:我的资源
最近工作忙碌,一直没有出来给大家更新有关OpenCV的内容了,十分抱歉!经过和领导的 浴血奋战 \color{red}{浴血奋战} 浴血奋战 ,我终于战胜了领导成为了一位独立创作人【哈哈哈,真TM有趣】。最近呢,开始着手新一轮的更新,大家可以随时关注我的动态和私信哦。
今天为大家加深一下理解,给各位奉上一场视觉盛宴-----Mat对象精讲!!!
前文链接:【C++的OpenCV】第十二课-OpenCV图像常用操作(九):找到图像的边界(轮廓)findContours()和drawContours()
计算机视觉中的图像是由计算机生成或处理得出的数字图像,而现实世界中的图像是由物理现象通过光学设备传到人眼或摄像头中的图像。其主要区别在于:
图像在计算机中通常以 数字化 的方式存储,即 将图像转换为数字信号 。具体来说,图像被分成 像素 \color{red}{像素} 像素 ,每个像素都有一个颜色值或灰度值。每个颜色值或灰度值都表示为一个数字,通常是8bit整数,即0到255之间的一个数。 这些数字被编码并存储在计算机内存或磁盘上,形成一个数字矩阵,其中每个数字代表一个像素的颜色或灰度值。这个数字矩阵可以被计算机读取和处理,以进行图像编辑、图像处理、图像增强等应用。常见的图像格式包括JPEG、PNG、GIF、BMP等。
像素是指组成图像的小方格,这些小方块都有一个明确的位置和被分配的色彩数值,小方格颜色和位置就决定该图像所呈现出来的样子。
一个像素中容纳的其实是一个或者一组色彩亮度值。先给大家一些提示:
分辨率指的是图像文件的像素数目,通常以横向像素数×纵向像素数来表示。分辨率越高,图片越清晰,细节表现更为丰富,但相应的文件大小也会增加。分辨率决定了图像的清晰度和可见细节,因此在选择摄影设备、打印设备或屏幕显示设备时,需要考虑达到所需分辨率的要求。
图像的通道数是指图像中可以分离出的独立信息的数量(重点,后边会有详细解释split和merge)。在彩色图像中,通常包含红色、绿色和蓝色(Red\Green\Blue)三个通道。这三个通道合称为RGB通道。每个像素都有三个值,它们代表着同一位置上红、绿、蓝三个颜色通道的亮度值。在灰度图像中,只有一个通道,每个像素只有一个亮度值。在一些特殊的图像处理任务中,会使用更多的通道来表示其他信息,例如alpha通道、深度通道或法线通道等。
我们再沿用一下前边使用过的一张图片,这样大家就理解的更透彻了。
其实彩色图像很好理解,也很常见,通常我们常见的是RGB模式的彩色图,即一个像素点上的色彩由三个通道(R通道、G通道、B通道)的值组合而成后表达。
灰度图就更加简单了,我们前边说了,一个像素点中可以有一组值,或者一个值,而一组值的就是类似RGB这中的彩色图像的值,如果假设,R=G=B,即一个像素上就变成了一个值!那这种一个像素有一个值的图像,称之为灰度图,灰度图对计算机视觉中图像处理的帮助是非常大的!简而言之,非常好理解,一个像素上只有一个值的图像,就是灰度图。
![在这里插入图片描述](https://img-blog.csdnimg.cn/8aebeaf7cf3a42b69b74e43ee586b918.webp
在OpenCV中,Mat是一个多维数组(矩阵)类(Matrix就是矩阵的意思,这里取其前三个字母),可以用于存储和处理图像和其他类型的数据。Mat类提供了许多有用的方法和操作符,使得图像和矩阵的处理更加容易和高效。它可以存储任意类型的数据,因此可以用于处理灰度图像、彩色图像和其他类型的数据。Mat类的使用也是OpenCV编程中非常重要的一部分。
问题来了,矩阵这玩意和咱们的图像有啥关系,看下边这幅图:
前边说了,图像保存在磁盘中就是以一组数字保存的,那么这组数字要能够合理表达图像,就得有一定结构,那这里不难发现上边的灰度图的每个像素其实就是一个值,这个值就表达灰色的亮度值,那这种灰度图数据,什么数据结构最好形象的表达出来呢?盯住红色框,不妨往下看:
arr = [
[101 89 110 101 98 99 103 123]
[100 67 98 95 89 95 99 110]
[101 56 87 89 87 93 95 97]
[96 65 76 78 85 89 91 92]
[67 56 67 78 74 83 86 86]
[56 54 65 76 76 78 82 83]
[67 34 56 56 73 74 79 79]
[56 45 54 45 65 68 73 75]
]
我竟然会变态到把这个东西手敲一遍。。。发现了吗,这种结构是不是特别适合保存图像数据,而这,就是矩阵,只不过用Python代码写的,大家别介意,毕竟这语言变态就变态在易读性上,不妨借过来用一用。总而言之,矩阵当之无愧。(说白了,Mat存图像贼牛!)
// 其实这里分为两大类:
// 1、创建
#include
#include
#include
using namespace cv;
int main()
{
//demo1:
Mat m;
m.create(Size(3,2), CV_32FC(1)); // 注意:这是构造一个2行3列的矩阵!Size(列,行)!!!一定记住喽!!!
Mat n = Mat::zeros(Size(3,2), CV_32FC1);// 元素值都是0的矩阵
Mat o = Mat::ones(Size(3,2), CV_32FC1);// 元素值都是1的矩阵
Mat p = (Mat_(2,3) << 1,2,3,4,5,6);
std::cout << p << std::endl;
return 0;
}
// 这是另外一块代码:
// 2、从内存中读取(这个和我讲的知识点暂时没关系,也希望你们不要把注意力放在一个接口的使用上,毕竟你需要成长)
#include
#include
#include
using namespace cv;
int main()
{
//demo2:
Mat img = imread("image.jpg");
if (!img.data)
{
return -1;
}
imshow("test", img);
waitKey(0);
std::cout << "hello world!\n";
return 0;
}
上述的demo1代码当中出现了一个参数:CV_32FC(1) 或者CV_32FC1,这是什么?
其中这个32F :就是代表像素中的每一个值是32位的浮点值。其中还有很多种类:8U 8S 16U 16S 32F 32S 64F ,其中,数字代表每个数字所占的bit位,U代表uchar类型,F代表float或者double(64F中的F),S代表int。
其中这个C1或者C(1),是一样的,C是Channel,通道的意思,后边的1是通道数,常见的组合有:C(同C1) , C1, C3 … 但其实,通道数可以为n。当n=1时,矩阵为二维矩阵(单通道矩阵),当n>1时,矩阵为三维矩阵(多通道矩阵),是不是有点迷糊了?为什么1代表二维矩阵?而大于1确实三维矩阵?为什么二维矩阵是单通道矩阵?而三维矩阵却成了多通道矩阵了??? 懵逼了吧?引发了一连串的“已放弃,核心已转储”吧?哈哈,不妨接着往下看!
首先,这里的维度,不是指二维图像和三维图像,而是矩阵的维度!所以二维矩阵不代表二维图像,三维矩阵更不代表三维图像!
第二,我们前边反复提到一个概念,一个像素中存储的是一个表示颜色的值,或者一组表示颜色的值,如果一个像素存一个值(单通道),这就是灰度图;换而言之,如果一个像素中存储三个值(三通道,例如:RGB三通道)表示该像素颜色的亮度,则这个图像就是彩色图像。
最后,我们再来讨论,众所周知,所有的图像都具备宽和高(国人口中的长和宽),最起码一张图像得有长和宽,所以,矩阵为了更好的存储图像,即至少是个二维矩阵(只有二维矩阵可以描述行和列)。而烧脑的地方来了,让我们联系第二点,整合一下思路!
简而言之!通道到底是什么?是像素中 表达颜色的值 的个数!灰度图(单通道)中每个像素只有一个值表示颜色;彩色图(例如RGB模式,三通道),每个像素中表达颜色的值却是3个!你理解了吗?
所以呀,再提炼一下!看下图,一看就懂!
[
[108 70 32]
[201 233 201]
[111 134 254]
]
[
[ [255 2 32] [101 34 243] 。。。 ]
[ [103 23 233] [47 0 1] 。。。 ]
。。。 。。。 。。。
]
// 偷偷说一句:可以理解为宽、高、像素点(一个值【单通道】、三个值【多通道】.....)
是不是豁然开朗了?
#include
#include
#include
using namespace cv;
int main()
{
//demo3:
Mat m = (Mat_(3,2) << 11, 12, 33, 42, 23, 53); // 模板构造 3行2列矩阵
std::cout << "行数:" << m.rows << std::endl; // 行数:3
std::cout << "列数:" << m.cols << std::endl; // 列数:2
return 0;
}
#include
#include
#include
using namespace cv;
int main()
{
Mat m = (Mat_(3, 2) << 11, 12, 33, 42, 23, 53);
Size size = m.size();
std::cout << "尺寸:" << size << std::endl; //Size()对象提供很好的易读性显示的结果:尺寸:[2 x 3]
return 0;
}
int main()
{
Mat m = (Mat_(3, 2) << 11, 12, 33, 42, 23, 53);
std::cout << "通道数:" << m.channels() << std::endl; //通道数:1
return 0;
}
int main()
{
Mat m = (Mat_(3, 2) << 11, 12, 33, 42, 23, 53);
std::cout << "像素个数:" << m.totals() << std::endl; //像素个数:6
//知道totals()是干嘛的了吧?
return 0;
}
int main()
{
Mat m = (Mat_(3, 2) << 11, 12, 33, 42, 23, 53);
std::cout << "矩阵维数:" << m.dims << std::endl; //矩阵维数:2
//注意:这是个变量!不是方法!
return 0;
}
点点滴滴的积累终成江河湖海,下次内容我们继续往后介绍《单通道值的访问方法》和《多通道矩阵基本操作》,大家做好准备哦。
持续更新,期待关注! \color{blue}{持续更新,期待关注!} 持续更新,期待关注!