12/9(月) 応用科学学会シンポジウムで自動運転に関する講演を担当します☆彡(試乗会もあります!来て!)

クリックでかんたん画像領域抽出「vcclick」チュートリアル

vcclickとは

概要

画像をクリックして「複数点の座標」や「多角形領域」をお手軽に抽出できる無料のPythonパッケージです。読み方は「ぶいしーくりっく」です。

  • 画像に複数の点を打って座標を調べたい
  • 画像に複数の点や線を描画したい
  • 画像の一部を切り抜きたい
  • 画像処理や機械学習のためにマスク画像を作成したい

このような場合に便利ではないかと思います。

利用環境&インストール方法

WondowsのWinPython3.6をおすすめしています。Google Colabでは動作しません(確定)。MacOSでも動作しません(2021/4/25時点)。

WinPython - Browse /WinPython_3.6/3.6.7.0 at SourceForge.net
Portable Scientific Python 2/3 32/64bit Distribution for Windows

pipでインストールできます。

pip install vcclick
サンプルコード

任意の画像またはこちらのサンプル画像でお試しください。入力画像は cv2.imread() で読み込んだBGR順のndarrayです。

import cv2
import matplotlib.pyplot as plt
from vcclick import vcclick

#ファイル名
image_file = 'vcclick-sample.jpg'

#画像の読み込み
img = cv2.imread(image_file)

#vcclickでクリック座標を取得
points = vcclick().single(img)
print(points)

ウィンドウが立ち上がります。左クリックで点を繋ぎ最後の点で右クリックします。ウィンドウは自動的に閉じます。下の例は左・左・左・左と4点を繋ぎ、最後に右クリックをしようとしている場面です。

------------------------------------
resizing in window size (750, 1000)      # 元画像をウィンドウサイズにリサイズします
(w, h) = (1944, 2592)                    # 元画像サイズ
(w, h) = (750, 1000)                     # ウィンドウ画像サイズ
points[0] = (293, 312)                   # クリックした座標(x, y)
points[1] = (456, 317)
points[2] = (467, 458)
points[3] = (363, 619)
points[4] = (268, 444)
return in original size (1944, 2592)     # 座標は元画像のスケールに戻して返されます
------------------------------------
[[ 759.456  808.704]
 [1181.952  821.664]
 [1210.464 1187.136]
 [ 940.896 1604.448]
 [ 694.656 1150.848]]

コンソールに結果が表示されました。クリックした5つの座標をndarray形式で取得できました。

その他のサンプルコード

マーク済み画像も取得できる

曲線のようにポチポチと点を繋いで、線が書き込まれた画像も取得してみます。

import cv2
import matplotlib.pyplot as plt
from vcclick import vcclick

#ファイル名
image_file = 'vcclick-sample.jpg'

#画像の読み込み
img = cv2.imread(image_file)

#vcclickでクリック座標を取得(マーク済み画像も取得)
myclick = vcclick()
points = myclick.single(img)
print(points)

#マーク済み画像を取得
img_draw = myclick.get_draw()
plt.imshow(cv2.cvtColor(img_draw, cv2.COLOR_BGR2RGB))
plt.show()
------------------------------------
resizing in window size (750, 1000)
(w, h) = (1944, 2592)
(w, h) = (750, 1000)
points[0] = (312, 327)
points[1] = (309, 364)
points[2] = (310, 410)
points[3] = (330, 442)
points[4] = (363, 452)
points[5] = (405, 447)
points[6] = (429, 420)
points[7] = (430, 373)
points[8] = (424, 329)
return in original size (1944, 2592)
------------------------------------
[[ 808.704  847.584]
 [ 800.928  943.488]
 [ 803.52  1062.72 ]
 [ 855.36  1145.664]
 [ 940.896 1171.584]
 [1049.76  1158.624]
 [1111.968 1088.64 ]
 [1114.56   966.816]
 [1099.008  852.768]]
ウィンドウサイズやマーカーオプションを指定できる

いくつかのオプションを指定してみます。ウィンドウサイズを長辺800ピクセル、ガイド線を、マーカーを、点を繋ぐ線分をなしにしてみます。

import cv2
import matplotlib.pyplot as plt
from vcclick import vcclick

#ファイル名
image_file = 'vcclick-sample.jpg'

#画像の読み込み
img = cv2.imread(image_file)

#vcclickでクリック座標を取得(マーク済み画像も取得)(オプション等)
myclick = vcclick()
points = myclick.single(img, window_size=800, guide=(255, 0, 0), marker=(255, 255, 255), line=None)
print(points)

#マーク済み画像を取得
img_draw = myclick.get_draw()
plt.imshow(cv2.cvtColor(img_draw, cv2.COLOR_BGR2RGB))
plt.show()
------------------------------------
resizing in window size (375, 500)
(w, h) = (1944, 2592)
(w, h) = (375, 500)
points[0] = (146, 154)
points[1] = (230, 155)
points[2] = (234, 235)
points[3] = (181, 312)
points[4] = (134, 226)
return in original size (1944, 2592)
------------------------------------
[[ 756.864  798.336]
 [1192.32   803.52 ]
 [1213.056 1218.24 ]
 [ 938.304 1617.408]
 [ 694.656 1171.584]]

デフォルトよりもやや小さいウインドウが立ち上がり、マーカー等は指定通りになっています(左図)。取得したマーク済み画像にもオプションが反映されています(右図)。

マスク配列も取得できる

クリックして点を繋いだ多角形領域のマスク配列も取得できます。マスク配列は物体抽出やセグメンテーションデータ作成に利用できます。

import cv2
import matplotlib.pyplot as plt
from vcclick import vcclick

#ファイル名
image_file = 'vcclick-sample.jpg'

#画像の読み込み
img = cv2.imread(image_file)

#vcclickでクリック座標を取得(マスク配列も取得)
myclick = vcclick()
points = myclick.single(img)
print(points)

#マスク配列を取得
mask = myclick.get_mask()
print(mask)
plt.imshow(mask)
plt.show()
------------------------------------
resizing in window size (750, 1000)
(w, h) = (1944, 2592)
(w, h) = (750, 1000)
points[0] = (312, 327)
points[1] = (422, 326)
points[2] = (438, 335)
points[3] = (451, 405)
points[4] = (447, 462)
points[5] = (419, 513)
points[6] = (368, 588)
points[7] = (320, 524)
points[8] = (303, 491)
points[9] = (291, 443)
points[10] = (302, 379)
return in original size (1944, 2592)
------------------------------------
[[ 808.704  847.584]
 [1093.824  844.992]
 [1135.296  868.32 ]
 [1168.992 1049.76 ]
 [1158.624 1197.504]
 [1086.048 1329.696]
 [ 953.856 1524.096]
 [ 829.44  1358.208]
 [ 785.376 1272.672]
 [ 754.272 1148.256]
 [ 782.784  982.368]]
[[False False False ... False False False]
 [False False False ... False False False]
 [False False False ... False False False]
 ...
 [False False False ... False False False]
 [False False False ... False False False]
 [False False False ... False False False]]

True/Falseからなるマスク配列が取得できました(右図)。元画像のndarray次元が (2592, 1944, 3) であるのに対し、マスク配列の次元は (2592, 1944) であることにご注意ください。

複数の領域を抽出できる

実行コマンドを myclick.single() から myclick.multi() に変えることで、一度に複数の領域を抽出することができます。オプションも同様に機能します。

import cv2
import matplotlib.pyplot as plt
from vcclick import vcclick

#ファイル名
image_file = 'vcclick-sample.jpg'

#画像の読み込み
img = cv2.imread(image_file)

#vcclickでクリック座標を取得(複数の多角形領域)(マーク済み画像も取得)(マスク配列も取得)
myclick = vcclick()
points = myclick.multi(img)
print(points)

#マーク済み画像を取得
img_draw = myclick.get_draw()
plt.imshow(cv2.cvtColor(img_draw, cv2.COLOR_BGR2RGB))
plt.show()

#マスク配列を取得
mask = myclick.get_mask()
print(mask)
plt.imshow(mask)
plt.show()

ウィンドウでは「左→左→・・・→右」で一つの多角形をマークする作業を複数回繰り返すことができます。すべてマークし終えたらウィンドウ右上の閉じるボタンまたはマウスの中クリックで終了します。

------------------------------------
resizing in window size (750, 1000)
(w, h) = (1944, 2592)
(w, h) = (750, 1000)
points[0] = (181, 153)
points[1] = (539, 153)
points[2] = (542, 280)
points[3] = (183, 279)
points[0] = (313, 325)
points[1] = (423, 325)
points[2] = (437, 333)
points[3] = (453, 425)
points[4] = (436, 484)
points[5] = (435, 550)
points[6] = (585, 551)
points[7] = (723, 597)
points[8] = (708, 612)
points[9] = (14, 608)
points[10] = (2, 595)
points[11] = (159, 552)
points[12] = (307, 551)
points[13] = (306, 498)
points[14] = (291, 439)
points[0] = (124, 673)
points[1] = (531, 674)
points[2] = (559, 710)
points[3] = (75, 707)
return in original size (1944, 2592)
------------------------------------
[array([[ 469.152,  396.576],
       [1397.088,  396.576],
       [1404.864,  725.76 ],
       [ 474.336,  723.168]]), array([[ 811.296,  842.4  ],
       [1096.416,  842.4  ],
       [1132.704,  863.136],
       [1174.176, 1101.6  ],
       [1130.112, 1254.528],
       [1127.52 , 1425.6  ],
       [1516.32 , 1428.192],
       [1874.016, 1547.424],
       [1835.136, 1586.304],
       [  36.288, 1575.936],
       [   5.184, 1542.24 ],
       [ 412.128, 1430.784],
       [ 795.744, 1428.192],
       [ 793.152, 1290.816],
       [ 754.272, 1137.888]]), array([[ 321.408, 1744.416],
       [1376.352, 1747.008],
       [1448.928, 1840.32 ],
       [ 194.4  , 1832.544]])]

返ってきた座標の配列はndarrayが複数入ったリスト形式になっていますのでご注意ください。マーク済み画像とマスク配列を得ることができました。

メソッドとオプション

実行メソッド

シングル領域用とマルチ領域用の2種類です。

#シングル
myclick = vcclick()
points = myclick.single(img)

#マルチ
myclick = vcclick()
points = myclick.multi(img)
オプション

実行メソッドに与えるオプションは以下のとおりです。

オプションデフォルト意味
window_size1000モニターに表示するウィンドウの長辺サイズです(単位はピクセル)。モニターに大きく表示したほうが正確にクリックできるため、モニターサイズに応じて適宜ご指定ください。
<例>
window_size=800
guide(0, 255, 0)カーソルに追随する十字のガイド線の色です。見やすい色をご指定ください。
<例>
guide=None #ガイド線なし
guide=(0, 255, 0) #緑
marker(255, 0, 0)マーカー(クリックした点)の色です。見やすい色をご指定ください。
<例>
marker=None #マーカーなし
marker=(255, 0, 0) #赤
line(0, 255, 0)マーカー(クリックした点)を繋ぐ線分の色です。見やすい色をご指定ください。
<例>
line=None #線分なし
line=(0, 255, 0) #緑
points_numNone指定した数の点で強制終了させます。右クリックで終了する(区切る)必要がありません。
<例>
points = myclick.single(img, points_num=4) #4点で終了
points = myclick.multi(img, points_num=3) #3点毎に区切る
return_size‘original’(試運転中)
‘original’ の場合、返り値の座標は入力された画像サイズを基準にします。’original’ 以外が指定された場合、ウィンドウサイズを基準にした座標が取得できます。
<例>
return_size=None #ウィンドウサイズ基準で返す
結果取得用メソッド

マーク済み画像とマスク配列を取得できます。

#マーク済み画像
img_draw = myclick.get_draw()

#マスク配列
mask = myclick.get_mask()

役に立つTips

マスクの適用例

マスク配列取得後、元画像にマスクを適用します。

import numpy as np
from copy import deepcopy

#物体以外を黒塗りにした画像
img_mask = deepcopy(img)
img_mask[mask==False] = 0
plt.imshow(cv2.cvtColor(img_mask, cv2.COLOR_BGR2RGB))
plt.show()

#物体を囲む矩形を切り出した画像
tmp = np.where(mask==True)
x1, x2, y1, y2 = np.min(tmp[1]), np.max(tmp[1]), np.min(tmp[0]), np.max(tmp[0])
img_crop = img_mask[y1:y2, x1:x2]
plt.imshow(cv2.cvtColor(img_crop, cv2.COLOR_BGR2RGB))
plt.show()
活用例

こんな感じで活用しています。

ライセンス

不明点はお気軽にお問い合わせください。

「vcclick を使ってみたブログを書く」○(著作権表示が必要)
「みんなも vcclick 使おうよ!」○
「vcclick を利用した商品を売る」○(著作権表示が必要)
「vcclick は私が作りました!」×
「vcclick のソースコードを修正する」×
「vcclick のラッパーを作成する」○(著作権表示が必要)

著作権表示

vcclickを使用してできた著作物(商品、論文、設計、プログラム、ブログ記事等)を不特定多数の人々が閲覧できる場所に公開する際には、vcclickが直接的または間接的に貢献したかにかかわらず、必ず著作権表示をしなければなりません。ただしこれは、

  • vcclickがビネット&クラリティ(=ビネクラ)によって作られたことが明示されていること
  • ビネット&クラリティのURL(https://vigne-cla.com/ または同/vcclick-tutorial/)が明示されていること

の両方が満たされていれば良いこととし、端的には

※vcclickはビネクラ(https://vigne-cla.com/)のソフトです

といった注釈を、十分な視認性を保って記載すれば良いこととします。また、二次的な営利利用にも本ライセンスを適用しなければなりません。例外として、vcclickの名称や機能のみを紹介した場合や、vcclickの名称や機能のみをデータベースの一要素として列挙した場合はこの限りではありません。

できること

個人利用、商用利用、創作物(商品、論文、設計、プログラム、ブログ記事等)の公開

禁止事項

ソースコードの修正・複製、pipを経由しないソースコードの配布、vcclickそのものやvcclickを利用した技術にかかる特許の出願・取得、トレードマークの主張

免責事項

vcclickを用いたことで生じたいかなる損害の補償もしかねます。

更新予定

MacOSへの対応(苦戦中)

更新履歴

1.0.9points_numオプションを追加
1.0.8multi()に中クリック終了機能を追加
1.0.5マーカーサイズの修正
1.0.4安定版公開

SNS等でお気軽にご連絡ください

※当ブログに関することは何でもご相談・ご依頼可能です(Servicesになくても)
※TwitterはFF外の場合はDMではなく返信orメンションでお願いしますm(_ _)m

情報発信しています

質問・コメントはSlackやDiscordでお気軽に

勉強会の告知はこちらで

vcclick
この記事を書いた人

博士(理学)。専門は免疫細胞、数理モデル、シミュレーション。米国、中国で研究に携わった。遺伝的アルゴリズム信者。物価上昇のため半額弁当とともに絶滅寸前。

この記事をシェアする
Vignette & Clarity(ビネット&クラリティ)
タイトルとURLをコピーしました