包含OpenCV数据的Python类成员变量初始化为指针



我创建了一个简单的Python类,在实例化它时将两个值作为参数(contentsresolution(。然后将这些参数分配给类的__init__函数中的类成员。

由于某种原因,类成员之一(contents(看起来是引用/指针,而另一个不是(resolution(。如果我在一个类上编辑contents,它会更新另一个,即使我已经实例化了该类的两个完全独立的实例。下面是一个简单的例子:

TestBaseClasses.py

import cv2
class Frame():
def __init__(self, contents, resolution):
self.contents = contents
self.resolution = [resolution[0], resolution[1]]
def resize(self, fx, fy):
self.contents = cv2.resize(self.contents, (0, 0), fx=fx, fy=fy)

测试.py

import cv2
from copy import deepcopy
from TestBaseClasses import Frame
frame = cv2.imread("test_img.png")
h, w, _ = frame.shape
ProcessFrame = Frame(frame, [h, w])
OriginalFrame = Frame(frame, [h, w])
print(type(frame))
print(ProcessFrame is OriginalFrame)
print(ProcessFrame.contents is OriginalFrame.contents)
print(ProcessFrame.resolution is OriginalFrame.resolution)
print(id(ProcessFrame.contents))
print(id(OriginalFrame.contents))
print("########################")
ProcessFrame = Frame(deepcopy(frame), [h, w])
OriginalFrame = Frame(deepcopy(frame), [h, w])
print(type(frame))
print(ProcessFrame is OriginalFrame)
print(ProcessFrame.contents is OriginalFrame.contents)
print(ProcessFrame.resolution is OriginalFrame.resolution)
print(id(ProcessFrame.contents))
print(id(OriginalFrame.contents))

test.py的输出

<class 'numpy.ndarray'>
False
True
False
4405193824
4405193824
########################
<class 'numpy.ndarray'>
False
False
False
4409151200
4491382256

正如您所看到的,我必须为frame变量创建一个deepcopy,以防止它链接到内存中的同一引用。您还可以看到frame变量的类型是numpy数组(而不是某种引用/指针(。

当我使用示例一(不带deepcopy(并在ProcessFrame中编辑contents成员时,它在OriginalFrame中编辑了contents成员。当我对resolution执行相同操作时,不会发生这种情况。

这到底是怎么回事?如果可以避免的话,我不想导入复制模块并使用深度复制。

需要注意的是,我使用的是Python 3.6。


更新

我开始认为这与cv2.imread()函数有关。如果我创建一个新的类成员并为其分配内容,那么它使用id()具有相同的值(即,它指向内存中的相同位置(。

在OpenCV文档中:
https://docs.opencv.org/3.4/d5/d98/tutorial_mat_operations.html

在"内存管理和引用计数"一节中,提到使用OpenCVimread函数读取的数据相当于C++中的Mat。它继续:

Mat是一种保持矩阵/图像特征(行和列号、数据类型等(和指向数据的指针。所以什么都没有阻止我们拥有与相同的数据。Mat保持引用计数,如果数据必须当Mat的某个特定实例被销毁时解除分配。

因此,尽管Python返回<class 'numpy.ndarray'>作为类型,但它实际上是指向内存中该数组的指针/引用(不知道Python中的区别,请有人对此进行扩展(。在这个例子中,他们继续展示如何复制图像数据:

img = cv.imread('image.jpg')
_img1 = np.copy(img)

在我的例子中,我刚刚更新了Frame类中的代码,其中self.contents初始化为:

self.contents = np.copy(contents)

这就解决了问题。

最新更新