プログラミングの芽

面白そうな技術を使って、楽しいことやりたい

アノテーション情報(座標)から画像をトリミングして保存する

今回は大量の画像を一括で処理することを目的とします。
数枚であればプログラム数行でできます。

前提として以下のようなlabels.csvファイルとそれに対応した画像があるとします。
f:id:atarms:20190130205640p:plain
filename: ファイル名
width height: 画像ファイルのサイズ
class: 分類ラベル
xmin ymin xmax ymax: 画像内のどこに分類ラベルに該当する画像があるのかを示すバウンディングボックス座標
今回使うのはfilename、xmin、ymin、xmax、ymax

必要なもの

import numpy as np
import csv
import cv2


アノテーションファイル.csvの情報を扱いやすいように配列に入れる。

csv_data=[]
with open("labels.csv","r", encoding='UTF-8') as f:
    reader = csv.reader(f)
    header = next(reader) #headerを読み飛ばす
    for line in f: #1行ずつ読み込む(行数分でfor)
        line = line.rstrip("\n").split(",")
        csv_data.append(line) #csv_data[]に1行ずつ追加
csv_data=np.array(csv_data,dtype="unicode") #numpy配列に変換
print(csv_data.shape)
print(csv_data[:,:]) #データ、要素の2次元配列

>>(631, 8)
[['01.jpg' '4032' '3024' ... '612' '1288' '1778']
 ['01.jpg' '4032' '3024' ... '819' '2768' '1912']
 ['02.jpg' '4032' '3024' ... '878' '2477' '1951']
 ...
 ['49.jpg' '4032' '3024' ... '2151' '2795' '2612']
 ['49.jpg' '4032' '3024' ... '607' '2043' '1101']
 ['49.jpg' '4032' '3024' ... '107' '1954' '596']]


画像のディレクトリ+先ほどの配列1列目を結合した画像パスを別の配列に入れる
今回は相対パスで作業を進めます。

dir_path="./" #画像のディレクトリ
img_path=[]
cnt=(csv_path.shape[0]) #データ数をcntに代入
for i in range(cnt): #cnt分繰り返す
    img_path.append(dir_path+csv_path[i,0]) #img[]に1枚ずつ読み込み
img_path=np.array(img_path) #画像パスの1次元配列
print(img_path)

>>['./01.jpg' './01.jpg' './02.jpg' './02.jpg' './03.jpg' './03.jpg'
 './04.jpg' './04.jpg' './05.jpg' './05.jpg' './06.jpg' './06.jpg'
...
 './49.jpg' './49.jpg' './49.jpg' './49.jpg' './49.jpg' './49.jpg'
 './49.jpg']


ついでにバウンディングボックスの座標も取り出しておく

bbox=[]
cnt=(csv_data.shape[0]) #データ数をcntに代入
for i in range(cnt): #データ数分繰り返す
    bbox.append(csv_data[i,4:]) #bbox[]にバウンディングボックスの座標を1つずつ格納
bbox=np.array(bbox,dtype="int64") 
print(bbox)

>>[[ 125  612 1288 1778]
 [1668  819 2768 1912]
 [1413  878 2477 1951]
 ...
 [2336 2151 2795 2612]
 [1570  607 2043 1101]
 [1466  107 1954  596]]


img_pathとbboxを使って画像をトリミング後、指定フォルダに保存

cnt = (csv_data.shape[0])
for i in range(cnt): #ラベル分処理する
    img_array = cv2.imread(img_path[i]) #i番目の画像を読み込み
    dst = img_array[(bbox[i,1]):(bbox[i,3]),(bbox[i,0]):(bbox[i,2])] #i番目の座標を使ってトリミング
    cv2.imwrite('./coin/coin{0}.jpg'.format(i), dst) #coin[i].jpgで保存

以上のプログラムよって以下の画像から
f:id:atarms:20190129195810j:plain:w500
以下の2枚の画像に分割できます。
f:id:atarms:20190129195836j:plain:w200 f:id:atarms:20190129195844j:plain:w200