简体   繁体   English

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

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

I have created a simple Python class that takes two values as arguments when instantiating it ( contents and resolution ).我创建了一个简单的 Python class 在实例化它时将两个值作为 arguments ( contentsresolution )。 These arguments are then assigned to class members in the class' __init__ function.然后将这些 arguments 分配给类' __init__ function 中的 class 成员。

For some reason, one of the class members ( contents ) appears to be a reference/pointer while the other is not ( resolution ).出于某种原因,class 成员之一( contents )似乎是引用/指针,而另一个不是( resolution )。 If I edit contents on one class, it updates the other even though I've instantiated two completely separate instances of the class.如果我在一个 class 上编辑contents ,它会更新另一个,即使我已经实例化了两个完全独立的 class 实例。 Here's the stripped down example:这是精简的示例:

TestBaseClasses.py 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)

test.py测试.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))

Output from test.py来自 test.py 的 Output

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

As you can see, I have to make a deepcopy of the frame variable in order to prevent it from being linked to the same reference in memory.如您所见,我必须对frame变量进行深度复制,以防止它链接到deepcopy中的相同引用。 You can also see that the frame variables' type is a numpy array (not some sort of reference/pointer).您还可以看到frame变量的类型是 numpy 数组(不是某种引用/指针)。

When I use example one (without deepcopy ) and edit the contents member in ProcessFrame , it edits the contents member in OriginalFrame .当我使用示例一(没有deepcopy )并编辑ProcessFrame中的contents成员时,它会编辑OriginalFrame中的contents成员。 This does not happen when I do the same for resolution .当我对resolution做同样的事情时,这不会发生。

What in the world is going on here?这里到底发生了什么? I'd like to not have to import the copy module and use deepcopy if I can avoid it.如果可以避免的话,我不想导入复制模块并使用 deepcopy。

It should be noted that I am using Python 3.6.需要注意的是,我使用的是 Python 3.6。


Update更新

I am beginning to think this is related to the cv2.imread() function.我开始认为这与cv2.imread() function 有关。 If I create a new class member and assign contents to it, it has the same value using id() (ie it's pointing to the same place in memory).如果我创建一个新的 class 成员并为其分配内容,它使用id()具有相同的值(即它指向内存中的相同位置)。

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

In the section 'Memory management and reference counting' , it mentions that the data read in using OpenCV imread function is the equivalent of Mat in C++.“内存管理和引用计数”部分中,它提到使用 OpenCV imread function 读取的数据相当于 ZF6F87C9FDCF8B3C3F07F93F1EE8712 中的Mat It goes on:它继续:

Mat is a structure that keeps matrix/image characteristics (rows and columns number, data type etc) and a pointer to data. Mat 是一种保持矩阵/图像特征(行数和列数、数据类型等)和指向数据的指针的结构。 So nothing prevents us from having several instances of Mat corresponding to the same data.因此,没有什么能阻止我们拥有多个 Mat 实例对应相同的数据。 A Mat keeps a reference count that tells if data has to be deallocated when a particular instance of Mat is destroyed. Mat 保留一个引用计数,该计数告诉当 Mat 的特定实例被销毁时是否必须释放数据。

Thus, although Python returns <class 'numpy.ndarray'> as the type, it is actually a pointer/reference (don't know the difference in Python, someone please expand on that) to that array in memory.因此,虽然 Python 返回<class 'numpy.ndarray'>作为类型,但它实际上是一个指针/引用(不知道 Python 的区别,请有人对此进行扩展)到 ZCD691B4957F098CDE288 中的该数组In it's example they go on to show how to make copies of the image data:在它的示例中,他们使用 go 来展示如何制作图像数据的副本:

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

In my case, I just updated the code in the Frame class where self.contents is initialized to:就我而言,我刚刚更新了Frame class 中的代码,其中self.contents被初始化为:

self.contents = np.copy(contents)

And that fixed the problem.这解决了问题。

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

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