图像的本质是矩阵
OpenCV 使用 Mat
(矩阵类)作为图像和数据的基本数据结构,这是因为图像本质上是一种二维或多维的矩阵形式。
- 像素数据的表示: 图像可以看作一个二维矩阵,其中每个元素代表一个像素值。例如:
- 灰度图像:一个二维矩阵,每个像素只有一个值。
- 彩色图像:一个三维矩阵,第三个维度表示颜色通道(如 BGR)。
- 矩阵计算的需求: 图像处理中很多操作本质上是矩阵运算,比如卷积、像素操作、几何变换等。
Mat
是专为图像矩阵设计的类,可以方便地表示这些数据结构。
Mat
的高效内存管理
- 动态内存分配:
Mat
会自动管理图像数据的内存分配和释放,用户无需手动管理内存。 - 引用计数:
Mat
使用引用计数技术,共享底层数据存储。当多个Mat
对象引用同一块数据时,不会重复分配内存,而是通过引用计数器跟踪资源的使用情况。
支持多维数据
Mat
不仅支持二维数据,还可以支持多维矩阵,适合处理:
- 高维数据(如科学计算中的张量)。
- 视频帧序列(多帧图像堆叠为三维矩阵)。
数据结构灵活性
Mat
提供了丰富的功能以适应各种需求:
- 支持多种数据类型(如
CV_8UC1
、CV_32FC3
)。 - 提供子矩阵和感兴趣区域(ROI)的操作,而不需要复制数据:cpp复制代码
cv::Mat roi = image(cv::Rect(50, 50, 100, 100)); // 提取感兴趣区域
- 支持各种通道数(单通道、三通道、四通道等)。
强大的接口支持
Mat
提供了很多成员函数,便于用户直接操作图像数据。例如:clone()
:复制图像数据。zeros()
、ones()
:创建全零或全一矩阵。at<T>()
:访问矩阵中的特定元素。- 转换类型、大小、通道等的操作函数。
高效的兼容性和扩展性
- 与 OpenCV 算法无缝集成: OpenCV 中的所有图像处理算法都以
Mat
作为输入和输出。 - 与第三方库的兼容:
Mat
可以轻松转换为其他库的数据格式,如 NumPy 数组(在 Python 中)或 Eigen 矩阵(在 C++ 中)。 Mat
的设计继承了 OpenCV 的早期版本IplImage
和CvMat
的优点,但克服了它们的一些缺点,例如类型不灵活、内存管理复杂等问题。- 它是 OpenCV 的统一数据结构,简化了库的设计,便于用户理解和使用。
使用OpenCV读取RGB图像和灰度图像
image = cv.imread('images/test.png')
print(image.shape) # (581, 400, 3) (Height,Width,Channel)
image = cv.imread('images/test.png',cv.IMREAD_GRAYSCALE)
print(image.shape) # (581, 400) (Height,Width)
print(image.shape)输出的值分别是高度、宽度和通道数。灰度图像只有一个通道,默认没显示。
如何创建一张空白图像
需要使用numpy来实现 import numpy as np
创建全黑色的空白图像
# 灰度图像(单通道)高度500, 宽度500
blank_image = np.zeros((500, 500), dtype=np.uint8)
# 彩色图像(三通道)
blank_image = np.zeros((500, 500, 3), dtype=np.uint8)
创建指定颜色的空白图像
# 单通道灰度图像,像素值全部为127
blank_image = np.full((500, 500), 127, dtype=np.uint8)
# 三通道彩色图像,BGR格式,蓝色
blank_image = np.zeros((500, 500, 3), dtype=np.uint8)
blank_image[:] = (255, 0, 0) # 设置为蓝色 (BGR)
创建带透明通道的空白图像
带透明度的图像需要 4 通道,通常表示为 BGRA 格式。
# 透明背景 高度500, 宽度500, 4通道透明图像
blank_image = np.zeros((500, 500, 4), dtype=np.uint8) # 4 通道 BGRA
# 设置为半透明红色背景
blank_image = np.zeros((500, 500, 4), dtype=np.uint8)
blank_image[:] = (0, 0, 255, 128) # BGRA: 红色 (255, 0, 0) + 半透明 (128)
图像的复制与拷贝
roi = image[100:200,100:200]
blank = np.zeros_like(image)
blank[100:200,100:200] = roi
- 通过 NumPy 切片,从
image
中提取一个矩形区域,坐标范围是:- 高度:
100
到200
(上下边界)。 - 宽度:
100
到200
(左右边界)。
- 高度:
- 切片范围:
- 起始索引包含,结束索引不包含(半开区间)。
- 提取的区域大小为
(100, 100)
。
如果坐标超出了图像的边界(如 image[100:1000, 100:200]
),会引发索引错误。
将 ROI 复制到空白图像时,目标区域大小需匹配,roi
的大小必须与目标区域的大小一致,否则会报错。
例如,roi
大小为 (100, 100, 3)
,blank[100:200, 100:200]
也是 (100, 100, 3)
。
# 使用.copy()去拷贝Mat
def mat_demo():
image = cv.imread('images/test.png')
if image is None:
print("Error: Image not found or failed to load.")
return
print(image.shape)
roi = image[100:200,100:200]
blank = np.zeros_like(image)
blank[300:400,100:200] = roi
cv.imshow('blank', blank)
blank_copy = blank.copy()
cv.imshow('blank_copy', blank_copy)
# cv.imshow('image', image)
cv.waitKey()
cv.destroyAllWindows()
copy()
和直接赋值(=
)的操作之间的区别主要体现在是否是 深拷贝 和 浅拷贝
直接赋值不会创建新的对象,而是将变量指向同一个内存地址(引用)。这是一种 浅拷贝。
使用 copy()
会创建一个新的对象,并将原始对象的内容拷贝到新对象中。这是 深拷贝。
© 版权声明
转载请注明出处,并标明原文链接。
本网站尊重知识产权,如有侵权,请及时联系我们删除。
本站所有原创内容仅用于学习和交流目的,未经作者和本站授权不得进行商业使用或盈利行为。
本网站尊重知识产权,如有侵权,请及时联系我们删除。
本站所有原创内容仅用于学习和交流目的,未经作者和本站授权不得进行商业使用或盈利行为。
THE END
暂无评论内容