繁体   English   中英

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

[英]Python Class Member Variable Containing OpenCV data initializes as a pointer

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

出于某种原因,class 成员之一( contents )似乎是引用/指针,而另一个不是( resolution )。 如果我在一个 class 上编辑contents ,它会更新另一个,即使我已经实例化了两个完全独立的 class 实例。 这是精简的示例:

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 的 Output

<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做同样的事情时,这不会发生。

这里到底发生了什么? 如果可以避免的话,我不想导入复制模块并使用 deepcopy。

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


更新

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

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

“内存管理和引用计数”部分中,它提到使用 OpenCV imread function 读取的数据相当于 ZF6F87C9FDCF8B3C3F07F93F1EE8712 中的Mat 它继续:

Mat 是一种保持矩阵/图像特征(行数和列数、数据类型等)和指向数据的指针的结构。 因此,没有什么能阻止我们拥有多个 Mat 实例对应相同的数据。 Mat 保留一个引用计数,该计数告诉当 Mat 的特定实例被销毁时是否必须释放数据。

因此,虽然 Python 返回<class 'numpy.ndarray'>作为类型,但它实际上是一个指针/引用(不知道 Python 的区别,请有人对此进行扩展)到 ZCD691B4957F098CDE288 中的该数组在它的示例中,他们使用 go 来展示如何制作图像数据的副本:

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

就我而言,我刚刚更新了Frame class 中的代码,其中self.contents被初始化为:

self.contents = np.copy(contents)

这解决了问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM