はじめに
画像内の個人情報を黒消ししてみます(Pythonで実装)。
画像内の人名や地名を見つけ、黒塗りするシンプルなものです。
※ 画像内個人情報を黒消ししてみた(電話番号編)はこちら
黒消し結果から
処理前の画像 | 処理後の画像 |
---|---|
使用したツール
- Tesseract
- さまざまなオペレーティングシステム上で動作する光学式文字認識(OCR)エンジン
- Apache License下でリリースされたフリーソフトウェア
- OpenCV
- 画像処理・画像解析および機械学習等の機能を持つライブラリ
- C/C++、Java、Python、MATLABで使用可能
- POSIX準拠のUnix系OS、Linux、Windows、Android、iOS等をサポート
- GiNZA
- オープンソースの日本語自然言語処理ライブラリ
- 高速かつ高精度な日本語の解析処理/依存構造(係り受け)解析/固有表現抽出
- 高度なNLP技術を国際化されたフレームワーク上で利用可能
- spaCy
- 高度な自然言語処理を行うため、PythonとCythonで書かれたOSSライブラリ
- 多言語解析処理と固有表現抽出のため、統計的ニューラルネットワークモデルや字句解析モデルを提供
開発環境
- 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) -
インストール時に、以下日本語オプションにチェックを入れる
- Additional script data (download)
- Japanese script
- Japanese vertical script
- Additional language data (download)
- Japanese
- Japanese (vertical)
- Additional script data (download)
Tesseract OCRのPythonラッパーpytesseract
をインストール
pip3 install pytesseract
OpenCVのPythonラッパーopencv-python
をインストール
pip3 install opencv-python
GiNZAの日本語モデルja_ginza
をインストール
pip3 install ja-ginza
サンプルコード
- 実行方法
python redact.py
- 実行結果
- 入力画像: カレントディレクトリのinput.png
- 標準出力: 抽出されたテキストと固有名詞の判定結果
- 出力画像: カレントディレクトリにoutput.pngが生成される
- ※ tesseract実行ファイルパスを通す必要あり
redact.py
import pytesseract as pt
import cv2
import re
import spacy
# tessdataディレクトリを指定
tessdata_dir_config = '--tessdata-dir "C:/Program Files/Tesseract-OCR/tessdata"'
# tesseract実行ファイルを指定
pt.pytesseract.tesseract_cmd = 'C:/Program Files/Tesseract-OCR/tesseract.exe'
# spaCyからGiNZAのja_ginzaモデルをロード
nlp = spacy.load('ja_ginza')
# 固有名詞の判定
def is_named_entity(text: str):
# テキストをDocクラスに変換
doc = nlp(text)
# DocクラスはTokenクラスのイテレーター
for token in doc:
# 品詞タグから固有名詞の単語を抽出
if token.pos_ in ['PROPN']:
# token.textは日本語形態素の単位
print(token.text, token.tag_, type(token))
return True
return False
# 黒消し処理
def redact(img: cv2.Mat, details: dict, idx: int):
# 黒消し範囲
(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
# 黒消し実施
return cv2.rectangle(img, start, end, color, thickness)
def redact_image(infile: str, keys: list = None):
# 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])
if is_named_entity(details['text'][idx]):
# 固有名詞を黒消し
matches += 1
img = redact(img, details, idx)
elif keys:
# 黒消しキーワードで検索
for key in keys:
results = re.findall(key, details['text'][idx], re.IGNORECASE)
for result in results:
matches += 1
img = redact(img, details, idx)
if matches > 0:
redacted_img = img.copy()
# 画像を保存
cv2.imwrite("output.png", redacted_img)
if __name__ == '__main__':
# 画像内の固有名詞を黒消し
redact_image(infile='input.png')
- 実行結果
>python redact.py
T
123-4567
東京
東京 名詞-固有名詞-地名-一般 <class 'spacy.tokens.token.Token'>
都
東京
東京 名詞-固有名詞-地名-一般 <class 'spacy.tokens.token.Token'>
市
東京
東京 名詞-固有名詞-地名-一般 <class 'spacy.tokens.token.Token'>
町
1-2-3
桃太郎
桃太郎 名詞-固有名詞-人名-名 <class 'spacy.tokens.token.Token'>
様
電話
番号
000-1111-2222
>dir output.png
おわりに
画像内の名前など固有名詞を、黒消ししてみました。
いろいろ改善は必要ですが、ひとまず。