画像内個人情報を黒消ししてみた(電話番号編)

## はじめに

画像内の個人情報を黒消ししてみます(Pythonで実装)。
画像内の電話番号と郵便番号を見つけ、黒塗りするシンプルなものです。

※ 画像内個人情報を黒消ししてみた(名前編)は[こちら](https://qiita.com/mingchun_zhao/items/1510da4a01d049c927dd)

## 黒消し結果から

|処理前の画像|処理後の画像|
|:--:|:--:|
|![input.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/914bfe6f-26ea-b0aa-85c5-ec4387f98f6d.png)|![output.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/6d2b18b8-7b97-8e9f-f1f2-6a6afb214628.png)|

## 使用したツール

- Tesseract
    - さまざまなオペレーティングシステム上で動作する光学式文字認識(OCR)エンジン
    - Apache License下でリリースされたフリーソフトウェア
- OpenCV
    - 画像処理・画像解析および機械学習等の機能を持つライブラリ
    - C/C++、Java、Python、MATLABで使用可能
    - POSIX準拠のUnix系OS、Linux、Windows、Android、iOS等をサポート

## 開発環境

- CPU: Intel(R) Core(TM) 3.30GHz(4コア8スレッド)
- メモリ: 16 GB
- OS: Windows 10
- Python 3.10

## 事前準備

### Tesserractをインストール

- Tesseract OCR 64bit版をダウンロード
[tesseract-ocr-w64-setup-v5.1.0.20220510.exe(64 bit)](https://digi.bib.uni-mannheim.de/tesseract/tesseract-ocr-w64-setup-v5.1.0.20220510.exe)

- インストール時に、以下日本語オプションにチェックを入れる
    - Additional script data (download)
        - Japanese script
        - Japanese vertical script
    - Additional language data (download)
        - Japanese
        - Japanese (vertical)

### Tesseract OCRのPythonラッパー`pytesseract`をインストール

```
pip3 install pytesseract
```

### OpenCVのPythonラッパー`opencv-python`をインストール

```
pip3 install opencv-python
```

## サンプルコード

- 実行方法
    - `python redact.py`
- 実行結果
    - 入力画像: カレントディレクトリのinput.png
    - 標準出力: 抽出されたテキスト
    - 出力画像: カレントディレクトリにoutput.pngが生成される
- ※ tesseract実行ファイルパスを通す必要あり

```python:redact.py
import pytesseract as pt
import cv2
import re

# tessdataディレクトリを指定
tessdata_dir_config = '--tessdata-dir "C:/Program Files/Tesseract-OCR/tessdata"'
# tesseract実行ファイルを指定
pt.pytesseract.tesseract_cmd = 'C:/Program Files/Tesseract-OCR/tesseract.exe'

def redact_image(infile: str, keys: list):
    # opencvで画像を読み込む
    img = cv2.imread(infile)
    # 画像をバイナリに変換
    bin_img = cv2.bitwise_not(img)
    # 画像からテキスト抽出(日本語と英語を指定、psm=6: 単一テキストブロックとみなす)
    details = pt.image_to_data(bin_img, output_type=pt.Output.DICT,
                               lang='jpn+eng', config=r'--psm 6')
    # マッチした回数
    matches = 0
    for idx in range(len(details['text'])):
        # 抽出テキストの信頼度スコアが30%以上のみ使用
        if float(details['conf'][idx]) > 30.0:
            # 黒消しキーワードで検索
            print(details['text'][idx])
            for key in keys:
                results = re.findall(key, details['text'][idx], re.IGNORECASE)
                for result in results:
                    matches += 1
                    # 黒消し範囲
                    (x, y, w, h) = (details['left'][idx], details['top'][idx],
                                    details['width'][idx], details['height'][idx])
                    start = (x, y)
                    end = (x + w, y + h)
                    color = (0, 0, 0)
                    thickness = -1
                    # 黒消し実施
                    img = cv2.rectangle(img, start, end, color, thickness)
    if matches > 0:
        redacted_img = img.copy()
        # 画像を保存
        cv2.imwrite("output.png", redacted_img)  

if __name__ == '__main__':
    # 電話番号の正規表現
    tel = r'([0-9０-９]{2,4})(-|ー)([0-9０-９]{2,4})(-|ー)([0-9０-９]{3,4})'
    # 郵便番号の正規表現
    zipcode = r'([0-9０-９]{3})(-|ー)([0-9０-９]{4})'
    # 画像内の電話番号と郵便番号を黒消し
    redact_image(infile='input.png', keys=[tel, zipcode])
```

- 実行結果
```
>python redact.py
T
123-4567
東京
都
東京
市
東京
町
1-2-3
桃太郎
様
電話
番号
000-1111-2222
```
```
>dir output.png
```
## おわりに

ゆくゆくは、住所や名前など個人情報を自動認識し、
黒消しできたらいいなー、と思ったりしています。