2016-04-16 39 views
3

私はOpenCVアプリケーションを書いています。これは基本的にカメラからフレームを取得し、画像処理を行い、2つの編集されたバリアントで画像を表示します。まず、cv2.imshow()を使用して画像を表示しましたが、OpenCV(Qtサポートなし)では最新のGUI要素を提供できませんでしたが、私はPySideを自分のGUIに使用することに決めました。QImageメモリリーク

しかし、これ以来、私は約830から850フレーム(関係なく、私が使用しているものタイマー率、またはどのくらいの画像処理私は)処理した後に、このエラーを取得する:私のイメージビューの両方のための

QImage: out of memory, returning null image 

をGUIにおいて、および各ループで、このいずれか

OpenCV Error: Unspecified error (The numpy array of typenum=2, ndims=3 can not be created) in NumpyAllocator::allocate, file ..\..\..\opencv-3.1.0\modules\python\src2\cv2.cpp, line 184 
OpenCV Error: Insufficient memory (Failed to allocate 921600 bytes) in cv::OutOfMemoryError, file ..\..\..\opencv-3.1.0\modules\core\src\alloc.cpp, line 52 
Traceback (most recent call last): 
    File "C:/myfile.py", line 140, in process_frame 
    img = QtGui.QImage(cv2.cvtColor(thresh_img, cv2.COLOR_RGB2BGR), self.width, self.height, 
cv2.error: ..\..\..\opencv-3.1.0\modules\core\src\alloc.cpp:52: error: (-4) Failed to allocate 921600 bytes in function cv::OutOfMemoryError 

(ここで画像処理することなく、それはまた、エラーが発生し)、私のコードの一部です:

import cv2 
import sys 
from PySide import QtGui, QtCore 
from threading import Thread 


class MainWindow(QtGui.QMainWindow): 
    def __init__(self, cam=0, parent=None): 
     super(MainWindow, self).__init__(parent) 

     self.camera = Camera(cam).start() 
     self.title = "Cam %s" % cam 
     self.counter = 0 

     widget = QtGui.QWidget() 
     self.layout = QtGui.QBoxLayout(QtGui.QBoxLayout.LeftToRight) 

     self.video_frame = QtGui.QLabel() 
     self.thresh_frame = QtGui.QLabel() 

     self.layout.addWidget(self.video_frame) 
     self.layout.addWidget(self.thresh_frame) 
     self.layout.addStretch() 

     self.setCentralWidget(widget) 
     widget.setLayout(self.layout) 

     self.setMinimumSize(640, 480) 
     self._timer = QtCore.QTimer(self) 
     self._timer.timeout.connect(self.process_frame) 
     self._timer.start(20) 

    def process_frame(self): 
     self.counter += 1 
     print(self.counter) 
     self.frame = self.camera.read() 
     self.height, self.width = self.frame.shape[:2] 

     thresh_img = cv2.threshold(cv2.cvtColor(self.frame, cv2.COLOR_RGB2GRAY), 0, 255, 
            cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] 
     thresh_img = cv2.erode(thresh_img, None, iterations=2) 
     thresh_img = cv2.dilate(thresh_img, None, iterations=2) 
     thresh_img = cv2.cvtColor(thresh_img, cv2.COLOR_GRAY2RGB) 

     img = QtGui.QImage(cv2.cvtColor(self.frame, cv2.COLOR_RGB2BGR), self.width, self.height, 
          QtGui.QImage.Format_RGB888) 
     img = QtGui.QPixmap.fromImage(img) 
     self.video_frame.setPixmap(img) 

     img = QtGui.QImage(cv2.cvtColor(thresh_img, cv2.COLOR_RGB2BGR), self.width, self.height, 
          QtGui.QImage.Format_RGB888) 
     img = QtGui.QPixmap.fromImage(img) 
     self.thresh_frame.setPixmap(img) 

    def closeEvent(self, event): 
     self.camera.stop() 
     event.accept() 


class Camera: 
    def __init__(self, src=0): 
     self.stream = cv2.VideoCapture(src) 
     (self.grabbed, self.frame) = self.stream.read() 

     self.stopped = False 

    def start(self): 
     Thread(target=self.update, args=()).start() 
     return self 

    def update(self): 
     while True: 
      if self.stopped: 
       return 
      (self.grabbed, self.frame) = self.stream.read() 

    def read(self): 
     return self.frame 

    def stop(self): 
     self.stopped = True 

if __name__ == "__main__": 
    app = QtGui.QApplication(sys.argv) 
    window = MainWindow(0) 
    window.show() 
    sys.exit(app.exec_()) 
私は私のプログラムのRAM使用量を見ることができ、Windowsのタスクマネージャで210

enter image description here

クラッシュの時点で、アプリはRAMのおよそ1.5ギガバイトを使用しています。私はgcモジュールとdel imgの後にgc.collect()を使ってみましたが、成功しませんでした。

他に何ができますか?

EDIT:スレッドCameraクラスは、ここでは関係ありません

、エラーもそれなしで表示されません。

+0

問題を再現できる完全なスタンドアロンプ​​ログラムを提供できますか? – tfv

+0

今は家にいませんが、すぐに投稿します!任意のアイデアimgインスタンスを削除する方法? – linusg

+0

@tfv私のコードを今更新しました。あなたはそれを見ていいかもしれません... – linusg

答えて

1

PySide固有のバグのようですが、PyQtを使って修正します。それはOpenCVに関連するものでもない。これは、どうやらこのバグは、Python 3.xの

を使用した場合のctypesを使って簡単な回避策が提供されたガベージコレクションの問題が原因である...今PySideを使用するためのソリューションが存在することになるよう

0

ルック:QtのオブジェクトをPythonオブジェクトを混合回避https://bugreports.qt.io/browse/PYSIDE-140

。下記の例を試して、refcountを修正して遊ぶのを避けてください。私の場合

stream = cv2.VideoCapture(0) 
grabbed, frame = stream.read() 

height, width = frame.shape[:2] 
data = Qt.QByteArray(cv2.cvtColor(frame, cv2.COLOR_RGB2BGR).tostring()) 
qimg = Qt.QImage(data, width, height, Qt.QImage.Format_RGB888) 

data.clear() 
del data 
+0

これはlooooong前ですが、とにかくおかげさまです。とにかく、refcounterメソッドは正常に動作していました。 – linusg

+0

あなたのためだけでなく、同じ/類似の問題の解決を探している他の人にも、それを残してください。 QtextEditを使用して、Refcountの回避策がQt5で機能していません。 – jkolczasty

1

、Iは、(一定の条件で)ビュースイッチをトリガーする異なるビューとQTimer切り替えるQStackedWidgetを用いました。

私はこのようなPIL.ImageQImageImageQtQPixmapとして、インスタンスを通過したそのうち別のビューからの引数を渡すためのfunctools.partialを、使用していました。

それは間違っていました。そのようなリソースがあるビューから別のビューに渡されると、ガーベッジコレクタによって適切にクリーンアップされません。

私のために働いたこと。

  1. は、あなたが(あなたのQWidgetのコンストラクタで)クラスのプロパティとして別のビューから渡す予定のすべての変数を宣言します。すべての画像リソース(PIL.ImageQImageImageQtQPixmapなど)をこれらの変数/プロパティに格納します。

  2. イメージリソースを含む引数を1つのビューから別のビューに渡さないでください。


あなたがOpenCVのとPyQtはを使用している場合はさらに、OpenCVの2.9でメモリリークが発生するバグが含まれていることに注意してください。メモリリークの原因を突き止める前に、最新バージョン(最新の2.xまたは3.x)にアップグレードしてください。

+0

あなたの答えをありがとう:) これは現在、私にとってはまったく関連していませんが、このアプリケーションにあったかどうかは100%ではないQStackedWidgetの使用を覚えています。トレースバックでわかるように、私は当時OpenCV 3.1.0を使っていました! – linusg