機械学習を行おうと思うと、学習のためのデータを用意しないといけません。各種チュートリアルを行う際は、例えば、手書き文字画像(MNIST)が事前に用意されていて、ディープラーニングのCNN(畳み込みニューラルネットワーク)の実行コードを写経するだけで体験することができます。しかし実際には、データが用意されていることはありません。というのも、何かしらデータが存在していたとしても、それらは機械学習やディープラーニングの処理に適したものになっておらず、そのまま使っても良い性能を出せない状態であることがほとんどだからです。
そこで今回は、学習用データとして画像データを想定し、それを準備する為のツールを作ってみたので紹介します。ただ作るだけでは面白くないので、今はやりのJupyter Notebookで動作する、HTMLウィジェットである「ipywidgets」を用いて、対話型インターフェースを有したツールにしてみたいと思います。
実行環境の準備
以下の環境で実装しています。
- python 3.6.6(Anaconda Python)
- Jupyter Notebook 5.6
「ipywidgets」は、以下のコマンドなどでインストールできます。
1 |
conda install -c conda-forge ipywidgets==6.0.0 |
また、「matplotlib」の「ginput」を実行するにあたり、ライブラリ「wxpython」を求められたので、condaコマンドでインストールしました。
1 |
conda install wxpython |
実装コードと実行結果の説明
以下は、Jupyter Notebook での実装です。
1 2 3 4 5 6 7 8 9 10 11 12 |
import matplotlib matplotlib.use('WXAgg') import matplotlib.pyplot as plt import cv2 import glob import os import ipywidgets as widgets from ipywidgets import interact, IntSlider from IPython.display import clear_output from IPython.display import display |
- はじめにおまじないとして、以下のコードを「import matplotlib.pyplot as plt」より先に実行しないとうまく動きません 。
12import matplotlibmatplotlib.use('WXAgg')
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# 座標の取得処理 def get_position(img): fig = plt.figure(figsize=(10,5)) # 描画領域のサイズを指定 ax = fig.add_subplot(111) ax.imshow(img) positions = plt.ginput(n=-1, timeout=0, show_clicks=True, mouse_add=1, mouse_pop=3) # 入力を待機 # n: Number of mouse clicks to accumulate. If negative, accumulate clicks until the input is terminated manually. # timeout: Number of seconds to wait before timing out. If zero or negative will never timeout. # show_clicks: If True, show a red cross at the location of each click. # mouse_add: Mouse button used to add points. # mouse_pop: Mouse button used to remove the most recently added point. # mouse_stop: Mouse button used to stop input. # 上記の mouse_add、mouse_pop、mouse_stop について、 # 入力値は次の操作を意味する # ⇒ 1:左クリック, 2:ミドルクリック, 3:右クリック. return positions[-2:] # 最後の2点の座標のみを返す |
- 今回の1つ目のメイン処理が「plt.ginput」になります。
- 実行すると以下のようなウィンドウが表示され、ユーザによる操作を待機し続けます。
- フッターにある虫眼鏡のアイコンをクリックしてONにしてから、上部の画像をドラッグすると、選択領域のみが拡大表示されます。
- フッターにある「←」「→」アイコンはそれぞれ、「操作を1つ戻す」「操作を1つ進める」という操作ができます。
- パラメータ「n」を「-1」、「timeput」を「0」にすることで、表示されるウィンドウをユーザが閉じるまで、操作を受け付けます。
- パラメータ「mouse_add」を「1」にすることで、左クリックした箇所の座標が取得されます。
- パラメータ「mouse_pop」を「3」にすることで、右クリックする度に、1つ前にクリックした箇所を取り除いてくれます。
- 上記パラメータの設定値には1~3が指定でき、それぞれ以下のように対応しています。
{1:左クリック、2:ミドルクリック、3:右クリック} - パラメータ「show_clicks」を「True」にすることで、クリックした箇所に自動的にマークがつきます。
- 実行すると以下のようなウィンドウが表示され、ユーザによる操作を待機し続けます。
1 2 3 4 5 |
# ファイルの情報 target_dir = "./data/" # 読み込みファイルのあるフォルダ output_dir = "./output/" # 出力先フォルダ target_files = glob.glob(target_dir+"*.png") # 読み込み対象ファイルの取得 |
- ファイル名をパターンマッチングで指定することで、複数のファイルを連続して処理できるようにしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
def main(btn): for file_name in target_files: dpi, format_ext= btn.description.split(",") dpi = int(dpi) print("処理ファイル: {} , DPI: {}, FORMAT: {}".format(file_name, dpi, format_ext)) img = plt.imread(file_name, format = "png") # ファイルの読み込み positions = get_position(img) # 座標の取得 if len(positions) < 2: # 2点以上の入力がない場合 print("2点以上をクリックしてください") continue # 取得座標の分解 x1 = int(positions[0][0]) x2 = int(positions[1][0]) y1 = int(positions[0][1]) y2 = int(positions[1][1]) x_min = min(x1,x2) x_max = max(x1,x2) y_min = min(y1,y2) y_max = max(y1,y2) # 画像の切り抜き img_cliped = img[y_min:y_max, x_min:x_max, :] # ファイルの保存 tmp = os.path.basename(file_name) tmp = os.path.splitext(tmp) save_file_name = output_dir+tmp[0]+"-"+str(dpi)+"."+format_ext plt.imsave(save_file_name, img_cliped, format = format_ext, dpi=dpi) print("Finish") |
1 2 3 4 5 6 |
dpi_slider = IntSlider(min=30, max=300, step=10, value=100, description="dpi") @interact(dpi=dpi_slider, format_ext=["png","jpg"]) def display_botton(dpi, format_ext): button_exec = widgets.Button(description=str(",".join([str(dpi),format_ext]))) # ボタンオブジェクトを作成 button_exec.on_click(main) # クリックしたときのイベントをハンドリング display(button_exec) |
- 上記を実行すると、以下のような対話型UIが表示されます。
- スライダー「dpi」は、「30」~「300」の間で、「10」刻みで指定可能です。
- ちなみに、この値は、「画像を保存する際の解像度」になります。
- リスト「format_ext」は、「png」「jpg」から選択可能です。
- ちなみに、この値は、「保存するファイルのフォーマット(拡張子)」になります。
- 入力欄の指定内容に従い、一番下にあるボタンのキャプションが変わります。
- スライダー「dpi」は、「30」~「300」の間で、「10」刻みで指定可能です。
使ってみよう
- 上から順に全てのセルを実行したいので、 Kernel メニューの Restart & Run All を実行します。
- 最下部にある入力欄を選択します。
- dpi:40
- format_ext:jpg
- ボタン「40,jpg」をクリックします。
- 立ち上がったウィンドウで切り抜きたい箇所を2か所クリックします。
- ウィンドウを閉じます(右上の「×」をクリック)
- 出力先を確認すると、ファイル「top-50years-b-40.jpg」が作成されています。
- 指定した箇所が切り取られています。
- ファイルのプロパティを確認すると、指定した解像度になっていることが確認できます。
- ※今回は指定ディレクトリにファイルを1つしか置いていなかったので、これで処理が終了しますが、ループしているので、ファイルが複数あれば、連続して、ファイル操作を行うことができます。
まとめ
データ分析において、データ前処理の活動は、重要であり、時間も必要とします。少しでもこの活動を効率的に行うためには、このような準備作業も重要になります。是非、各種ツールを作って、チームに共有しましょう。
執筆者プロフィール
- 入社以来、C/S型の業務システム開発に従事してきました。ここ数年は、SalesforceやOutSystemsなどの製品や、スクラム開発手法に取り組み、現在のテーマは、DeepLearning/機械学習です。
この執筆者の最新記事
- Pick UP!2021.11.11VoTTを複数人で使って、アノテーションを行いたい!(ファイル移行を用いて)
- Pick UP!2020.11.20AIoTデバイス「M5StickV」、はじめの一歩
- RPA2019.08.15「OSSのRPA」+「自作の三目並べマシン」でGoogleに挑む!
- AI2019.04.22暗記学習(Rote Learning)で三目並べを強くする