2020/07/04

カメラで撮影した紙の画像の濃淡除去

目的


皺があったり光を一様に当てられない環境で紙をカメラで撮影すると、明るい部分と暗い部分ができてしまいます。
画像を二値化したいとき、このような明るさの変化が二値化の障害になることがあります。 そこで、これを緩和する方法を試してみます。 全体的な明度差のある画像に対応できていないOCRを使うときの前処理のひとつとして使えるかもしれません。

手法


日本の特許(登録番号3909604)を使ってみます。

畳み込み演算でぼかした画像のピクセルで元のピクセルの値を割った値を元に画像を再構成することで、細かい構造を残しながら全体的な濃淡を除去します。

詳細は https://www.inpit.go.jp/blob/katsuyo/pdf/business/19t1-2.pdf または、特許公報を参照してください。

ソースコード


gray.pngを読み込んで処理したあと、mod.pngに書き込みます。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import numpy as np
import cv2

def flatten(img, kernel_size=77):
    # Make a kernel
    half = kernel_size//2
    k = np.array(list(range(1,half+1))+[half+1]+list(range(half, 0, -1)))
    ks = [k]
    for i in range(2, half+2, 1):
        ks.append(k*i)
    for i in range(half, 0, -1):
        ks.append(k*i)
    k = np.stack(ks)
    k = np.array(k, dtype=np.float32)/np.sum(k)

    # Calculate uneven coefficients (JPP3909604)
    ave = cv2.filter2D(img, -1, k).astype(np.float32)
    a = img.astype(np.float32)/ave

    # Make a flatten image
    a = (a-1)*768+255
    a[a>255] = 255
    a[a<0] = 0
    return a.astype(np.uint8)

if __name__ == '__main__':
    img = cv2.imread('gray.png')
    img = flatten(img)
    cv2.imwrite('mod.png', img)


処理例を以下に示します。

処理前の画像

処理後の画像
文字周りの明度はある程度一定になっていることがわかります。