この記事は Alibaba Cloud Advent Calendar 2020 18日目の記事となります。(ちょいと遅れました)
この記事の背景
類似画像検索サービス Image Search への画像登録は、ストレージサービス OSS からのエクスポートでできます。
しかし、OSS 内にファイル名が異なる同一画像がある場合、同一画像が重複して登録されます。
その結果、画像検索結果に同一画像が返され、同一画像の重複を間引く必要が出てきます。
そこで、OSS 内にある同一画像を削除するべく、仮想サーバー ECS に OSS から画像をダウンロードし、OpenCV で同一画像判定をして、同一画像を削除したのち、OSS に画像を再アップロードしたいと思います。
※エクスポートについては公式ドキュメントをご参照ください。
ECS に OSS から画像をダウンロード
OSS には Image Search のカテゴリに従ってフォルダがあり、各フォルダ内に約700枚 ~ 10000枚の画像があります。
これらの画像を ossutil を使って、ECS に一括ダウンロードします。
インスタンスのスペックは 2vCPU 8GiB です。
使用したコマンドは cp で、--jobs
オプションで同時実行数を 100 に指定した結果、2分程度でダウンロードが完了しました。
OSS フォルダ構成
products
├── 0
├── 1
├── 2
├── 20
├── 21
├── 22
├── 3
├── 4
├── 5
├── 6
├── 7
├── 8
├── 88888888
└── 9
cp コマンド発行
ECS の images
ディレクトリに上記 OSS フォルダ構成で画像がダウンロードされます。
./ossutil64 cp --jobs=100 -f -r oss://バケット名/products/ images/
実行ログ
Scanned num: 11500, size: 937,891,951. Dealed num: 7673(download 7673 objects), OK size: 541,480,436, Speed: 1053
Scanned num: 20400, size: 2,033,138,975. Dealed num: 13068(download 13068 objects), OK size: 1,173,929,335, Speed
Scanned num: 39600, size: 4,868,303,380. Dealed num: 17742(download 17742 objects), OK size: 1,784,801,542, Speed
...
FinishWithError: Total num: 98039, size: 9,244,025,341. Error num: 1. OK num: 98038(download 98038 objects), Transfer size: 9,244,007,415.
average speed 100570000(byte/s)
91.921215(s) elapsed
実行結果
[root@ホスト名 ~]# ll images
total 4564
drwxr-xr-x 2 root root 458752 Dec 20 17:43 0
drwxr-xr-x 2 root root 634880 Dec 18 16:34 1
drwxr-xr-x 2 root root 446464 Dec 18 16:34 2
drwxr-xr-x 2 root root 417792 Dec 18 16:34 20
drwxr-xr-x 2 root root 180224 Dec 18 16:34 21
drwxr-xr-x 2 root root 352256 Dec 18 16:35 22
drwxr-xr-x 2 root root 438272 Dec 18 16:35 3
drwxr-xr-x 2 root root 819200 Dec 18 16:35 4
drwxr-xr-x 2 root root 589824 Dec 18 16:35 5
drwxr-xr-x 2 root root 69632 Dec 18 16:35 6
drwxr-xr-x 2 root root 122880 Dec 18 16:35 7
drwxr-xr-x 2 root root 65536 Dec 20 16:06 8
drwxr-xr-x 2 root root 40960 Dec 18 16:35 88888888
drwxr-xr-x 4 root root 4096 Dec 18 16:35 9
OpenCV で同一画像判定と同一画像削除
OpenCV で同一画像を判定し、同一画像を削除する Python プログラムを作りました。
処理内容
- 実行引数で指定されたカテゴリIDディレクトリ内の画像ファイル一覧を取得する
- 画像ファイル一覧の先頭画像から1枚ずつ、次の画像ファイルと同一判定をする
- 同一であれば次の画像ファイルを同一画像リストに追加する
- 最後の画像ファイルとの比較が完了したら、画像ファイル一覧及びディレクトリ内から同一画像リストの画像を削除する
-
- に戻り、画像ファイル一覧を最後まで比較する
つまり、10000枚画像があれば、n = 10000 となり、最高で
\begin{eqnarray*}
{}_n C _2 = 49,995,000
\end{eqnarray*}
回の処理を行うことになります。
14カテゴリあるため、ECS のスペックを 16vCPU 32GiB にして全ディレクトリを並行して処理していますが、17:40 から開始しても 22:40 現在、3カテゴリしか処理が完了していません。
CPU 使用率は 88% 前後なので、期待通りです。
Python プログラム
import os
import sys
import cv2
import numpy as np
path = './' + sys.argv[1] + '/'
files = os.listdir(path)
same_images = []
for file in files:
for comparison_file in files:
print('DIR:' + sys.argv[1] + ':FILE:' + str(files.index(file)) + ':COMPFILE:' + str(files.index(comparison_file)))
if files.index(file) >= files.index(comparison_file):
continue
img = cv2.imread(path + file)
comparison_img = cv2.imread(path + comparison_file)
if np.array_equal(img, comparison_img):
print('========================================FOUND SAME IMAGE :' + comparison_file + '========================================')
same_images.append(comparison_file)
if files.index(comparison_file) == len(files) - 1:
for delete_file in same_images:
os.remove(path + delete_file)
files.remove(delete_file)
same_images = []
実行コマンド
nohup python search_same_image.py 8 &
実行ログ
...
DIR:8:FILE:714:COMPFILE:711
DIR:8:FILE:714:COMPFILE:712
DIR:8:FILE:714:COMPFILE:713
DIR:8:FILE:714:COMPFILE:714
実行結果は如何程に
処理が完了した3カテゴリの処理前後の画像枚数を比較してみます。
100枚程度削除されていると、プログラムを組んだ甲斐があります。
処理途中の11カテゴリが楽しみです。
カテゴリID | 処理前枚数 | 処理後枚数 |
---|---|---|
0 | 9442 | 8899 |
1 | 9320 | 9262 |
2 | 8937 | 7535 |
20 | 5951 | 5739 |
21 | 3462 | 2978 |
22 | 6935 | 6803 |
3 | 7991 | 5931 |
4 | 15755 | 12342 |
5 | 12417 | 8741 |
6 | 817 | 767 |
7 | 1432 | 1237 |
8 | 848 | 715 |
9 | 6414 | 6091 |
88888888 | 740 | 740 |
OpenCV で Warning が出ている
処理途中でちょくちょく以下の Warning が出ています。
調査すると、PNG のメタデータが不正なため、ImageMagick による画像変換が必要なようですが、そのまま処理し続けています。
参考にしたページはこちら。 OpenCVで「libpng warning: iCCP: known incorrect sRGB profile」というエラーの対処法
libpng warning: iCCP: known incorrect sRGB profile
OSS に画像を再アップロード
ダウンロードと同じく、cp コマンドを使用します。
cp コマンド発行
ECS の images
ディレクトリから別の OSS バケットの products
フォルダに同構成で画像がアップロードされます。
ECS のスペックが上がっているので、同時実行数は 800 くらいでもいいかもしれません。
※同一画像判定 & 画像削除処理が終わっていないのでまだ実施していません。
./ossutil64 cp --jobs=800 -f -r images/ oss://バケット名/products/
まとめ
まだ何も終わっていないですが、今回のポイントは ossutil cp コマンドの同時実行数オプションです。かなり優秀です。
あっという間に画像がダウンロードされました。
ossutil はオプションが豊富なので、プログラムを組む必要がないのがありがたいです。