1
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.

Alibaba Cloud Advent Calendar 2020

Day 18

Alibaba Cloud OSS 内にある同一画像を除去する

Last updated at Posted at 2020-12-20

この記事は 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 プログラムを作りました。

処理内容

  1. 実行引数で指定されたカテゴリIDディレクトリ内の画像ファイル一覧を取得する
  2. 画像ファイル一覧の先頭画像から1枚ずつ、次の画像ファイルと同一判定をする
  3. 同一であれば次の画像ファイルを同一画像リストに追加する
  4. 最後の画像ファイルとの比較が完了したら、画像ファイル一覧及びディレクトリ内から同一画像リストの画像を削除する
    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 プログラム

search_same_image.py
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 はオプションが豊富なので、プログラムを組む必要がないのがありがたいです。

1
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
1
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?