opencv で カードの向きを直してみる
チュートリアルを通じて学んだことを活かして、机の上においたカードを普通に(真上ではない角度から)撮影した画像を、まっすぐに修正してみる。
なお、カードが真っ白だったので、向きが分かるように、適当に文字を上に乗せました。(カードにペンでかけばよかったかな・・・)
試行錯誤の結果ですが、処理の流れは、、、
白を検出(HSVに変換します)
二値化
境界を検出する
境界を近傍する
4つ角の座標を得る
射影変換する
#!/usr/bin/env python # -*- coding: utf-8 -* import sys import cv2 import numpy as np from pprint import pprint def main(): image = cv2.imread('DSC_2848.2.jpg') #cv2.imshow('original', image) # リサイズ height, width ,depth = image.shape image = cv2.resize(image, (width/4, height/4)) imageOrg = image cv2.imshow('resize', image) cv2.imwrite('50.resize.png', image) # HSVへ変換 image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 白抽出:凄く明るい場所 threashhold_min = np.array([0,0,180], np.uint8) threashhold_max = np.array([255,255,255], np.uint8) image = cv2.inRange(image, threashhold_min, threashhold_max) # BGRへ変換 # inRange で グレースケールされている image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB) cv2.imshow('inRange', image) cv2.imwrite('50.inRange.png', image) # ノイズ除去 kernel = np.ones((9,9), np.uint8) image = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel) image = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel) cv2.imshow('removeNoise', image) cv2.imwrite('50.removeNoise.png', image) # 反転処理 image = 255 - image # 境界抽出 gray_min = np.array([0], np.uint8) gray_max = np.array([128], np.uint8) threshold_gray = cv2.inRange(image, gray_min, gray_max) image, contours, hierarchy = cv2.findContours(threshold_gray,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) # 最大面積を探す max_area_contour=-1 max_area = 0 for contour in contours: area=cv2.contourArea(contour) if(max_area<area): max_area=area max_area_contour = contour #print(max_area_contour) # カラー化 #image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGBA) contours = [max_area_contour] cv2.drawContours(imageOrg, max_area_contour, -1, (0, 255, 0), 5) # 輪郭の近似 epsilon = 0.01 * cv2.arcLength(max_area_contour,True) approx = cv2.approxPolyDP(max_area_contour,epsilon,True) #print(approx) if len(approx) == 4: cv2.drawContours(imageOrg, [approx], -1, (255, 0, 0), 3) cv2.imshow('findContours', imageOrg) cv2.imwrite('50.findContours.png', imageOrg) # ソートが必要かな? #pprint(approx) #approx= np.sort(approx,axis=1) #approx= np.sort(approx,axis=0) #pprint(approx) height, width ,depth = imageOrg.shape # 射影変換 pts1 = np.float32(approx) pts2 = np.float32([[600,200],[300,200],[300,350],[600,350]]) pprint(pts1) pprint(pts2) M = cv2.getPerspectiveTransform(pts1,pts2) imageOrg = cv2.warpPerspective(imageOrg,M,(width,height)) cv2.imshow('getPerspectiveTransform', imageOrg) cv2.imwrite('50.getPerspectiveTransform.png', imageOrg) cv2.waitKey(0) cv2.destroyAllWindows() return 0 if __name__ == '__main__': try: main() except KeyboardInterrupt: pass
リサイズ
白を検出して二値化
ノイズ除去
境界検出
射影変換
cv2.approxPolyDP
で帰ってくる配列ですが、3番目の引数に True を指定したので、閉じたポリゴンを返してくれるはず。
closed – これが真の場合,近似された曲線は閉じたものになり(つまり,最初と最後の頂点が接続されます),そうでない場合は,開いた曲線になります.
ですが、並び順が固定なのか、変動するのか不明。
このプログラムでは、右上 > 左上 > 左下 > 右下 の順(右上スタートの反時計回り)でしたが、毎回そうなのか、どうなのか・・・。