↓もし、良かったらSNSでの紹介よろしくお願いします。

OpenCV(Python)GUI基礎編、ペイントツールを作ってみた

bootstrap

簡単なペイントツールを作ってみた。

OpenCVのGUI基礎編、これが3回目です。1回は画像の表示、2回目は線の描画について解説しました。今回は簡単なペイントツールを作ってトラックバーについて解説します。

ペイントツール

# -*- coding: utf-8 -*-
import cv2
#sx, syは線の始まりの位置
sx, sy = 0, 0
#ペンの色
color = (0, 0, 0)
#ペンの太さ
thickness = 1
#マウスの操作があるとき呼ばれる関数
def callback(event, x, y, flags, param):
    global img, sx, sy, color, thickness
    #マウスの左ボタンがクリックされたとき
    if event == cv2.EVENT_LBUTTONDOWN:
        sx, sy = x, y
    #マウスの左ボタンがクリックされていて、マウスが動いたとき
    if flags == cv2.EVENT_FLAG_LBUTTON and event == cv2.EVENT_MOUSEMOVE:
        cv2.line(img, (sx, sy), (x, y), color, thickness)
        sx, sy = x, y
# トラックバーを変更したらペンを変更
def changePencil(pos):
    global color, thickness
    r = cv2.getTrackbarPos("R", "img")
    g = cv2.getTrackbarPos("G", "img")
    b = cv2.getTrackbarPos("B", "img")
    color = (b, g, r)
    thickness = cv2.getTrackbarPos("T", "img")
#画像を読み込む
img = cv2.imread("img.jpg")
#ウィンドウの名前を設定
cv2.namedWindow("img", cv2.WINDOW_NORMAL)
#マウス操作のコールバック関数の設定
cv2.setMouseCallback("img", callback)
#トラックバーのコールバック関数の設定
cv2.createTrackbar("R", "img", 0, 255, changePencil)
cv2.createTrackbar("G", "img", 0, 255, changePencil)
cv2.createTrackbar("B", "img", 0, 255, changePencil)
cv2.createTrackbar("T", "img", 1, 100, changePencil)
while(1):
    cv2.imshow("img", img)
    k = cv2.waitKey(1)
    #Escキーを押すと終了
    if k == 27:
        break
    #sを押すと画像を保存
    if k == ord("s"):
        cv2.imwrite("painted.png", img)
        break

このコードを実行すると次のような画面が現れます。画面を左クリックでなぞると線が描けます。

paint_tool1

このウィンドには4つのトラックバーが付いてます。RGBの3つのバーでペンの色を設定します。Tのトラックバーで線の太さを調整します。

トラックバーの解説

#トラックバーのコールバック関数の設定
cv2.createTrackbar("R", "img", 0, 255, changePencil)
cv2.createTrackbar("G", "img", 0, 255, changePencil)
cv2.createTrackbar("B", "img", 0, 255, changePencil)
cv2.createTrackbar("T", "img", 1, 100, changePencil)

cv2.createTrackbar(name, windowName, startPos, max, callback)でトラックバーを追加します。nameはトラックバーの名前です。windowNameはトラックを表示するウィンドウの名前です。

startPosはトラックバーが最初に表示されたときの初期値です。maxはトラックバーの目盛の最大値です。最小値は0なのは変えられません。callbackはトラックバーを変えたときに呼ばれる関数を設定します。

トラックバーのコールバック関数

# トラックバーを変更したらペンを変更
def changePencil(pos):
    global color, thickness
    r = cv2.getTrackbarPos("R", "img")
    g = cv2.getTrackbarPos("G", "img")
    b = cv2.getTrackbarPos("B", "img")
    color = (b, g, r)
    thickness = cv2.getTrackbarPos("T", "img")

トラックバーのコールバック関数はトラックバーの位置を引数として受け取ります。つまり、posには変更されたトラックバーの位置が入ってます。

けれど今回はトラックバーの位置をcv2.getTrackbarPosでトラックバーの位置を取得してます。これはペンの色を決めるには変更されたトラックバーの位置だけではなく他のトラックバーの位置も取得しなけらばいけないからです。

トラックバーが変更されたらグローバル変数のcolor,thicknessに値を入れます。colorはペンの色、thicknessはペンの太さを表しています。

カラーパレットの分離

pallete_bunri

このままだとペイントツールらしくないので、カラーパレットを別のウィンドに分離してみまた。

# -*- coding: utf-8 -*-
import cv2
import numpy as np
#sx, syは線の始まりの位置
sx, sy = 0, 0
#ペンの色
color = (0, 0, 0)
#ペンの太さ
thickness = 1
#マウスの操作があるとき呼ばれる関数
def callback(event, x, y, flags, param):
    global img, sx, sy, color, thickness
    #マウスの左ボタンがクリックされたとき
    if event == cv2.EVENT_LBUTTONDOWN:
        sx, sy = x, y
    #マウスの左ボタンがクリックされていて、マウスが動いたとき
    if flags == cv2.EVENT_FLAG_LBUTTON and event == cv2.EVENT_MOUSEMOVE:
        cv2.line(img, (sx, sy), (x, y), color, thickness)
        sx, sy = x, y
# トラックバーの値を変更する度にRGBを出力する
def changePencil(pos):
    global palette_img, color, thickness
    r = cv2.getTrackbarPos("R", "palette")
    g = cv2.getTrackbarPos("G", "palette")
    b = cv2.getTrackbarPos("B", "palette")
    palette_img[:] = [b, g, r]
    color = (b, g, r)
    thickness = cv2.getTrackbarPos("T", "palette")
#画像を読み込む
img = cv2.imread("img.jpg")
#パレット画像を作成
palette_img = np.zeros((200, 512, 3), np.uint8)
#ウィンドウの名前を設定
cv2.namedWindow("img", cv2.WINDOW_NORMAL)
#パレットウィンドを生成
cv2.namedWindow("palette")
#マウス操作のコールバック関数の設定
cv2.setMouseCallback("img", callback)
#トラックバーのコールバック関数の設定
cv2.createTrackbar("R", "palette", 0, 255, changePencil)
cv2.createTrackbar("G", "palette", 0, 255, changePencil)
cv2.createTrackbar("B", "palette", 0, 255, changePencil)
cv2.createTrackbar("T", "palette", 1, 100, changePencil)
while(1):
    cv2.imshow("img", img)
    cv2.imshow("palette", palette_img)
    k = cv2.waitKey(1)
    #Escキーを押すと終了
    if k == 27:
        break
    #sを押すと画像を保存
    if k == ord("s"):
        cv2.imwrite("painted.png", img)
        break

numpyインポート

# -*- coding: utf-8 -*-
import cv2
import numpy as np

単色画像を作るために、numpyをインポートしましょう。

パレットウィンドの生成

#パレットウィンドを生成
cv2.namedWindow("palette")

paletteという名前でウィンドを生成しましょう。

パレット画像の生成

#パレット画像を作成
palette_img = np.zeros((200, 512, 3), np.uint8)

np.zerosで高さが200、幅が512、各値が[0, 0, 0]の画像を生成します。

パレットに色を表示

cv2.imshow("palette", palette_img)

palette_imgに現在のペンの色を表示します。色情報の更新はトラックバーのコールバック関数から行います。

トラックバーの表示ウィンドの変更

後はトラックバーの表示ウィンドを変更をすれば完成です。

# トラックバーの値を変更する度にRGBを出力する
def changePencil(pos):
    global palette_img, color, thickness
    r = cv2.getTrackbarPos("R", "palette")
    g = cv2.getTrackbarPos("G", "palette")
    b = cv2.getTrackbarPos("B", "palette")
    palette_img[:] = [b, g, r]
    color = (b, g, r)
    thickness = cv2.getTrackbarPos("T", "palette")
#トラックバーのコールバック関数の設定
cv2.createTrackbar("R", "palette", 0, 255, changePencil)
cv2.createTrackbar("G", "palette", 0, 255, changePencil)
cv2.createTrackbar("B", "palette", 0, 255, changePencil)
cv2.createTrackbar("T", "palette", 1, 100, changePencil)