画像処理AIの開発では学習データや検出データとして様々な画像を扱いますが、必ずと言っていいほど加工が必要になってきます。AIモデルが認識できる画像形式は決まっている一方、顧客が持つ画像には様々な形式があるからです。
作業現場では各社専用の点検カメラ、車載カメラ、スマートフォン、デジカメなどが使われており、その設定も違います。よって出力する画像のファイル形式やサイズ、解像度、明度、撮影角度などが異なってきます。
AIモデルが良い精度を出すよう、これらの画像を加工するのもエンジニアの腕です。大変な割に裏の仕事なのであまり評価されないこともありますが、性能の良いAIを作るテクニックでもありますので、覚えて損はありません。
よく使うLinuxコマンド
- 画像のファイル形式を変換する
AIモデルで用いる画像ファイルのほとんどはJPGかPNG形式です。収集した画像が違う場合、変換をする必要があります。
1 2 |
$ mogrify -format jpg filename.tif (上記は tif -> jpg) |
- 画像の縦横サイズを調べる
画像サイズは大変重要で、AIモデルに適合するサイズか、サイズによって精度が違うのか、変換した後のサイズが正しいかなどを確認しながら進めます。
1 2 3 4 5 |
$ identify imagefile (結果例) imagefile 302x231+0+0 PseudoClass 16c 2122b GIF 1s (↑画像サイズ) |
- 画像の縦横サイズを変更する(リサイズ)
画像が歪まないよう縦横の尺度はそのままで拡大縮小する方法です。学習画像や検出画像のサイズを統一すると精度が高まる場合があります。また結果の比較をする際に使用します。切り抜くこと(トリミング、クロップ)とは違います。
1 2 |
$ mogrify -resize 1024x1024 imagefile (↑ 変更したいピクセルサイズ。ただし縦横比は維持する。) |
- 複数のファイル名を一度に変更する
AIでは大量のデータを扱うためよく使うコマンドです。
1 |
$ rename ’s/置換前の文字列/置換後の文字列/g’ *jpg |
よく使うOpenCV命令
OpenCVとはPythonライブラリの一つで、色々な画像処理を行うことができます。画像を読み込んだ後にたった1行か数行で難しいことができてしまいます。
- 画像の縦横サイズを変更する(OpenCV版リサイズ)
画像が歪まないよう縦横の尺度はそのままで拡大縮小する方法です。学習画像や検出画像のサイズを統一すると精度が高まる場合があります。また結果の比較をする際に使用します。切り抜くこと(トリミング、クロップ)とは違います。
1 2 3 4 |
import cv2 img = cv2.imread('imagefile') img = cv2.resize(img, dsize=(1024,1024)) # 変更後のピクセルサイズを指定 cv2.imwrite('imagefile2', img) |
- 画像を切り抜く(トリミング、クロップ)
画像サイズを他の画像と合わせる、他の画像と物体の大きさを合わせる、学習/検出したくない部分を削るなどの工夫をする際に使用します。
1 2 3 4 |
import cv2 img = cv2.imread('imagefile') img1 = img[Ybegin:Yend,Xbegin:Xend] # 縦横の範囲を指定 cv2.imwrite('imagefile2', img1) |
- 画像の反転
学習データを増やしたい(データ拡張といいます)時によく使用します。左右を反転させた画像を作ることで学習データを2倍にできます。上下反転もできます。ですが、文字なども反転してしまうためそのようなデータを学習してよいかは考えましょう。
1 2 3 4 |
import cv2 img = cv2.imread('imagefile') dst = cv2.flip(img,1) # 0=上下反転、1=左右反転 cv2.imwrite('imagefile2', dst) |
- 画像の回転
学習データを増やしたい(データ拡張といいます)時によく使用します。いくつか違う角度で回転させた画像を作ることで学習データを数倍にできます。ただ現実に有り得ない状態を学習しても意味がありませんので考えましょう。
1 2 3 4 5 6 7 8 9 10 |
import cv2 img = cv2.imread('imagefile') height = img.shape[0] width = img.shape[1] center = (int(width/2), int(height/2)) SCALE = 1.0 ANGLE = 45 # 回転角度を指定 trans = cv2.getRotationMatrix2D(center, angle , scale) img2 = cv2.warpAffine(img, trans, (width,height)) cv2.imwrite('imagefile2', img2) |
- 画像全体の明るさ変更
顧客の仕事内容によっては画像が暗いケースがあります。このような場合は明度を高めることによってAIの検出精度が上がり、人間の目でも確認できるようになります。また学習データを増やす際にも利用できます。
1 2 3 4 5 6 7 |
import cv2 img = cv2.imread('imagefile') CNTRST = 1.0 BLIGHT = 30 # 明るさを指定 img = CNTRST * img + BLIGHT img = np.clip(img, 0, 255).astype(np.uint8) cv2.imwrite('imagefile2', img) |
- ぼかしを入れる
学習データを増やしたい(データ拡張といいます)時に使用します。人の目では分からないぐらいのわずかなぼかしでも、AIモデルにとっては違うデータとなるためデータ拡張には有効です。
1 2 3 4 |
import cv2 img = cv2.imread('imagefile') img = cv2.GaussianBlur(img, (3, 3), 3) # 数字を増やすほどぼける cv2.imwrite('imagefile2', img) |
- 特定の色になっている箇所(物体)のみ抽出する
色を特徴とした物体検出をする時の事前確認や、学習データの要素を強調したい時、またセグメンテーション検出結果を確認する際などに使用します。
1 2 3 4 5 6 7 8 |
import cv2 import numpy as COLOR_LOWER = np.array([100,50,50]) # 色の範囲を指定。例は青系 COLOR_UPPER = np.array([110,255,255]) # 色の範囲を指定。例は青系 img = cv2.imread('imagefile') mask = cv2.inRange(img, COLOR_LOWER, COLOR_UPPER) output = cv2.bitwise_and(img, img, mask=mask) # 該当色の箇所以外を黒くする cv2.imwrite('imagefile2', output) |
- 特定の色になっている箇所の面積を求める(ピクセルをカウントする)
色を特徴とした物体検出をしたい時の事前確認や、セグメンテーション検出結果を確認したり比較したりする際に使用します。
1 2 3 4 5 6 7 8 9 |
import cv2 import numpy as COLOR_LOWER = np.array([100,50,50]) # 色の範囲を指定。左は青系。 COLOR_UPPER = np.array([110,255,255]) # 色の範囲を指定。左は青系。 img = cv2.imread('imagefile') mask = cv2.inRange(img, COLOR_LOWER, COLOR_UPPER) output = cv2.bitwise_and(img, img, mask=mask) # 該当色の箇所以外を0にする output_1ch = output.sum(axis=2) # 画像は奥行き3の行列であるため1つに合算する pic_pixel = np.count_nonzero(output_1chan) # 0以外のピクセルをカウント |
- 物体の輪郭(エッジ)を抽出する
物体の輪郭を抽出したい時に使用します。輪郭を強調した画像を作ると強力な学習になることがあります。
1 2 3 4 5 6 7 |
import cv2 EDGE_SENS = 100 # エッジ感度。小さいほど敏感に検出。 EDGE_LENGTH = 200 # こちらは200前後で固定を推奨。 img = cv2.imread('imagefile') img = cv2.cvtColor(img, cv2.COLOR_BGR2Lab) img = cv2.Canny(img, EDGE_SENS, EDGE_LENGTH) cv2.imwrite('imagefile2', img) |
- 2枚の画像を重ね合わせる
学習画像の要素を強調したい時や、元画像と検出結果を重ねて確認する際に使用します。
1 2 3 4 5 |
import cv2 img = cv2.imread('imagefile') img2 = cv2.imread('imagefile2') overlay_img = np.maximum(img, img2) # 3チャネルとも最大値をとると色の合成となる cv2.imwrite('outfile', overlay_img) |
- 2枚の画像を並べる
元画像と検出結果を比較したり、画像の変換前後を比べるなどの際に使用します。
1 2 3 4 5 |
import cv2 left_img = cv2.imread('imagefile') right_img = cv2.imread('imagefile2') concat_img = cv2.hconcat([left_img, right_img]) cv2.imwrite('imagefile3', concat_img) |
- 画像のキャンパスを変更
画像の大きさを変えずキャンパス(背景)のサイズを大きくしたい場合に使います。プログラムの仕様で画像サイズを統一しなければならないが画像は変えたくないというケースで使用します。
1 2 3 4 5 6 7 |
from PIL import Image CANVAS = (4032, 3024) # キャンバスのサイズ COLOR = (0,0,0) # 背景を黒にする場合 result = Image.new("RGB", CANVAS, COLOR) img = Image.open('imgfile') result.paste(img,(0,0)) result.save('imagefile2') |
以上、AI開発でよく使う画像処理を挙げました。
一つ一つは大したことではありませんが、AI精度をコツコツ高めるテクニックとしては有用です。
AI開発ではなかなか結果が出ずに諦めたくなることがあります。モデル側をいじってもあまり変わらないことがあるのです。このような時はデータ側をいじり倒してみてください。上記の組み合わせで何度か救われたことがあります。
くじけそうになった時、試してみてください。