はじめ
python3とopenCVを使ってjpg画像が"イラスト"なのか"写真"なのか識別してみました.思っていたよりも参考資料がなかったので,ほぼ自前でやりました.
環境
・ Python 3.6.4
・ Windows 10
必要なモジュールは以下のとおりです
・opencv-python
opencv-pythonはpipでインストールできます.
$ pip install opencv-python
識別の手順
- 画像ファイルを読み込みむ
- 読み込んだ画像(オリジナル画像)をグレイスケール化し以下の画像を得る.(エッジ検出はキャニー法です)
3. グレイスケール化した画像からエッジ検出した画像(can_img)
4. グレイスケール化した画像をガウシアンフィルタでぼかしてからエッジ検出した画像(gau_can_img)
5. グレイスケール化した画像をメディアンフィルタでぼかしてからエッジ検出した画像(med_can_img) - can_imgとgau_can_imgとの差,can_imgとmed_can_imgとの差を計算し,その差を足す.
(イラストに比べて写真のほうがピントなどでぼけている部分があり,ぼかしを入れる前後で検出されるエッジの変化が大きいと予想したためこの差を識別に使用しました.また,イラストでは描かれているものの輪郭がはっきりしているものが多いと思ったりもしました) - オリジナル画像から各画素のRGBを取得し,最も多く現れる色がどのくらい頻度で現れているのかを算出する.
(イラストのほうが写真に比べて同じ色が含まれている量が多いと予想したためです) - 3,4で得られた値からスコアを算出して,イラストか写真か判別する.
まとめると...
「"ぼかしによるエッジ検出量の差"と"画像中で最も多く現れる色の出現頻度"をもとにスコアを算出し,そのスコアが一定以上ならイラスト,一定未満なら写真として識別する」
ということです.
スコアの算出
スコアは以下の式で算出しています.SCOREが0.5より高ければイラスト,低ければ写真と識別されます.
SCORE = ((1 / diff_result) * 0.8 + (color_result / 100) * 0.2) * 0.625
・ diff_result: 手順3で得られた結果
・ color_result: 手順4で得られた結果
diff_resultは画像をぼかしたときにエッジ検出量がどのくらい減ったかというものなので,この値が低いほどイラストとしてのスコアが高くなります.
color_resultは画像中で最も多く現れる色の出現頻度なので,この値が高いほどイラストしてのスコアが高くなります.
上のスコア算出の計算式は値を見ながら調整したものなので,最適ではないと思います.はい.
# 画像データ
画像データはpixivやフリーの写真素材サイトなどからとってきました.
ソースコード
githubにおいてあります.
https://github.com/suzuryu/ImageIdentification.git
画像サイズが大きい場合は,画像サイズを1/2に縮小しています.
識別はかなり大きな画像でなければ0~10秒程度で終わります.
(4032*3024より大きいものはわからないです.はい)
実行
ex) 実行例
イラストは著作権的なのが面倒なのでイラストやから.
$ python identifiesImage.py exmaple.jpg
score : 0.476 -->picture
$ python identifiesImage.py exmaple2.jpg
score : 0.351 -->picture
$ python identifiesImage.py exmaple3.jpg
score : 0.918 -->illust
結果 意外と良い
score: 0.8581 画像枚数: 2630枚 正解枚数: 2557枚
写真判定: 0.795
イラスト判定: 0.82
約2600件の画像で全体として識別率85%と結構いい感じに識別できました.写真をイラストとして識別しちゃうのが多かったです.
相性の悪いイラストや写真だと間違った識別をしやすくなると思います.
(写実的なイラスト,証明写真, 風景写真・イラスト etc..)