(2017/05/24追記)
githubにコードを登録しました。本ページに記載したものそのままですが。
https://github.com/summer4an/mosaic_detector
前提
https://twitter.com/stsiizk/status/858517661889646592
あれ?これってもしかして…
というわけで来るべき日に備えて(?)準備をすることにしました。
モザイクの種類は複数ありますが、今回は単一の色で塗られた箱が多数並んだものを対象にします。
ググってみましたがモザイク加工する話題ばかりで、モザイク部分を検出する方法については特に見つけられなかったため自力で。
ゴールは画像のモザイク部分を検出し、白塗りすることです。
python3.5.2とOpenCV3.2.0を利用しました。
方針
画像加工ソフトやpythonでコードを組んで試行錯誤したところ、以下の手順で満足のいく結果が得られました。
1. グレースケールに変換
2. Cannyでエッジ検出
3. 白黒反転
4. 少しぼかす
5. 各種サイズの格子画像でそれぞれパターンマッチング
6. マッチした箇所を塗りつぶす
4で少しぼかすのは、3の結果で箱の境目の線が1ピクセル幅の直線にはなってくれず、2ピクセルの幅の間を行ったり来たりしたものになったため、パターンマッチングしづらかったためです。
5で各種サイズの格子画像を使うのは、パターンマッチングが拡大縮小に弱いためです。一般的と思われる11ピクセルから20ピクセル四方の格子画像を使いました。
コード
まず以下で各サイズのパターンマッチング用の格子画像を作ります。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#モザイクのサイズが11から20までだった場合のためのパターン画像ファイルを生成。
#以下参考資料。
# http://qiita.com/suto3/items/5181b4a3b9ebc206f579
from PIL import Image
def make_image(masksize, filename):
picturesize = 2+masksize+masksize-1+2
screen = (picturesize, picturesize)
img = Image.new('RGB', screen, (0xff,0xff,0xff))
pix = img.load()
for i in range(2,picturesize,masksize-1):
for j in range(2,picturesize,masksize-1):
for k in range(0,picturesize):
pix[i, k] = (0,0,0)
pix[k, j] = (0,0,0)
img.save(filename)
return
for i in range(11, 20+1):
make_image(i, "pattern"+str(i)+"x"+str(i)+".png")
この格子画像を使って以下で検出をします。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#モザイクの箇所を検出し、白塗りする。
#以下参考資料。
# ・Template Matching
# http://docs.opencv.org/3.2.0/d4/dc6/tutorial_py_template_matching.html
# http://opencv.jp/cookbook/opencv_img.html#id32
import cv2
import numpy as np
import sys
args = sys.argv
if len(args) != 2:
print("too few argument.")
sys.exit(1)
img_rgb = cv2.imread(args[1])
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY) #グレースケールに
img_gray = cv2.Canny(img_gray,10,20) #エッジ検出
img_gray = 255-img_gray #白黒反転
img_gray = cv2.GaussianBlur(img_gray,(3,3),0) #少しぼかす
cv2.imwrite('output_gray.png', img_gray)
for i in range(11,20+1):
pattern_filename = "pattern"+str(i)+"x"+str(i)+".png"
template = cv2.imread(pattern_filename, 0)
w, h = template.shape[::-1]
img_kensyutu_kekka = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
threshold = 0.3
loc = np.where(img_kensyutu_kekka >= threshold)
for pt in zip(*loc[::-1]):
#cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (255,255,255), 1)
cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (255,255,255), -1)
cv2.imwrite('output_progress_'+str(i)+'.png', img_rgb)
cv2.imwrite('output_result.png', img_rgb)
cv2.imshow('window1', img_rgb)
cv2.imshow('window2', img_gray)
cv2.waitKey(0)
cv2.destroyAllWindows()
結果
以下のいろいろなサイズでモザイクを掛けた画像を処理します。
画像は http://gahag.net/011032-cat-sunflower-smell/ から。
モザイクを掛けた箇所はもれなく塗りつぶすことができました。
余計な箇所も塗りつぶされていますが、どうせ補完されるのでOKでしょう。
他の画像でも結果は同様でしたので満足です。