├── analyze.py ├── bambu2.jpg ├── bambu3.jpg ├── bambu_tile5.jpg ├── contour_0.jpg ├── contour_1.jpg ├── contour_2.jpg ├── contour_3.jpg ├── contour_4.jpg ├── contour_5.jpg ├── contour_6.jpg ├── contour_7.jpg ├── contour_8.jpg ├── man2.png ├── test.jpg ├── threshold.jpg ├── warp_0.jpg ├── warp_1.jpg ├── warp_2.jpg ├── warp_3.jpg ├── warp_4.jpg ├── warp_5.jpg ├── warp_6.jpg ├── warp_7.jpg └── warp_8.jpg /analyze.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | from itertools import izip 4 | 5 | def rectify(contour): 6 | contour = contour.reshape((4, 2)) 7 | newContour = np.zeros((4, 2), dtype=np.float32) 8 | add = contour.sum(1) 9 | newContour[0] = contour[np.argmin(add)] 10 | newContour[2] = contour[np.argmax(add)] 11 | 12 | diff = np.diff(contour, axis=1) 13 | newContour[1] = contour[np.argmin(diff)] 14 | newContour[3] = contour[np.argmax(diff)] 15 | return newContour 16 | 17 | def preprocess(image): 18 | gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) 19 | blurred = cv2.GaussianBlur(gray, (5, 5), 0) 20 | threshold = cv2.adaptiveThreshold(blurred, 255, 1, 1, 11, 2) 21 | #blurredTreshold = cv2.GaussianBlur(threshold, (5, 5), 5) 22 | return threshold 23 | 24 | def imgdiff(img1,img2): 25 | img1 = cv2.GaussianBlur(img1,(5,5),5) 26 | img2 = cv2.GaussianBlur(img1,(5,5),5) 27 | diff = cv2.absdiff(img1,img2) 28 | diff = cv2.GaussianBlur(diff,(5,5),5) 29 | flag, diff = cv2.threshold(diff, 200, 255, cv2.THRESH_BINARY) 30 | result = np.sum(diff) 31 | return result 32 | 33 | def find_closest_card(training,img): 34 | features = preprocess(img) 35 | return sorted(training.values(), key=lambda x:imgdiff(x[1], features))[0][0] 36 | 37 | im = cv2.imread('bambu3.jpg') 38 | thresh = preprocess(im) 39 | cv2.imwrite('threshold.jpg', thresh) 40 | contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) 41 | tiles = [] 42 | for c in contours: 43 | perimeter = cv2.arcLength(c, True) 44 | approx = cv2.approxPolyDP(c, 0.02*perimeter, True) 45 | area = cv2.contourArea(approx) 46 | if area > 800 and area < 10000 and len(approx) == 4: 47 | tiles.append(approx); 48 | 49 | tiles.sort(key=lambda x: x[0][0][0]) 50 | index = 0 51 | for tile in tiles: 52 | temp = im.copy() 53 | cv2.drawContours(temp, [tile], 0, (0, 255, 0), 3) 54 | cv2.imwrite("contour_%s.jpg" % index, temp) 55 | index += 1 56 | 57 | index = 0 58 | for tile in tiles: 59 | rectangle = cv2.minAreaRect(tile) 60 | r = cv2.cv.BoxPoints(rectangle) 61 | h = np.array([[0,0], [449, 0], [449,449], [0,449]], np.float32) 62 | transform = cv2.getPerspectiveTransform(rectify(tile), h) 63 | warp = cv2.warpPerspective(im, transform, (450, 450)) 64 | cv2.imwrite('warp_%s.jpg'% index, warp) 65 | index += 1 66 | 67 | trained = dict([i+1, tiles[i]] for i in range(0, len(tiles))) 68 | 69 | unknown = cv2.imread('bambu_tile5.jpg') 70 | print find_closest_card(trained, unknown) 71 | 72 | -------------------------------------------------------------------------------- /bambu2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/bambu2.jpg -------------------------------------------------------------------------------- /bambu3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/bambu3.jpg -------------------------------------------------------------------------------- /bambu_tile5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/bambu_tile5.jpg -------------------------------------------------------------------------------- /contour_0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/contour_0.jpg -------------------------------------------------------------------------------- /contour_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/contour_1.jpg -------------------------------------------------------------------------------- /contour_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/contour_2.jpg -------------------------------------------------------------------------------- /contour_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/contour_3.jpg -------------------------------------------------------------------------------- /contour_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/contour_4.jpg -------------------------------------------------------------------------------- /contour_5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/contour_5.jpg -------------------------------------------------------------------------------- /contour_6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/contour_6.jpg -------------------------------------------------------------------------------- /contour_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/contour_7.jpg -------------------------------------------------------------------------------- /contour_8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/contour_8.jpg -------------------------------------------------------------------------------- /man2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/man2.png -------------------------------------------------------------------------------- /test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/test.jpg -------------------------------------------------------------------------------- /threshold.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/threshold.jpg -------------------------------------------------------------------------------- /warp_0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/warp_0.jpg -------------------------------------------------------------------------------- /warp_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/warp_1.jpg -------------------------------------------------------------------------------- /warp_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/warp_2.jpg -------------------------------------------------------------------------------- /warp_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/warp_3.jpg -------------------------------------------------------------------------------- /warp_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/warp_4.jpg -------------------------------------------------------------------------------- /warp_5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/warp_5.jpg -------------------------------------------------------------------------------- /warp_6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/warp_6.jpg -------------------------------------------------------------------------------- /warp_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/warp_7.jpg -------------------------------------------------------------------------------- /warp_8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbaruzza/mahjong-opencv/2f7c19867a38cb141be0196ee1d5d1061172b0d0/warp_8.jpg --------------------------------------------------------------------------------