【OpenCV】円の描画、マウスイベントで移動と拡大【Python】

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">画像上に円を置いて、ドラッグで移動、辺縁部のドラッグで拡大縮小を行えるプログラムを書きました。<a href="https://twitter.com/hashtag/OpenCV?src=hash&amp;ref_src=twsrc%5Etfw">#OpenCV</a> <a href="https://twitter.com/hashtag/Python?src=hash&amp;ref_src=twsrc%5Etfw">#Python</a> <a href="https://t.co/X3k0aZwwJa">pic.twitter.com/X3k0aZwwJa</a></p>&mdash; Natz (@Natz_tec) <a href="https://twitter.com/Natz_tec/status/1373144493071855617?ref_src=twsrc%5Etfw">March 20, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

OpenCVで円を描画、マウスイベントによる移動と拡大を実装しました。

最初に左クリックした位置に円を配置します
円周**内**で左クリックしたままドラッグすると円の**位置**が移動します。
円周**上**で左クリックしたままドラッグすると円の**半径**が変化します。

左クリック判定
ON : ```isGrabbed = True```
OFF: ```isGrabbed = False```

    
ポインタ位置判定
![bool.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923577/d5d19c91-1952-8a04-50cc-a17b71436ea8.png)
（```isInside```と```isOntheLine```が両方```True```は存在しません）



以下サンプルコード　　

※`testIm = cv2.imread(r'C:\****\sample_pic.jpg')`で画像を読み込みます。使用する画像のアドレスに書き換えて使用して下さい。
グローバル変数を削除した改訂版は[こちら](https://qiita.com/NagayamaT/items/aec08852fdaaababca8a)

```
import cv2
import numpy as np
import math


def draw_circle(event,x,y,flags,params):
    global cnt,windowName,testIm,centerX,centerY,r,color,distX,distY,isGrabbed,isInside,isOntheLine,posState
    distR = math.ceil(math.sqrt((x-centerX)**2 + (y-centerY)**2))

    if event == cv2.EVENT_LBUTTONDOWN:
        cnt += 1
        isGrabbed = True
        if cnt == 1:
            [centerX,centerY] = [x,y]
            print([centerX,centerY])
        if cnt>1:
            if posState == 0: # inside
                isInside = True
                isOntheLine = False
                distX = centerX - x
                distY = centerY - y

            elif posState == 1: # on the line
                isInside = False
                isOntheLine = True

            elif posState == 2:
                isInside = False
                isOntheLine = False

    if event == cv2.EVENT_LBUTTONUP:
        isGrabbed = False


    if event == cv2.EVENT_MOUSEMOVE:
        if cnt == 0:
            [centerX,centerY] = [x,y]

        if cnt > 0:
            if isGrabbed == False:
                if distR < r-5: # inside
                    posState = 0
                    color = (255,0,0)
                elif (distR <= r+5) & (distR >= r-5): # on the line
                    posState = 1
                    color = (0,255,0)
                elif distR > r+5: # outside
                    posState = 2
                    color = (0,0,255)
            else:

                if isInside == True:
                    centerX = x+distX
                    centerY = y+distY
                elif isOntheLine == True:
                    r = distR
        img_tmp = testIm.copy()
        cv2.circle(img_tmp,(centerX,centerY), r, color, 5)
        cv2.imshow(windowName,img_tmp)

if __name__=="__main__":
    global cnt,windowName,testIm,centerX,centerY,r,color,distX,distY,isGrabbed,isInside,isOntheLine,posState
    centerX = 0                     #保存すべきX座標
    centerY = 0                     #保存すべきY座標
    cnt = 0                         #画像内でのクリック回数
    r = 50
    distX = 0
    distY = 0
    posState = 0 # 0,1,2
    isGrabbed = False
    isInside = False
    isOntheLine = False
    color = (0,0,255)
    testIm = cv2.imread(r'C:\****\sample_pic.jpg')
    testIm = testIm/255
    windowName = "Select window"
    cv2.namedWindow(windowName)
    cv2.setMouseCallback(windowName,draw_circle)
    cv2.imshow(windowName,testIm)
    key = cv2.waitKey()

```


※マウスイベントの宣言でグローバル変数を使っているので注意してください。