kujirahand/tkeasygui-python

OpenCVと組み合わせる場合の問題

Closed this issue · 21 comments

Ta2S commented

ver0.2.57までで、ほぼ関数を使用しないプログラムは、PySimpleGUIからTkEasyGUIに移行できたのですが、もう少しきれいなコードを書きたいと、関数を使用したプログラムに書き換えるチャレンジで、後方に記載したエラーが出ます。
下記プログラムは、wrtn+Claude2.1に質問できるように削っています。

import cv2
import PySimpleGUI as sg
#import TkEasyGUI as sg
import numpy as np

グローバル変数を定義

cap = None
window0 = None
window2 = None

def load_setting():
with open('C:/code/python/TaS_INSP_Mark/settings1.3.txt', 'r') as f:
lines = f.readlines()

env_vars = []
for line in lines:
    key, value = line.strip().split('=')
    env_vars.append((key, int(value)))

IMX1 = env_vars[0][1]
DL = env_vars[1][1]
VCAP1 = env_vars[2][1]
EXP1 = env_vars[3][1]
TY1 = env_vars[4][1]
TX1 = env_vars[5][1]
TY2 = env_vars[6][1]
TX2 = env_vars[7][1]
DSP = env_vars[8][1]
SPK = env_vars[9][1]
FCS = env_vars[10][1]
THEMEN = env_vars[11][1]

if IMX1 == 0:
    CAY1 = 4656
    CAX1 = 3496
    DL = 2
    FCS = 0
elif IMX1 == 1:
    CAY1 = 4000
    CAX1 = 3000
    DL = 1
    FCS = 95

DY1 = 1920
DX1 = 1080
SY1 = 1280
SX1 = 961
FONT1 = 11

if THEMEN==0:
    THEME='default'
elif THEMEN==1:
    THEME='winnative'
elif THEMEN==2:
    THEME='clam'

TY3 = CAY1-TY2
TX3 = CAX1-TX2
return IMX1,CAY1,CAX1,DL,VCAP1,EXP1,TY1,TX1,TY2,TX2,TY3,TX3,DSP,DY1,DX1,SY1,SX1,FONT1,SPK,FCS,THEME

def window0_open():
global window0
layout0 = [[sg.Text('シート検査Setting起動中')]]
window0 = sg.Window('Window Title', layout0, no_titlebar=True, keep_on_top=True, modal=True, finalize=True)

def camera_setting(CAY1,CAX1,DL,VCAP1,EXP1,IMX1,FCS):
global cap
cap = cv2.VideoCapture(VCAP1)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, CAY1)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, CAX1)

cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 0)
cap.set(cv2.CAP_PROP_EXPOSURE, EXP1)
cap.set(cv2.CAP_PROP_AUTO_WB, 0)

ret, frame000 = cap.read()
ret, frame000 = cap.read()

if IMX1 == 1:
    cap.set(cv2.CAP_PROP_AUTOFOCUS, 0)
    cap.set(cv2.CAP_PROP_FOCUS, FCS)
elif IMX1 == 2:
    cap.set(cv2.CAP_PROP_AUTOFOCUS, 0)
    cap.set(cv2.CAP_PROP_FOCUS, FCS)

def camera_check(ret):
global window2
try:
if ret == False:
layout2 = [[sg.Text(' カメラが接続されていません ')],
[sg.Button(' Exit ')]]
window2 = sg.Window('Title', layout2, keep_on_top=True, modal=True, finalize=True)

    if window2:
        while True:
            event, values = window2.read()
            if event == sg.WIN_CLOSED:
                window2.close()
                break
            elif event in (None, '         Exit         ', sg.WINDOW_CLOSED):
                window2.close()
                break
finally:
    if window2:
        window2.close()

if name == 'main':
IMX1,CAY1,CAX1,DL,VCAP1,EXP1,TY1,TX1,TY2,TX2,TY3,TX3,DSP,DY1,DX1,SY1,SX1,FONT1,SPK,FCS,THEME = load_setting() # 設定ファイルから整数の配列を読み込む
window0_open()
camera_setting(CAY1,CAX1,DL,VCAP1,EXP1,IMX1,FCS)
window0.close()

ret, frame = cap.read()

camera_check(ret)

cap.release()
cv2.destroyAllWindows()

インストールの関係で、Python3.11.4+PySimpleGUI4.61では、エラー出ず。

Python3.12.2+TkEasyGUI0.2.57では、次のエラーが出ます。
[ WARN:0@14.233] global cap_msmf.cpp:1768 CvCapture_MSMF::grabFrame videoio(MSMF): can't grab frame. Error: -2147483638
[ WARN:0@24.250] global cap_msmf.cpp:1768 CvCapture_MSMF::grabFrame videoio(MSMF): can't grab frame. Error: -2147483638
[ WARN:0@34.271] global cap_msmf.cpp:1768 CvCapture_MSMF::grabFrame videoio(MSMF): can't grab frame. Error: -2147483638
Window.close.failed: <TkEasyGUI.widgets.Window object at 0x000002144E913320> is not in list

Python3.12.2+TkEasyGUI0.2.67では、次のエラーが出ます。
[ WARN:0@14.268] global cap_msmf.cpp:1768 CvCapture_MSMF::grabFrame videoio(MSMF): can't grab frame. Error: -2147483638
[ WARN:0@24.283] global cap_msmf.cpp:1768 CvCapture_MSMF::grabFrame videoio(MSMF): can't grab frame. Error: -2147483638
[ WARN:0@34.306] global cap_msmf.cpp:1768 CvCapture_MSMF::grabFrame videoio(MSMF): can't grab frame. Error: -2147483638
Traceback (most recent call last):
File "c:\code\python\TaS_INSP_Mark\Ta2SInspectMarkVer1.3setp01.py", line 116, in
camera_check(ret)
File "c:\code\python\TaS_INSP_Mark\Ta2SInspectMarkVer1.3setp01.py", line 106, in camera_check
window2.close()
File "C:\Users\tamta\AppData\Local\Programs\Python\Python312\Lib\site-packages\TkEasyGUI\widgets.py", line 648, in close
self.set_alpha_channel(0.0) # force hide
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\tamta\AppData\Local\Programs\Python\Python312\Lib\site-packages\TkEasyGUI\widgets.py", line 576, in set_alpha_channel
self.window.attributes("-alpha", alpha)
File "C:\Users\tamta\AppData\Local\Programs\Python\Python312\Lib\tkinter_init_.py", line 2051, in wm_attributes
return self.tk.call(args)
^^^^^^^^^^^^^^^^^^
_tkinter.TclError: bad window path name ".!toplevel2"

Ta2S commented

補足です。
確認中に使用しているカメラは、IMX577のUSB3.0接続で、4000x3000の解像度です。
Python3.12.2+TkEasyGUI0.2.57では、window0が表示されず、window2は表示されます。
Python3.12.2+TkEasyGUI0.2.67では、window0が表示されません。

更に試しました。
Python3.11.4+TkEasyGUI0.2.57では、次のエラーが出ます。
window0が表示されず、window2は表示されます。
[ WARN:0@17.106] global cap_msmf.cpp:1759 CvCapture_MSMF::grabFrame videoio(MSMF): can't grab frame. Error: -2147483638
[ WARN:0@27.135] global cap_msmf.cpp:1759 CvCapture_MSMF::grabFrame videoio(MSMF): can't grab frame. Error: -2147483638
Window.close.failed: <TkEasyGUI.widgets.Window object at 0x000001E6E55BD5D0> is not in list

Python3.11.4+TkEasyGUI0.2.67では、エラーが出ませんでした。

Ta2S commented

再補足です。
Python3.11.4+TkEasyGUI0.2.67では、window0が表示されません。

Ta2S commented

再々補足です。
IMX1=0で、IMX298センサーのUSB2.0接続カメラ
IMX1=1で、IMX577センサーのUSB3.0接続カメラ
IMX1=2で、IMX179センサーのUSB3.0接続カメラ
を選択しますが、IMX179センサー用の削り方にミスがあるようですが、IMX577センサー用の設定ですので、影響は無いと思います。
ret, frame000 = cap.read()
ret, frame000 = cap.read()
は、IMX298センサー用で、1回目にエラーが出たり、2回目に8秒かかったりするので、事前に2回キャプチャーしておかないと、約1FPSで取り込めないため書いていますが、IMX577・IMX179センサーでは削除しても問題ないと思いますが、今はまだ残しています。
ややこしくてすみません。

ご報告、ありがとうございます。すみません。Pythonのコードが崩れてしまっていて試せません。
下記のように、バッククォート三つ(```)で囲っていただけるでしょうか。

```
ここにPythonのコード
```

以下のエラーの件、確認してみます。

File "C:\Users\tamta\AppData\Local\Programs\Python\Python312\Lib\site-packages\TkEasyGUI\widgets.py", line 576, in set_alpha_channel
self.window.attributes("-alpha", alpha)
File "C:\Users\tamta\AppData\Local\Programs\Python\Python312\Lib\tkinter_init_.py", line 2051, in wm_attributes
return self.tk.call(args)
^^^^^^^^^^^^^^^^^^
_tkinter.TclError: bad window path name ".!toplevel2"
Ta2S commented

すいません。コードを記しなおし、その下に、settings1.3.txtファイルの内容を記します。よろしくお願いします。
'''
import cv2
#import PySimpleGUI as sg
import TkEasyGUI as sg
import numpy as np

グローバル変数を定義

cap = None
window0 = None
window2 = None

def load_setting():
with open('C:/code/python/TaS_INSP_Mark/settings1.3.txt', 'r') as f:
lines = f.readlines()

env_vars = []
for line in lines:
    key, value = line.strip().split('=')
    env_vars.append((key, int(value)))

IMX1 = env_vars[0][1]
DL = env_vars[1][1]
VCAP1 = env_vars[2][1]
EXP1 = env_vars[3][1]
TY1 = env_vars[4][1]
TX1 = env_vars[5][1]
TY2 = env_vars[6][1]
TX2 = env_vars[7][1]
DSP = env_vars[8][1]
SPK = env_vars[9][1]
FCS = env_vars[10][1]
THEMEN = env_vars[11][1]

if IMX1 == 0:
    CAY1 = 4656
    CAX1 = 3496
    DL = 2
    FCS = 0
elif IMX1 == 1:
    CAY1 = 4000
    CAX1 = 3000
    DL = 1
    FCS = 95

DY1 = 1920
DX1 = 1080
SY1 = 1280
SX1 = 961
FONT1 = 11

if THEMEN==0:
    THEME='default'
elif THEMEN==1:
    THEME='winnative'
elif THEMEN==2:
    THEME='clam'

TY3 = CAY1-TY2
TX3 = CAX1-TX2
return IMX1,CAY1,CAX1,DL,VCAP1,EXP1,TY1,TX1,TY2,TX2,TY3,TX3,DSP,DY1,DX1,SY1,SX1,FONT1,SPK,FCS,THEME

def window0_open():
global window0
layout0 = [[sg.Text('シート検査Setting起動中')]]
window0 = sg.Window('Window Title', layout0, no_titlebar=True, keep_on_top=True, modal=True, finalize=True)

def camera_setting(CAY1,CAX1,DL,VCAP1,EXP1,IMX1,FCS):
global cap
cap = cv2.VideoCapture(VCAP1)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, CAY1)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, CAX1)

cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 0)
cap.set(cv2.CAP_PROP_EXPOSURE, EXP1)
cap.set(cv2.CAP_PROP_AUTO_WB, 0)

ret, frame000 = cap.read()
ret, frame000 = cap.read()

if IMX1 == 1:
    cap.set(cv2.CAP_PROP_AUTOFOCUS, 0)
    cap.set(cv2.CAP_PROP_FOCUS, FCS)
elif IMX1 == 2:
    cap.set(cv2.CAP_PROP_AUTOFOCUS, 0)
    cap.set(cv2.CAP_PROP_FOCUS, FCS)

def camera_check(ret):
global window2
try:
if ret == False:
layout2 = [[sg.Text(' カメラが接続されていません ')],
[sg.Button(' Exit ')]]
window2 = sg.Window('Title', layout2, keep_on_top=True, modal=True, finalize=True)

    if window2:
        while True:
            event, values = window2.read()
            if event == sg.WIN_CLOSED:
                window2.close()
                break
            elif event in (None, '         Exit         ', sg.WINDOW_CLOSED):
                window2.close()
                break
finally:
    if window2:
        window2.close()

if name == 'main':
IMX1,CAY1,CAX1,DL,VCAP1,EXP1,TY1,TX1,TY2,TX2,TY3,TX3,DSP,DY1,DX1,SY1,SX1,FONT1,SPK,FCS,THEME = load_setting() # 設定ファイルから整数の配列を読み込む
window0_open()
camera_setting(CAY1,CAX1,DL,VCAP1,EXP1,IMX1,FCS)
window0.close()

ret, frame = cap.read()

camera_check(ret)

cap.release()
cv2.destroyAllWindows()
'''
IMX1=1
DL=1
VCAP1=0
EXP1=-4
TY1=160
TX1=160
TY2=160
TX2=160
DSP=0
SPK=1
FCS=95
THEMEN=2

Ta2S commented

うまくできませんでした。次のGoogleドライブから取得できますか?
Ta2SInspectMarkVer1.3setp01.py
https://drive.google.com/file/d/1gawn12FwjHnQ4eMu79_nYSc1YE8kR3BE/view?usp=drive_link
settings1.3.txt
https://drive.google.com/file/d/13Q3zOK3OLa-jyXQpy_bZCtfRUWP19yGN/view?usp=drive_link

Ta2S commented

設定ファイルそのままだと、
下記コードの所を
elif IMX1 == 1:
CAY1 = 4000
CAX1 = 3000

4000→1920、3000→1080などと変更すると、ノートパソコンのカメラなどで動作するようになると思います。

@Ta2S Google Driveですが権限がないと言われます。
もし、ファイルを添付してくださる場合は、このフォームの右上にクリップのアイコンがあり、そこからファイルをアップロードできそうですが、どうでしょうか?

スクリーンショット 2024-05-08 20 20 12

Ta2S commented

すいません。アクセス制限を変更する必要がありました。
リンクを知っている全員に変更しました。

Ta2S commented

Pythonファイルのままでは添付できませんでしたので、メモ帳にコピーしてTXTファイルとして添付しています。
cap = cv2.VideoCapture(VCAP1) がなぜか設定できなくなっているように思います。
cap = cv2.VideoCapture(0) としてもダメでした。
asyncio.run(asyncio.sleep(5)) などで設定待ちしてもダメでした。

@Ta2S さま、添付ありがとうございます。これから検証してみます。

プログラムを確認してみました。こちらは、OpenCVでカメラを表示するプログラムでしょうか。
パスを変えたり、いろいろ試してみましたが、PySimpleGUIに変更しても、エラーが出て動きませんでした。

それで、OpenCVのカメラがウィンドウに表示できるかサンプルを作ってみました。
下記の例では正しくWebカメラの画面が表示できました。
https://github.com/kujirahand/tkeasygui-python/blob/main/tests/opencv_camera.py

もしかすると、イベントループで、window.readメソッドをread(timeout=1)とすると、動くかもです。
私が作った上記サンプルは、timeoutを指定しないと、正しくカメラの画面を読み取りませんでしたので。
(イベントモデルはPySimpleGUIと同じように書けるようにしていますが、全くではありません。)

今後、ためになると思いますので、タイトル変更させていただきました。

Ta2S commented

確認結果を報告させていただきます。

window0が表示されない件は、自己解決しました。
window0.refresh() でウィンドウ画面の更新をすると、表示されました。
私の環境、i5-7400 16GBメモリ 256GBSSD QuadroP600Video Windows11Pro64の問題かもしれません。

cap = cv2.VideoCapture(VCAP1) は、設定できていました。
下記コードを追加することで、確認できました。
print('camera = ',VCAP1,CAY1,CAX1)
print(" - CAP_PROP_FRAME_WIDTH: ", cap.get(cv2.CAP_PROP_FRAME_WIDTH))
print(" - CAP_PROP_FRAME_HEIGHT: ", cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

イベントループで、window.readメソッドをread(timeout=1)とすると、動くかもの件は、動きませんでした。
静止画取り込み、かつwindow.readが関係していないからでしょうか。

Python3.12.2+PySimpleGUI4.60、エラーが出て動かないことを確認しました。
Python3.12.2では、ret, frame = cap.read()が正常に出来ていないようです。

関数を使用したプログラムに書き換えるチャレンジをする前のプログラムは、下記になります。
https://drive.google.com/file/d/181iWbVxBTaJQaxCcaMaowBJTd8mky__x/view?usp=drive_link
Python3.11.4+TkEasyGUI0.2.67 でも、Python3.12.2+TkEasyGUI0.2.67 でも、Python3.12.2+TkEasyGUI0.2.57 でも正常に動作します。
本検査プログラム用の環境設定のみ行うプログラムで、パソコンやカメラの選択・設定をし、撮影する静止画像の検査対象範囲をトリミング範囲として表示・設定するものです。

今回の問題は、Python3.11.4からPython3.12.2へのバージョンアップに対する仕様変更に、プログラミング初心者の私では、対処できないだけかもしれません。

Ta2S commented

すいません。自己解決したように思えます。

別のwindows11ノートパソコンで、Python3.12.1+TkEasyGUI0.2.68の組み合わせで、動作しました。
このパソコンには、Python3.12.1のみインストールしています。

i5-7400 16GBメモリ 256GBSSD QuadroP600Video Windows11Pro64には、Python3.11.4と3.12.2をインストールしています。
2つのバージョンのPythonをインストールしていることが原因の可能性が高いのでは、と思われます。

今後、Python3.12系のみインストールして検証していきますが、とりあえず現時点での状況をご報告させていただきます。

Ta2S commented

i5-7400 16GBメモリ 256GBSSD QuadroP600Video Windows11Pro64、Python3.11.4と3.12.2をアンインストールして、3.12.3のみインストールした状態でも、PySimpleGUIとTkEasyGUI共にret, frame = cap.read()が正常に出来ませんでした。

Python3.12.3をアンインストールして、インストールしていたフォルダも削除し、3.12.1をインストールしても、PySimpleGUIとTkEasyGUI共にret, frame = cap.read()が正常に出来ませんでした。

PySimpleGUI4.60.0
camera = 0 4000 3000

  • CAP_PROP_FRAME_WIDTH: 4000.0
  • CAP_PROP_FRAME_HEIGHT: 3000.0
    [ WARN:0@14.250] global cap_msmf.cpp:1768 CvCapture_MSMF::grabFrame videoio(MSMF): can't grab frame. Error: -2147483638
    cap open True
    ret False
    frame <class 'NoneType'>

TkEasyGUI0.2.68
camera = 0 4000 3000

  • CAP_PROP_FRAME_WIDTH: 4000.0
  • CAP_PROP_FRAME_HEIGHT: 3000.0
    [ WARN:0@14.214] global cap_msmf.cpp:1768 CvCapture_MSMF::grabFrame videoio(MSMF): can't grab frame. Error: -2147483638
    cap open True
    ret False
    frame <class 'NoneType'>
    Traceback (most recent call last):
    File "c:\code\python\Ta2SInspectSeet\Ta2SInspectMarkVer1.3setp02.py", line 138, in
    camera_check(ret)
    File "c:\code\python\Ta2SInspectSeet\Ta2SInspectMarkVer1.3setp02.py", line 121, in camera_check
    window2.close()
    File "C:\Users\tamta\AppData\Local\Programs\Python\Python312\Lib\site-packages\TkEasyGUI\widgets.py", line 657, in close
    self.set_alpha_channel(0.0) # force hide
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "C:\Users\tamta\AppData\Local\Programs\Python\Python312\Lib\site-packages\TkEasyGUI\widgets.py", line 585, in set_alpha_channel
    self.window.attributes("-alpha", alpha)
    File "C:\Users\tamta\AppData\Local\Programs\Python\Python312\Lib\tkinter_init_.py", line 2046, in wm_attributes
    return self.tk.call(args)
    ^^^^^^^^^^^^^^^^^^
    _tkinter.TclError: bad window path name ".!toplevel2"

次に打つ手を今は思いつかないので、とりあえず動く環境に何とか戻して、プログラム後半の関数化を先にすすめることにします。

Ta2S commented

ret, frame = cap.read()がPython3.12系で正常に働かない原因が判明しました。

ビデオカードQuadro P600もしくはそのドライバが原因と思われます。
ドライバアップデートをしても、動作せず。
ビデオカードを取り外し、内臓ビデオ機能にすると、動作するようになりました。

camera = 0 4000 3000

  • CAP_PROP_FRAME_WIDTH: 4000.0
  • CAP_PROP_FRAME_HEIGHT: 3000.0
    cap open True
    ret True
    frame <class 'numpy.ndarray'>

私のパソコン環境との相性問題であり、お手数をおかけし、申し訳ありませんでした。

無事解決されたとのこと、良かったです😊
IssueをCloseさせていただきます。