【OpenCV】マウスイベントのグローバル変数を消す【Python】

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)
```
辞書型で渡してやると**参照渡し**になるので変数の中身が更新されるのがミソ
タプルとかでマウスイベントに渡すと値がそのまま渡されるので、「マウスイベントが実行されるたびにメインで記述した値」が渡されて値が更新されません。
なので、クリック回数の保存とかをしたいときは**グローバル変数**にするか**辞書型**で渡すのが有効だったということですね。

[この記事](https://qiita.com/NagayamaT/items/e044f36ca62b56992302)に出てくるソースコードではグローバル変数を使っていました。

↓に辞書型に書き直したコードを置いておきます。

```
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()

```