pythonで２つの画像を比較してその差異を分かりやすく示すための画像を新たに生成するプログラムを作ってみた

pythonで２つの画像を比較してその差異を分かりやすく示すための画像を新たに生成するプログラムを作ってみました。
ちなみに、ディレクトリ名を日本語にしたかったので、日本語のパスにも対応するように作ってます。

ソースコードはこちら↓ の「2_差分画像の生成」のプログラムです。

https://github.com/jun-higuche/python-ImageCompare

## 背景

この記事の前に書いた記事とほぼ同じ背景です。
↓

https://qiita.com/jun_higuche/items/752ef756a182261fcc55#%E8%83%8C%E6%99%AF

付け足すと、差分を分かりやすく示す画像を生成しておいた方がより確認がし易いと思い、作ってみることにしました。

## 01_画像比較して異なる箇所を赤枠で囲んだ画像を生成するプログラム

こちらでは、２つの画像を比較させて、その差異の箇所に赤枠を付けた画像を生成するというプログラムになります。

```python:main2_01.py
"""
画像比較して異なる箇所を赤枠で囲む
"""

import cv2
import os
from opencv_japanese import imread, imwrite
import numpy as np

dirname =  os.path.dirname(__file__)

#画像読み込み
img_1 = imread(dirname + '\\1_1.png')
img_2 = imread(dirname + '\\1_2.png')

height = img_2.shape[0]
width = img_2.shape[1]

img_1 = cv2.resize(img_1 , (int(width), int(height)))

img_1_gray = cv2.cvtColor(img_1, cv2.COLOR_BGR2GRAY)
img_2_gray = cv2.cvtColor(img_2, cv2.COLOR_BGR2GRAY)

#画像を引き算
img_diff = cv2.absdiff(img_1_gray, img_2_gray)

#2値化
ret2,img_th = cv2.threshold(img_diff,20,255,cv2.THRESH_BINARY)

#輪郭を検出
contours, hierarchy = cv2.findContours(img_th, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

#閾値以上の差分を四角で囲う
for i,cnt in enumerate(contours):
    x, y, width, height = cv2.boundingRect(cnt)
    if width > 20 or height > 20:
        cv2.rectangle(img_1, (x, y), (x+width, y+height), (0, 0, 255), 1)

#画像を生成
imwrite(dirname + "/output/diff_image.jpg", img_1)
```


## 02_画像比較して異なる箇所が分かる画像を生成するプログラム

そして、こちらは、２つの画像を比較させてその差異のある箇所（ピクセル的な）を色を変えて示すというプログラムになります。

```python:main2_02.py
"""
画像比較して異なる箇所を別画像で表示
↓を参考に
https://note.nkmk.me/python-opencv-numpy-image-difference/
"""

import cv2, os
import numpy as np
from opencv_japanese import imread, imwrite

dirname =  os.path.dirname(__file__)

img_1 = imread(dirname + '\\1_1.png')
img_2 = imread(dirname + '\\1_2.png')

height = img_1.shape[0]
width = img_1.shape[1]

img_size = (int(width), int(height))

# 画像をリサイズする
image1 = cv2.resize(img_1, img_size)
image2 = cv2.resize(img_2, img_size)

# ２画像の差異を計算
im_diff = image1.astype(int) - image2.astype(int)

# 単純に差異をそのまま出力する
imwrite(dirname + '/output/01_diff.png', im_diff)

# 差異が無い箇所を中心（灰色：128）とし、そこからの差異を示す
imwrite(dirname + '/output/02_diff_center.png', im_diff + 128)

# 差異が無い箇所を中心（灰色：128）とし、差異を2で割った商にする（差異を-128～128にしておきたいため）
im_diff_center = np.floor_divide(im_diff, 2) + 128
imwrite(dirname + '/output/03_diff_center.png', im_diff_center)
```

## それぞれのやり方で差異を示す画像を生成してその特徴を比較してみた。

Android端末で、適当なスクリーンショットを撮ってサンプル画像として使ってみました。

### サンプルの画像：

| 1_1.jpg | 1_2.jpg | 
|:-----------|:------------|
| ![1_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448092/a360ed40-dba8-e2b4-07c2-6622b07d4b64.jpeg)| ![1_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448092/6fbf643d-edbd-d136-4df4-ecc6ebbf2c94.jpeg)|

### 比較結果

#### 01_画像比較して異なる箇所を赤枠で囲んだ画像を生成するプログラム

ちょっとわかりづらいかもですが、↓の画像上方に差異の箇所を赤枠で示すことができました。

|diff_image.jpg|
|:-----------|
|![diff_image.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448092/e5c50f09-bb27-da20-8f35-c53c7cd392f8.jpeg)|

このサンプルの場合は、差異の箇所が文字の部分だけですので、これでも十分わかりますよね。


#### 02_画像比較して異なる箇所が分かる画像を生成するプログラム

|01_diff.jpg|02_diff_center.jpg|03_diff_center.jpg|
|:-----------|:------------|:------------|
|![01_diff.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448092/92bc9ba3-3f49-6a00-b883-aa7676cf68a4.jpeg)|![02_diff_center.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448092/fb60372b-cb48-6bd3-a68b-6e21008caa3d.jpeg)|![03_diff_center.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448092/85e4e4dc-ba52-ea33-a5e3-741e79a79abd.jpeg)|

ちょっと解説ですが、
「01_diff.jpg」は、ただただ差異を描画しようとしてみたのですが、どうもマイナス値については、全て0（黒）になってしまうようで、差異があるかどうかが分かりませんでした。
なので、「02_diff_center.jpg」のように、中間値を「128（灰色）」として、そこからの差異として示してみました。ただ、ここでも、差異が-256～256となるために、差異がマイナス値となってしまい。黒潰れてしまうことがあります。
なので、次に、「03_diff_center.jpg」のように差異の最小値を-128とするために、２で割った商を予め計算してみました。
これで、割と差異が見易い画像になったかと思います。

### まとめ

今回、差異を示すために、赤枠を付けた画像の生成と、差異のある箇所を色付けして示すという事をやってみました。
差異の箇所が限定的な場合には「赤枠を付けた画像」で良さそうですが、多くの場所に差異が出てくる場合には２つ目の「差異のある箇所を色付けした画像」の方が良さそうです。

今回は以上です。
次は、前回ご紹介した類似度の算出と、今回の差異画像の生成の２つを利用して、新と旧の両方で動かしたアプリのキャプチャ画像を比較させて、まとめてExcelファイルに貼り付け、結合テストの結果エビデンスとしてしまうプログラムを紹介したいと思います。