台形検出+射影変換
レジュメなんかをデータ化する際,印刷機でスキャンできればいいのですが,忙しいとスマホのカメラで済ませることもあるかと思います.そうするとレジュメが曲がっていたり,机の余計な部分が移ってしまいます.
下記のプログラムでは,射影変換を行うことにより,スキャン風のいい感じな画像に補正してくれます.
import sys
import cv2
import numpy as np
def image2scan(src):
# extract white
hsv = cv2.cvtColor(src, cv2.COLOR_BGR2HSV)
lower_white = np.array([0,0,100])
upper_white = np.array([180,45,255])
mask_white = cv2.inRange(hsv, lower_white, upper_white)
res_white = cv2.bitwise_and(src, src, mask= mask_white)
# detect trapezoid
gray = cv2.cvtColor(res_white, cv2.COLOR_BGR2GRAY)
tmp= cv2.findContours(gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = tmp[0] if len(tmp) == 2 else tmp[1]
areas = [cv2.contourArea(cnt) for cnt in contours]
max_area = contours[np.argmax(areas)]
epsilon = 0.1 * cv2.arcLength(max_area, True)
approx = cv2.approxPolyDP(max_area, epsilon, True)
# projection transform
length = np.max(approx, axis=0)[0]
cor = np.float32([[0, 0], [length[0], 0], [0, length[1]], length])
approx_sum = [a[0][0]+a[0][1] for a in approx]
sorted_sum = list(np.sort(approx_sum))
sorted_idx = [approx_sum.index(i) for i in sorted_sum]
pts = np.float32(np.array([
approx[sorted_idx[0]][0], approx[sorted_idx[1]][0],
approx[sorted_idx[2]][0], approx[sorted_idx[3]][0]]))
if pts[1][0] < pts[2][0]:
pts = pts[[0, 2, 1, 3]]
M = cv2.getPerspectiveTransform(pts, cor)
dst = cv2.warpPerspective(src, M, (length[0], length[1]))
return dst
def main():
path = sys.argv[1]
camera_image = cv2.imread(path)
scan_like_image = image2scan(camera_image)
try:
write_path = sys.argv[2]
except IndexError:
write_path = "dst_" + path
cv2.imwrite(write_path, scan_like_image)
if __name__ == '__main__':
main()