2013년 7월 29일 월요일

[Python] openCV를 이용해 스도쿠 그림 인식 및 계산 예제




다음과 같은 스도쿠 이미지를


위와 같이 refactor 한 후,


점점 contour 를 조정해 가면서 숫자를 알아낸다


혹은 아래처럼 스도쿠판의 네 꼭지점을 먼저 찾아서 스도쿠 범위를 정하는 방법도 있다




그림 인식에는 openCV 가 사용된다.

코드를 한달 전 정도에 짜서 내용도 잘 기억 안나고, 코멘트도 영어로 단 상태인데,

조만간 수정할 계획이다 :)

# author = 'carpedm20'
import cv2
from cv import *
from cv2 import *
import numpy as np

img =  cv2.imread('sudoku.jpg')

# can remove lots of noises by blur effect
gray = cv2.GaussianBlur(gray,(5,5),0)
#cv2.imwrite('gaussian.jpg',gray)

# change color from RGB image to Gray image
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

mask = np.zeros((gray.shape),np.uint8)
kernel1 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(11,11))

close = cv2.morphologyEx(gray,cv2.MORPH_CLOSE,kernel1)
div = np.float32(gray)/(close)
res = np.uint8(cv2.normalize(div,div,0,255,cv2.NORM_MINMAX))
res2 = cv2.cvtColor(res,cv2.COLOR_GRAY2BGR)

# adaptive threshold : taking a best value for a local neighbourhood
# threshold : find treshold taking image as a whole
thresh = cv2.adaptiveThreshold(gray,255,1,1,11,2)
cv2.imwrite('img_thresh.jpg',thresh)

white = Closing[src, DiskMatrix[5]];
srcAdjusted = Image[ImageData[src]/ImageData[white]]

# # of contour by mode
# CV_RETR_EXTERNAL < CV_RETR_LIST < CV_RETR_CCOMP < CV_RETR_TREE
#contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

biggest = None
#biggest = []
max_area = 0
for i in contours:
 # calculate area of contour
        area = cv2.contourArea(i)
        if area > 100:
  # calculates a contour perimeter or a curve lengt
  # closed : True - Flag indicating whether the curve is closed or not
                peri = cv2.arcLength(i,True)
                #peri = cv2.arcLength(i,False)
  # Approximates a polygonal curves with the specified precision.
                approx = cv2.approxPolyDP(i,0.02*peri,True)
                #approx = cv2.approxPolyDP(i,0.02*peri,False)

                if area > max_area and len(approx)==4:
                #if len(approx)>=4:
                        biggest = approx
                        #biggest.append(approx)
                        max_area = area

# -1 : indicating a contour to draw, negative means all contours
# (0,255,0) : RGB
# 3 : width of countour, negative means fill the countours
cv2.drawContours(img, biggest, -1, (0,255,0), 2)

cv2.imwrite('contour.jpg',img)

def rectify(h):
        h = h.reshape((4,2))
        hnew = np.zeros((4,2),dtype = np.float32)

        add = h.sum(1)
        hnew[0] = h[np.argmin(add)]
        hnew[2] = h[np.argmax(add)]

        diff = np.diff(h,axis = 1)
        hnew[1] = h[np.argmin(diff)]
        hnew[3] = h[np.argmax(diff)]

        return hnew

approx=rectify(biggest)
h = np.array([ [0,0],[449,0],[449,449],[0,449] ],np.float32)

retval = cv2.getPerspectiveTransform(approx,h)
warp = cv2.warpPerspective(gray,retval,(450,450))

cv2.imwrite('warp.jpg',warp)

reference : http://opencvpython.blogspot.in/2012/06/sudoku-solver-part-1.html

댓글 1개:

  1. 안녕하십니까 전기공학부 학생입니다. 다름이 아니라 open cv 과제를 하고있습니다.
    실례가 안된다면 혹시 소스를 부탁해도 괜찮으십니까?부탁드리겠습니다.

    답글삭제