OpenCVのマウスイベントの記述で「グローバル変数使わなあかんのか…」となってしまった人用
結論、マウスイベントの第三引数param
に辞書型で渡してあげましょう。
def Something(event,x,y,flags,param):
global aaa,bbb,ccc
aaa = 何らかの処理
if __name__=="__main__":
global aaa,bbb,ccc
cv2.setMouseCallback(windowName,Something)
↓
def Something(event,x,y,flags,param):
param["aaa"] = 何らかの処理
if __name__=="__main__":
param = {"aaa":初期値,"bbb":初期値,"ccc":初期値}
cv2.setMouseCallback(windowName,Something,param)
辞書型で渡してやると参照渡しになるので変数の中身が更新されるのがミソ
タプルとかでマウスイベントに渡すと値がそのまま渡されるので、「マウスイベントが実行されるたびにメインで記述した値」が渡されて値が更新されません。
なので、クリック回数の保存とかをしたいときはグローバル変数にするか辞書型で渡すのが有効だったということですね。
この記事に出てくるソースコードではグローバル変数を使っていました。
↓に辞書型に書き直したコードを置いておきます。
import cv2
import numpy as np
import math
def draw_circle(event,x,y,flags,param):
distR = math.ceil(math.sqrt((x-param["centerX"])**2 + (y-param["centerY"])**2))
if event == cv2.EVENT_LBUTTONDOWN:
param["cnt"] += 1
param["isGrabbed"] = True
if param["cnt"] == 1:
[param["centerX"],param["centerY"]] = [x,y]
if param["cnt"]>1:
if param["posState"] == 0: # inside
param["isInside"] = True
param["isOntheLine"] = False
param["distX"] = param["centerX"] - x
param["distY"] = param["centerY"] - y
elif param["posState"] == 1: # on the line
param["isInside"] = False
param["isOntheLine"] = True
elif param["posState"] == 2:
param["isInside"] = False
param["isOntheLine"] = False
if event == cv2.EVENT_LBUTTONUP:
param["isGrabbed"] = False
if event == cv2.EVENT_MOUSEMOVE:
if param["cnt"] == 0:
[param["centerX"],param["centerY"]] = [x,y]
if param["cnt"] > 0:
if param["isGrabbed"] == False:
if distR < param["r"]-5: # inside
param["posState"] = 0
param["color"] = (255,0,0)
elif (distR <= param["r"]+5) & (distR >= param["r"]-5): # on the line
param["posState"] = 1
param["color"] = (0,255,0)
elif distR > param["r"]+5: # outside
param["posState"] = 2
param["color"] = (0,0,255)
else:
if param["isInside"] == True:
param["centerX"] = x+param["distX"]
param["centerY"] = y+param["distY"]
elif param["isOntheLine"] == True:
param["r"] = distR
img_tmp = testIm.copy()
cv2.circle(img_tmp,(param["centerX"],param["centerY"]), param["r"], param["color"], 5)
cv2.imshow(windowName,img_tmp)
if __name__=="__main__":
testIm = cv2.imread(r'C:\****\sample_pic.jpg')
windowName = "Select window"
param = {"centerX":0,"centerY":0,"cnt":0,"r":50,"distX":0,"distY":0,"isGrabbed":False,"isInside":False,"isOntheLine":False,"color":(0,0,255),"posState":0}
cv2.namedWindow(windowName)
cv2.setMouseCallback(windowName,draw_circle,param)
cv2.imshow(windowName,testIm)
key = cv2.waitKey()