2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2021-03-21

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

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?