OpenCV(Python)
で処理した画像の画素値ヒストグラムをmatplotlib.pyplot
しようとしてハマったのでメモしておきます。
環境
項目 | バージョン |
---|---|
OS | MacOSX Sierra |
Python | 3.6.2(pyenv-virtualenv) |
matplotlibのbackend | TkAgg(pyenvとvirtualenvで環境構築した時にmatplotlib.pyplotが使えなかった時の対処法を参考に設定させていただきました) |
$ pip freeze -l
cycler==0.10.0
matplotlib==2.1.2
numpy==1.13.3
opencv-python==3.3.0.10
pyparsing==2.2.0
python-dateutil==2.6.1
pytz==2018.3
six==1.11.0
やりたかったこと
- 現在カメラに写っている画像をプレビューしながら、画素値のヒストグラムをリアルタイムに描画する
だいぶ端折っていまいまいましたが、当初はだいたい下のようなコードを書きました。
.python
# coding: UTF-8
import cv2
import numpy as np
import matplotlib
from matplotlib import pyplot as plt
def run():
cv2.namedWindow(self.srcWindowName) # 加工前の映像表示ウィンドウ生成
cv2.namedWindow(self.dstWindowName) # 加工後の映像表示ウィンドウ生成
cap = cv2.VideoCapture(0)
while True:
ret, src = cap.read()
if ret:
dst = convert(src) # 加工
cv2.imshow(self.srcWindowName, src)
cv2.imshow(self.dstWindowName, dst)
# ヒストグラム
img_hist = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)
hist = cv2.calcHist([img_hist],[0],None,[256],[0,256])
plt.plot(hist)
plt.xlim([0,256])
plt.ylim([0,10000])
plt.pause(.01)
plt.cla() # 現在描写されているグラフを消去
key = cv2.waitKey(1)
if key == 27: # ESCキー押されたら終了
break
cap.release()
cv2.destroyAllWindows()
エラー
上記のコードを実行すると、以下のようなエラーが発生しました。
2018-02-21 17:42:24.083 python[11468:1380593] -[QNSApplication _setup:]: unrecognized selector sent to instance 0x7feff8ecedb0
2018-02-21 17:42:24.086 python[11468:1380593] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[QNSApplication _setup:]: unrecognized selector sent to instance 0x7feff8ecedb0'
*** First throw call stack:
(
0 CoreFoundation 0x00007fffbd5122cb __exceptionPreprocess + 171
1 libobjc.A.dylib 0x00007fffd232948d objc_exception_throw + 48
2 CoreFoundation 0x00007fffbd593f04 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
3 CoreFoundation 0x00007fffbd484755 ___forwarding___ + 1061
4 CoreFoundation 0x00007fffbd4842a8 _CF_forwarding_prep_0 + 120
5 Tk 0x0000000116b19c02 TkpInit + 471
6 Tk 0x0000000116a952a9 Tk_Init + 1794
7 _tkinter.cpython-36m-darwin.so 0x000000011696edd4 Tcl_AppInit + 84
8 _tkinter.cpython-36m-darwin.so 0x0000000116969c4f _tkinter_create + 1071
9 python 0x000000010d53ef46 _PyCFunction_FastCallDict + 166
10 python 0x000000010d5c764e call_function + 478
11 python 0x000000010d5c06b3 _PyEval_EvalFrameDefault + 4851
12 python 0x000000010d5c8126 _PyEval_EvalCodeWithName + 2566
13 python 0x000000010d5c8bc6 _PyFunction_FastCallDict + 662
14 python 0x000000010d4f5eba _PyObject_FastCallDict + 346
15 python 0x000000010d4f5fec _PyObject_Call_Prepend + 156
16 python 0x000000010d4f5c15 PyObject_Call + 101
17 python 0x000000010d5573ee slot_tp_init + 158
18 python 0x000000010d5536a9 type_call + 313
19 python 0x000000010d4f5e84 _PyObject_FastCallDict + 292
20 python 0x000000010d4f62d5 _PyObject_FastCallKeywords + 197
21 python 0x000000010d5c7622 call_function + 434
22 python 0x000000010d5c073d _PyEval_EvalFrameDefault + 4989
23 python 0x000000010d5c8878 fast_function + 568
24 python 0x000000010d5c7629 call_function + 441
25 python 0x000000010d5c06b3 _PyEval_EvalFrameDefault + 4851
26 python 0x000000010d5c8126 _PyEval_EvalCodeWithName + 2566
27 python 0x000000010d5c8bc6 _PyFunction_FastCallDict + 662
28 python 0x000000010d4f5eba _PyObject_FastCallDict + 346
29 python 0x000000010d4f5fec _PyObject_Call_Prepend + 156
30 python 0x000000010d4f5c15 PyObject_Call + 101
31 python 0x000000010d5c0a07 _PyEval_EvalFrameDefault + 5703
32 python 0x000000010d5c8126 _PyEval_EvalCodeWithName + 2566
33 python 0x000000010d5c8919 fast_function + 729
34 python 0x000000010d5c7629 call_function + 441
35 python 0x000000010d5c06b3 _PyEval_EvalFrameDefault + 4851
36 python 0x000000010d5c8878 fast_function + 568
37 python 0x000000010d5c7629 call_function + 441
38 python 0x000000010d5c06b3 _PyEval_EvalFrameDefault + 4851
39 python 0x000000010d5c8126 _PyEval_EvalCodeWithName + 2566
40 python 0x000000010d5c8919 fast_function + 729
41 python 0x000000010d5c7629 call_function + 441
42 python 0x000000010d5c06b3 _PyEval_EvalFrameDefault + 4851
43 python 0x000000010d5c8126 _PyEval_EvalCodeWithName + 2566
44 python 0x000000010d5c8919 fast_function + 729
45 python 0x000000010d5c7629 call_function + 441
46 python 0x000000010d5c06b3 _PyEval_EvalFrameDefault + 4851
47 python 0x000000010d5c8878 fast_function + 568
48 python 0x000000010d5c7629 call_function + 441
49 python 0x000000010d5c06b3 _PyEval_EvalFrameDefault + 4851
50 python 0x000000010d5c8878 fast_function + 568
51 python 0x000000010d5c7629 call_function + 441
52 python 0x000000010d5c06b3 _PyEval_EvalFrameDefault + 4851
53 python 0x000000010d5c8126 _PyEval_EvalCodeWithName + 2566
54 python 0x000000010d5bf330 PyEval_EvalCode + 48
55 python 0x000000010d5f3339 PyRun_FileExFlags + 185
56 python 0x000000010d5f286d PyRun_SimpleFileExFlags + 285
57 python 0x000000010d60c1b3 Py_Main + 3427
58 python 0x000000010d4ea7d8 main + 248
59 libdyld.dylib 0x00007fffd2c0f235 start + 1
60 ??? 0x0000000000000002 0x0 + 2
)
libc++abi.dylib: terminating with uncaught exception of type NSException
Abort trap: 6
OpenCVとmatplotlib.pyplotが競合していた
どうやらOpenCVで生成したウィンドウがある状態で、pyplotの描画を行おうとすると、上記のエラーが発生してしまうようです。
上記のエラーでググるとstackoverflowなどでは、「明示的にTkAgg
を使う宣言をする」という解決策が大半だったのですが、原因は別のところにありました。
結果的にcv2.namedWindow(self.srcWindowName)
やcv2.imshow(self.srcWindowName, src)
などのプレビュー描画処理をコメントアウトすることで、ヒストグラムは正常に表示されるようになりました。
プレビューしながら・・・という機能を作るためには、別プロセスでプレビュー機能を立ち上げたほうが良いかもしれません。