0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

アノテーション確認ツールを作成してみた。 サムネイル編

Last updated at Posted at 2021-07-01

#背景
アノテーションを行った画像をなるべく少ない労力で確認したい

#既存の確認方法の問題点
アノテーションデータをopenCVで画像に加工してエクスプローラーにあるサムネイルで確認すると楽にはなるが、画像間の空白が広いためにスクロール量が増え、その度に読込が走るため確認速度が思うように上がらない。


#解決策
サムネイルを自分で作ればいいじゃん、ということで作ってみました。
予想以上にめんどくさかった・・・・。
コマンドプロンプトで叩けば動きます。
※画像ごとのアスペクト比は維持されます。

実行方法
 python my_thumbnail.py
入力:
 1.画像フォルダパス
 2.サムネイルにした時の列数
 3.出力フォルダパス
出力:
 1.サムネイル画像 (jpg形式)
 2.画像の横に表示される番号とファイル名の対応リスト (カンマ区切り形式)


#コード

my_thumbnail.py
from enum import Enum
import numpy as np
import cv2
import glob
import os

class MyColor(Enum):
    BLACK  = (0,0,0)
    WHITE  = (255,255,255)

def main():
    concat_img()

def concat_img():
    img_file_list = []
    in_dir         = input("入力フォルダを指定: ") + "/"
    img_array_num  = int(input("画像連結時の列数を指定: "))
    out_dir        = input("出力フォルダを指定: ") + "/"
    ############################
    # 縦連結画像の保存(画像1)
    ############################
    for i in range(img_array_num):
        im_list, fn_list               = collect_image_mod(in_dir+"*.jpg", img_array_num, i)
        tmp_img_name                   = out_dir+str(i)+"_tmp.jpg"
        im_list_resize, img_array_list = vconcat_resize_min(i,list(im_list),list(fn_list))
        img_file_list.append(img_array_list)
        cv2.imwrite(tmp_img_name, im_list_resize)
    ############################
    # 画像の横連結(画像2)
    ############################
    im_list      = collect_image(out_dir+"*.jpg")
    out_img_name = out_dir + "out.jpg"
    img          = hconcat_resize_min(list(im_list))
    cv2.imwrite(out_img_name,img)
    ############################
    # 画像の一覧作成
    ############################
    with open(out_dir+"img_list.txt", 'w') as f:
        for array_list in img_file_list:
            for file in array_list:
                f.write("%s\n" % file)
    ############################
    # 一時画像(画像1)の削除
    ############################
    for i in range(img_array_num):
        tmp_img_name = out_dir+str(i)+"_tmp.jpg"
        os.remove(tmp_img_name)

def collect_image(dir):
    im_list = []
    files = sorted(glob.glob(dir))
    for file in files:
        img = cv2.imread(file)
        assert img is not None, "読み込みに失敗しました"
        im_list.append(img)
    return im_list

def collect_image_mod(dir,mod,cls):
    im_list  = []
    fn_list  = []
    files = sorted(glob.glob(dir))
    for i,file in enumerate(files):
        if i%mod==cls:
            img = cv2.imread(file)
            assert img is not None, "読み込みに失敗しました"
            im_list.append(img)
            fn_list.append(os.path.splitext(os.path.basename(file))[0])
    return im_list, fn_list

def hconcat_resize_min(im_list, interpolation=cv2.INTER_CUBIC):
    h_max = max(im.shape[0] for im in im_list)
    im_list_border = [cv2.copyMakeBorder(im, 1, h_max-im.shape[0], 1, 1, cv2.BORDER_CONSTANT, value=MyColor.BLACK.value)
                      for im in im_list]
    return cv2.hconcat(im_list_border)
    
def vconcat_resize_min(mod_num, im_list, fn_list):
    file_list  = []
    w_min = min(im.shape[1] for im in im_list)
    im_list_resize = [cv2.resize(im, (w_min, int(im.shape[0] * w_min / im.shape[1])), cv2.INTER_CUBIC) for im in im_list]
    text_area_with = len(str(mod_num))*50 + len('-')*50 + len(str(len(im_list_resize)))*50
    for i,img in enumerate(im_list_resize):
        img_num_str = str(mod_num) + '-' + str(i)
        img_num_len = len(img_num_str)
        img = cv2.copyMakeBorder(img, 1, 1, text_area_with, 1, cv2.BORDER_CONSTANT, value=MyColor.BLACK.value)
        img = cv2.putText(img, img_num_str, (0, 50), cv2.FONT_HERSHEY_PLAIN, 4, MyColor.WHITE.value, 4, cv2.LINE_AA)
        im_list_resize[i] = img
        file_list.append(img_num_str + ", " + fn_list[i])
    return cv2.vconcat(im_list_resize), file_list

main()

#実行例1(列数2で実行)
out.jpg

img_list.txt
0-0, barley-field-1684052__340
0-1, bridge-53769__340
0-2, fantasy-3077928__480
0-3, forest-931706__340
0-4, istockphoto-1054985458-170667a
0-5, istockphoto-1206377870-170667a
0-6, istockphoto-1254013331-170667a
0-7, istockphoto-516449022-170667a
0-8, mountain-landscape-2031539__340
0-9, railroad-163518__340
0-10, road-1072823__480
0-11, sea-164989__340
0-12, sunset-3325080__340
1-0, beach-418742__340
1-1, fantasy-3077928__340
1-2, forest-1072828__340
1-3, hills-615429__340
1-4, istockphoto-1141688597-170667a
1-5, istockphoto-1224783016-170667a
1-6, istockphoto-1254564400-170667a
1-7, istockphoto-525670203-170667a
1-8, mountains-1587287__340
1-9, road-1072821__340
1-10, road-220058__340
1-11, sunset-1373171__340
1-12, tree-736885__340

#実行例2(列数10で実行)
out.jpg

img_list.txt
0-0, barley-field-1684052__340
0-1, istockphoto-1206377870-170667a
0-2, road-1072823__480
1-0, beach-418742__340
1-1, istockphoto-1224783016-170667a
1-2, road-220058__340
2-0, bridge-53769__340
2-1, istockphoto-1254013331-170667a
2-2, sea-164989__340
3-0, fantasy-3077928__340
3-1, istockphoto-1254564400-170667a
3-2, sunset-1373171__340
4-0, fantasy-3077928__480
4-1, istockphoto-516449022-170667a
4-2, sunset-3325080__340
5-0, forest-1072828__340
5-1, istockphoto-525670203-170667a
5-2, tree-736885__340
6-0, forest-931706__340
6-1, mountain-landscape-2031539__340
7-0, hills-615429__340
7-1, mountains-1587287__340
8-0, istockphoto-1054985458-170667a
8-1, railroad-163518__340
9-0, istockphoto-1141688597-170667a
9-1, road-1072821__340

#最後に
単体の画像はpixabayさまよりダウンロードいたしました。
ありがとうございます、感謝しかないです。
https://pixabay.com/ja/

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?