【opencv-python】【トリミング】画像を固定サイズの矩形で切り取るためのGUIを作りました

はじめに

大きな画像から一部を切り取る機会は多々あります。

その時に固定サイズの矩形(長方形)で切り取りたい時はありませんか?きっとあるはずです。

簡単な方法がみつからなかったのでOpenCV-Pythonを使ってGUIを作りました。

使用例

python exe.py cat.jpg --width 200 --height 200

実行中の画面

f:id:touch-sp:20220414193941j:plain:w500
マウス操作で緑の矩形を移動させます。
キーボードの「S」を押せば緑で囲まれた部分が切り取られて保存されます。
何枚でも保存可能です。
終了するときは「Esp」キーを押します。

Pythonスクリプト

import os
import argparse
import cv2

parser = argparse.ArgumentParser()

parser.add_argument('file_name', help='image file name')
parser.add_argument('--width', type=int, default=200, help='width of bounding box')
parser.add_argument('--height',type=int, default=200, help='height of bounding box')

args = parser.parse_args() 

fname = args.file_name
width = args.width
height = args.height

drawing = False
ix, iy, width_diff, height_diff = 30, 30, 0, 0
 
# マウスコールバック関数
def my_mouse_callback(event, x, y, flags,param):

    global ix, iy, drawing, width_diff, height_diff
 
    if event == cv2.EVENT_MOUSEMOVE:      # マウスが動いた時
        if(drawing == True):
            ix = x - width_diff
            iy = y - height_diff
 
    elif event == cv2.EVENT_LBUTTONDOWN:  # マウス左押された時
        if (ix < x < ix + width) and (iy < y < iy + height):        
            width_diff = x - ix
            height_diff = y - iy
            drawing = True
 
    elif event == cv2.EVENT_LBUTTONUP:    # マウス左離された時
        drawing = False

img = cv2.imread(fname)
temp = img.copy()

source_window = "push s key for save"
cv2.namedWindow(source_window)
cv2.setMouseCallback(source_window, my_mouse_callback)

while True:
    cv2.imshow(source_window,temp)
    cv2.rectangle(temp, (ix, iy), (ix + width, iy + height), (0,255,0), 2)  # 矩形を描画

    if(drawing):            # 左クリック押されてたら
        temp = img.copy()   # 画像コピー
        cv2.rectangle(temp, (ix, iy), (ix + width, iy + height), (0,255,0), 2)  # 矩形を描画

    # キー操作
    k = cv2.waitKey(1) & 0xFF
    if k == 27 and not drawing:             # esc押されたら終了
        break

    elif k == ord('s') and not drawing:
        img_height, img_width = img.shape[0:2]

        if (ix >=0 and ix + width <= img_width) and (iy >= 0 and iy + height <= img_height):
            result = img[iy:iy + height, ix:ix + width, :]

            file_index = 1
            while True:
                if os.path.isfile('result_%d.jpg'%file_index):
                    file_index += 1
                else:
                    break

            cv2.imwrite('result_%d.jpg'%file_index, result) 

cv2.destroyAllWindows()

動作環境

Windows 11 と Ubuntu 20.04 on WSL2 の二つの環境で動作確認しています。

Windows 11

python 3.9.12
opencv-python==4.5.5.64

Ubuntu 20.04 on WSL2

python 3.9.5
opencv-python==4.5.5.64