文章目录
- 前言
- 一、浅拷贝
- 二、深拷贝
- 三、比较
- 总结
前言
在数字图像处理中,针对读取到的一张图像,需要反复利用这张图像做各种的变换,以满足我们项目的需求。在这之前,最容易忽略的一点就是图像之间的拷贝问题,其中的浅拷贝和深拷贝不仅影响数据的存储方式,还直接关系到内存管理和数据修改的影响范围。
一、浅拷贝
浅拷贝是指创建一个新的对象,但这个新对象会引用原始对象中的数据(或指向原始数据的指针)。这意味着,如果原始数据发生变化,通过浅拷贝得到的数据也会发生变化,因为它们实际上指向的是同一块内存地址。
在OpenCV中,当使用赋值操作符(=)时,通常执行的是浅拷贝。
二、深拷贝
深拷贝则是创建一个全新的对象,并复制原始对象中的所有数据到新对象中。这样,原始对象和新对象拥有独立的内存地址和数据。因此,对原始对象的修改不会影响到通过深拷贝得到的新对象。
OpenCV的C++接口提供了clone()方法,但在Python中,可以直接使用NumPy的深拷贝机制。
三、比较
此处举一个简单的例子,当我们想在输入的图像中分别实现画矩形和画圆的操作时,首先我们定义两个函数用于绘制矩形和圆:
def draw_rectangle(image, top_left, bottom_right, color, thickness=2):"""在图像上绘制矩形:param image: 要绘制的图像:param top_left: 矩形左上角的坐标 (x, y):param bottom_right: 矩形右下角的坐标 (x, y):param color: 矩形的颜色,格式为 (B, G, R):param thickness: 矩形边框的厚度:return: 绘制了矩形的图像"""cv2.rectangle(image, top_left, bottom_right, color, thickness)return imagedef draw_circle(image, center, radius, color, thickness=2, fill=False):"""在图像上绘制圆:param image: 要绘制的图像:param center: 圆的中心坐标 (x, y):param radius: 圆的半径:param color: 圆的颜色,格式为 (B, G, R):param thickness: 圆边框的厚度,如果fill=True,则此参数将被忽略:param fill: 是否填充圆:return: 绘制了圆的图像"""if fill:cv2.circle(image, center, radius, color, -1)else:cv2.circle(image, center, radius, color, thickness)return image
我们均使用浅拷贝调用函数的时候,得到的结果不管是原图还是绘制之后的图像均被绘制了图像,这与我们的目的相反。
image = cv2.imread('D:/test.png')
# 绘制矩形
rect_img = image
rect_image = draw_rectangle(rect_img, (50, 50), (200, 200), (0, 0, 0), 3)
# 绘制圆
cir_img = image
circle_image = draw_circle(cir_img, (150, 150), 50, (255, 255, 255), 3, False)
我们均使用深拷贝调用函数的时候,得到的结果互不干扰。
image = cv2.imread('D:/test.png')
# 绘制矩形
rect_img = image.copy()
rect_image = draw_rectangle(rect_img, (50, 50), (200, 200), (0, 0, 0), 3)
# 绘制圆
cir_img = image.copy()
circle_image = draw_circle(cir_img, (150, 150), 50, (255, 255, 255), 3, False)
总结
区分深拷贝和浅拷贝主要是为了理解数据是如何在内存中存储和管理的,以及如何在不同的对象或函数之间安全地传递数据。浅拷贝可能更节省内存(因为它不复制数据),但在某些情况下,如果原始数据被意外修改,可能会导致数据不一致的问题。深拷贝虽然会消耗更多的内存,但它提供了更高的数据安全性和独立性。