Created
October 3, 2016 22:25
-
-
Save bhive01/e92304ec0cde3a8b84a54cc73f3d4432 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import argparse | |
| import trans #pip install trans | |
| import time | |
| import cv2 | |
| import math | |
| import pandas as pd | |
| import numpy as np | |
| import zbar # sudo apt-get install libzbar-dev \ pip install zbar | |
| from sklearn.neighbors import NearestNeighbors | |
| from scipy.spatial.distance import squareform, pdist | |
| from itertools import permutations | |
| from play2_funcs import * | |
| #cv2.namedWindow("Original", cv2.WINDOW_NORMAL) | |
| #cv2.namedWindow("CannyEdges", cv2.WINDOW_NORMAL) | |
| #cv2.namedWindow("mask", cv2.WINDOW_NORMAL) | |
| #cv2.resizeWindow('Original', 600,600) | |
| #cv2.resizeWindow('CannyEdges', 600,600) | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("-i", "--image", required = True, | |
| help = "Path to the image") | |
| args = vars(ap.parse_args()) | |
| img = cv2.imread(args["image"]) | |
| height, width, channels = img.shape | |
| totalpx = float(height*width) | |
| # constants | |
| minarea = 1000./12000000. * totalpx # 1000px^2/12MP smallest size acceptable square | |
| maxarea = 150000./12000000. * totalpx #150kpx^2/12MP largest size acceptable square | |
| # create gray image for histogram expansion | |
| gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) | |
| # create a CLAHE object (Arguments are optional). | |
| clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) | |
| # apply CLAHE histogram expansion to find squares better with canny edge detection | |
| cl1 = clahe.apply(gray_img) | |
| cv2.imwrite("clahe.png", cl1) | |
| # blur slightly so defects on card squares are less likely to be picked up | |
| # also reduces background noise | |
| bilateralBlur = cv2.bilateralFilter(cl1, 15, 50, 100, 25) | |
| cv2.imwrite("bilateralBlur.png", bilateralBlur) | |
| # Canny edge detector to find squares | |
| edges = cv2.Canny(bilateralBlur, 100, 200) | |
| cv2.imwrite("edges.png", edges) | |
| # compute contours to find the squares of the card | |
| _, contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) | |
| mindex = [] # variable of which contour is which | |
| mu = [] # variable to store moments | |
| mc = [] # variable to x,y coordinates in tuples | |
| mx = [] # variable to x coordinate as integer | |
| my = [] # variable to y coordinate as integer | |
| marea = [] # variable to store area | |
| msquare = [] # variable to store whether something is a square (1) or not (0) | |
| mchild = [] # variable to store child hierarchy element | |
| mheight = [] # fitted rectangle height | |
| mwidth = [] # fitted rectangle width | |
| mwhratio = [] # ratio of height/width | |
| mcolorR = [] # variable to store R | |
| mcolorG = [] # variable to store G | |
| mcolorB = [] # variable to store B | |
| mark = 0 # for counting the 3 marks in corners of QR Code | |
| # extract moments from contour image | |
| for x in range(0, len(contours)): | |
| mu.append(cv2.moments(contours[x])) | |
| marea.append(cv2.contourArea(contours[x])) | |
| mchild.append(int(hierarchy[0][x][2])) | |
| mindex.append(x) | |
| # cycle through moment data and compute location for each moment | |
| for m in mu: | |
| if m['m00'] != 0: # this is the area term for a moment | |
| mc.append((int(m['m10']/m['m00']), int(m['m01']/m['m00']))) | |
| mx.append(int(m['m10']/m['m00'])) | |
| my.append(int(m['m01']/m['m00'])) | |
| else: | |
| mc.append((0,0)) | |
| mx.append(0) | |
| my.append(0) | |
| # loop over our contours | |
| for index, c in enumerate(contours): | |
| # area isn't 0 and is greater than minarea and less than maxarea | |
| if (marea[index] != 0 and marea[index] > minarea and marea[index] < maxarea): | |
| # finding squares | |
| # from http://www.pyimagesearch.com/2014/04/21/building-pokedex-python-finding-game-boy-screen-step-4-6/ | |
| # approximate the contour | |
| peri = cv2.arcLength(c, True) | |
| approx = cv2.approxPolyDP(c, 0.02 * peri, True) | |
| center, wh, angle = cv2.minAreaRect(c) | |
| mwidth.append(wh[0]) | |
| mheight.append(wh[1]) | |
| mwhratio.append(wh[0]/wh[1]) | |
| # if our approximated contour has four points, then | |
| # we can assume that we have found 4-sided objects (possibly squares) | |
| if len(approx) == 4: | |
| msquare.append(1) | |
| # if it's four pointed construct a mask for the contour, then compute mean RGB | |
| # creates a mask equal in size to img | |
| mask = np.zeros(img.shape[:2], dtype="uint8") | |
| # draw and fill contour | |
| cv2.drawContours(mask, [c], -1, 255, -1) | |
| # erode slightly to get away from dirty edges | |
| #mask = cv2.erode(mask, None, iterations = 2) | |
| # extract median BGR value | |
| mean = cv2.mean(img, mask=mask)[:3] | |
| # append color data to mcolor array | |
| mcolorR.append(int(mean[2])) | |
| mcolorG.append(int(mean[1])) | |
| mcolorB.append(int(mean[0])) | |
| else: | |
| # it's not a square | |
| msquare.append(0) | |
| mcolorR.append(0) | |
| mcolorG.append(0) | |
| mcolorB.append(0) | |
| else: | |
| # contour has an area of zero, not interesting | |
| msquare.append(0) | |
| mcolorR.append(0) | |
| mcolorG.append(0) | |
| mcolorB.append(0) | |
| mwidth.append(0) | |
| mheight.append(0) | |
| mwhratio.append(0) | |
| #make a pandas df | |
| locarea = {'index' : mindex, 'X' : mx, 'Y' : my, 'width' : mwidth, 'height' : mheight, 'WHratio': mwhratio, 'Area' : marea, 'R' : mcolorR, 'G' : mcolorG, 'B' : mcolorB, 'square' : msquare, 'child' : mchild} | |
| df = pd.DataFrame(locarea) | |
| # filter df for attributes that would isolate squares of reasonable size | |
| df = df[(df['Area'] > minarea) & (df['Area'] < maxarea) & (df['child'] != -1) & (df['square'] > 0) & (df['WHratio'] < 1.06) & (df['WHratio'] > 0.94)] #& | |
| # variable for computing proximity | |
| pixeldist = 100 | |
| # compute distance matrix and add up which ones have distance less than pixeldist pixels | |
| distmatrix = pd.DataFrame(squareform(pdist(df[['X', 'Y']]))).apply(lambda x: x[x<=pixeldist].count() - 1, axis=1) | |
| df = df.assign(distprox = distmatrix.values) | |
| filteredArea = df['Area'] | |
| sizecomp = np.zeros((len(filteredArea), len(filteredArea))) | |
| for p in xrange(0, len(filteredArea)): | |
| for o in xrange(0, len(filteredArea)): | |
| big = max(filteredArea.iloc[p], filteredArea.iloc[o]) | |
| small = min(filteredArea.iloc[p], filteredArea.iloc[o]) | |
| pct = 100. * (small/big) | |
| sizecomp[p][o] = pct | |
| pixelsizepct = 90 | |
| sizematrix = pd.DataFrame(sizecomp).apply(lambda x: x[x>=pixelsizepct].count() - 1, axis=1) | |
| df = df.assign(sizeprox = sizematrix.values) | |
| ## need to figure out a way to filter the results from the | |
| print df | |
| for index in df['index']: | |
| cv2.drawContours(img, contours, index, (0,0,255), -1) | |
| cv2.imwrite("squares.png", img) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment