Summary
Macでマウスを使って矩形領域を指定して画面キャプチャする(2021.7.7)のはできるようになったので、今回は静止画像を表示し、その上にマウスを使って矩形領域を指定して、その領域だけをキャプチャする。
マウスイベントの取得の方法は、基本的にMacでマウスを使って矩形領域を指定して画面キャプチャする(2021.7.7)と同じで、call back関数を定義し、その関数でevent, x, y, flags, param
を引数として受け取るようにする。
cv2.namedWindow('Type [q] to quit capturing')
cv2.setMouseCallback('Type [q] to quit capturing', draw_circle)
cv2.namedWindow()で設定した名前の文字列と同一文字列で対象のwindowを特定できるようにしてcall back関数を指定する。
この対応が誤っていると、
(-27:Null pointer) NULL window handler in function 'cvSetMouseCallback'.
などとおこられます。
### 表示した画像にマウス操作でインポーズ描画する
whileループ中で、毎回元画像からコピーして再描画することで軌跡を消去する。
draw_circleの中では、クリックイベントが発生するごとにポジションをpt0に保存する。
一度マウスがクリックされたなら、画面内のどこか(最新のpt0の場所)に赤丸を書き続ける。
def draw_circle(event, x, y, flags, param):
global circle_clicked, pt0
print(x, y, event, flags, param, cv2.EVENT_LBUTTONDOWN, circle_clicked)
if event == cv2.EVENT_LBUTTONDOWN:
print("Draw!!! (%d, %d), %s" % (x, y, circle_clicked))
# pt0 shall be updeted for every Left click
pt0 = (x, y)
if circle_clicked == False:
circle_clicked = True
while True:
# Clear image for drowing new cirle and rectancle
frame = image.copy()
if topLeft_clicked == True and botRight_clicked == False:
cv2.rectangle(frame, pt1, pt2, (0, 255, 0), 1)
cv2.circle(frame, center=pt1, radius=5, color=(0,0,255), thickness=-1)
elif topLeft_clicked == True and botRight_clicked == True:
cv2.rectangle(frame, pt1, pt2, (0, 0, 255), 2)
# show the frame
cv2.imshow('Type [q] to quit capturing', frame)
カメラ画像の取得したい矩形領域の左上と右下の2点でマウス左クリックすると、領域を選択できる。その状態でs
キーを押すと領域を切り出して画像として保存する。
選択された領域と切り出された画像が一致していないのは、キーを押す操作をしているあいだに手持ちの被写体がずれているからです。
1回目のクリックが完了すると、現在選択されている区画を緑線で表示する。
2度目にクリックすると赤枠になり選択領域が確定する。
完成したスクリプトは次のようになります。 領域の選択が完了した状態でs
キーを押すと、赤枠で囲まれた領域を切り出して./photo_crop.jpg
に保存し、赤枠で領域を確定していない城代でs
キーが押された場合は、全体をキャプチャーして./photo.jpg
に保存します。q
で終了。
ソースコードはこちら(test_image_impose_test.py)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# =======================================================
# opencvを使ってマウスで矩形領域を指定して静止画上にインポーズする
#
# test_image_impose.py
# coded by Noboru Harada (noboru@ieee.org)
#
# Changes:
# 2021/07/07: First version
# =======================================================
import cv2
def draw_circle(event, x, y, flags, param):
global circle_clicked, pt0
print(x, y, event, flags, param, cv2.EVENT_LBUTTONDOWN, circle_clicked)
if event == cv2.EVENT_LBUTTONDOWN:
print("Draw!!! (%d, %d), %s" % (x, y, circle_clicked))
# pt0 shall be updeted for every Left click
= (x, y)
pt0 if circle_clicked == False:
= True
circle_clicked
def draw_rectangle(event, x, y, flags, param):
global pt1, pt2, topLeft_clicked, botRight_clicked
print(x, y, event, flags, param, cv2.EVENT_LBUTTONDOWN, topLeft_clicked, botRight_clicked)
if event == cv2.EVENT_LBUTTONDOWN:
if topLeft_clicked == True and botRight_clicked == True:
# release botRight_clicked
= False
botRight_clicked # renew topLeft_clicked
= True
topLeft_clicked = (x, y)
pt1 = (x, y)
pt2 elif topLeft_clicked == False and botRight_clicked == False:
= (x, y)
pt1 = True
topLeft_clicked elif topLeft_clicked == True and botRight_clicked == False:
= (x, y)
pt2 = True
botRight_clicked print("Draw!!! (%d, %d), %s, %s" % (x, y, topLeft_clicked, botRight_clicked))
elif botRight_clicked == False:
= (x, y)
pt2
# init position values
= (0, 0)
pt0 = (0, 0)
pt1 = (0, 0)
pt2 = False
circle_clicked = False
topLeft_clicked = False
botRight_clicked
print("Type 'q' to quit capturing")
= cv2.imread('./infile.jpg')
image 'Type [q] to quit capturing', image)
cv2.imshow('Type [q] to quit capturing')
cv2.namedWindow(
'Type [q] to quit capturing', draw_rectangle)
cv2.setMouseCallback(
while True:
# Clear image for drowing new cirle and rectancle
= image.copy()
frame
if topLeft_clicked == True and botRight_clicked == False:
0, 255, 0), 1)
cv2.rectangle(frame, pt1, pt2, (=pt1, radius=5, color=(0,0,255), thickness=-1)
cv2.circle(frame, centerelif topLeft_clicked == True and botRight_clicked == True:
0, 0, 255), 2)
cv2.rectangle(frame, pt1, pt2, (
# show the frame
'Type [q] to quit capturing', frame)
cv2.imshow(
= cv2.waitKey(1) & 0xFF
key
if key == ord('q'):
break
if key == ord('s'):
= image
frame if topLeft_clicked == True and botRight_clicked == True:
= pt1
x1, y1 = pt2
x2, y2 if x1 > x2 or y1 > y2:
= pt2
x1, y1 = pt1
x2, y2 = image[y1 : y2, x1 : x2]
crop_frame = "./photo_crop.jpg"
filename
cv2.imwrite(filename,crop_frame)else:
= "./photo.jpg"
filename
cv2.imwrite(filename,image)
# terminate resources
cv2.destroyAllWindows()