Skip to content

Instantly share code, notes, and snippets.

@bhive01
Created October 3, 2016 22:25
Show Gist options
  • Save bhive01/e92304ec0cde3a8b84a54cc73f3d4432 to your computer and use it in GitHub Desktop.
Save bhive01/e92304ec0cde3a8b84a54cc73f3d4432 to your computer and use it in GitHub Desktop.
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