animation/fourcell/analyze.py

213 lines
4.9 KiB
Python

import sys
import cv2
import numpy as np
import math
def image_resize(image, width = None, height = None, inter = cv2.INTER_AREA):
dim = None
(h, w) = image.shape[:2]
if width is None and height is None:
return image
if width is None:
r = height / float(h)
dim = (int(w * r), height)
else:
r = width / float(w)
dim = (width, int(h * r))
resized = cv2.resize(image, dim, interpolation = inter)
return resized
def display (image) :
resized = image_resize(image, 800, 800)
cv2.imshow('img', resized)
while True:
key = cv2.waitKey(0)
if key == 27:
cv2.destroyAllWindows()
break
exit(0)
def get_center (contour) :
M = cv2.moments(contour)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
return cX, cY
def draw_line (image, hps, a, b) :
print(f'{a} -> {b}')
lA = (hps[a-1]['x'], hps[a-1]['y'])
lB = (hps[b-1]['x'], hps[b-1]['y'])
cv2.line(image, lA, lB, [0, 255, 0], 10)
return (lA, lB)
def horiz_angle (line) :
deltaY = line[1][1] - line[0][1] #P2_y - P1_y
deltaX = line[1][0] - line[0][0] #P2_x - P1_x
angleInDegrees = math.degrees(math.atan2(deltaY, deltaX))
print(angleInDegrees)
return angleInDegrees
def verts_angle (line) :
deltaY = line[1][1] - line[0][1] #P2_y - P1_y
deltaX = line[1][0] - line[0][0] #P2_x - P1_x
angleInDegrees = - (math.atan2(deltaX, deltaY) * 180 / math.pi)
print(angleInDegrees)
return angleInDegrees
if len(sys.argv) < 2:
print('Please provide path to image for analysis')
exit(1)
if len(sys.argv) < 3:
print('Please provide path to template file to create')
exit(2)
scanImage = sys.argv[-2]
templateFile = sys.argv[-1]
print(f'Analyzing {scanImage} and creating {templateFile}')
orig = cv2.imread(scanImage)
img = orig.copy()
height, width = img.shape[:2]
orientation = height > width
pageDim = (11, 8.5)
if not orientation :
pageDim = (8.5, 11)
pageRatio = pageDim[1] / pageDim[0]
left=-1
right=-1
top=-1
bottom=-1
if orientation :
left = width * 0.2
right = width * 0.8
else :
top = height * 0.2
bottom = height * 0.8
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.medianBlur(gray, 31)
ret, thresh = cv2.threshold(blur, 200, 255, cv2.THRESH_BINARY)
canny = cv2.Canny(thresh, 75, 200)
contours, hierarchy = cv2.findContours(canny, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
contourList = []
areaList = []
for contour in contours:
approx = cv2.approxPolyDP(contour, 0.03 * cv2.arcLength(contour, True), True)
if cv2.isContourConvex(approx) :
cX, cY = get_center(contour)
if (orientation and ( cX < left or cX > right) ) or ( not orientation and ( cY < top or cY > bottom)) :
area = cv2.contourArea(contour)
areaList.append(area)
contourList.append(contour)
maxArea=0
maxIndex=0
#reduce to lambda
for i in range(len(areaList)) :
area = areaList[i]
if area > maxArea:
maxArea = area
maxIndex = i
count = 0
holePunches = []
centersStr = []
areaRange = 0
topLeft = None
minDist = 1000000
# pretty good
# add position constraint
while count < 6 :
areaRange+=1
for i in range(len(areaList)) :
area = areaList[i]
if area == maxArea or area * ((100 + areaRange) / 100) > maxArea :
cX, cY = get_center(contourList[i])
strC = f'{cX},{cY}'
if strC in centersStr :
continue
centersStr.append(strC)
print(f'{cX},{cY}')
#cv2.circle(img, (cX, cY), 40, (255, 0, 0), -1)
hp = {
'x' : cX,
'y' : cY,
'contour' : contourList[i],
'dist' : math.dist((cX, cY), (0, 0)),
'order': -1
}
if hp['dist'] < minDist :
minDist = hp['dist']
topLeft = hp
holePunches.append(hp)
count+=1
for hp in holePunches :
hp['dist'] = math.dist( (topLeft['x'], topLeft['y']), (hp['x'], hp['y']) )
holePunches = sorted(holePunches, key = lambda hp: hp['dist'])
i = 0
for hp in holePunches :
hp['order'] = i
cv2.putText(img, str(i + 1), (hp['x'], hp['y']), cv2.FONT_HERSHEY_SIMPLEX, 20, (0, 0, 255), 5, cv2.LINE_AA, False)
i+=1
verts = []
horiz = []
#across top
horiz.append(horiz_angle(draw_line(img, holePunches, 1, 3)))
#across bottom
horiz.append(horiz_angle(draw_line(img, holePunches, 4, 6)))
#middle
horiz.append(horiz_angle(draw_line(img, holePunches, 2, 5)))
#top left
verts.append(verts_angle(draw_line(img, holePunches, 1, 2)))
#long left
verts.append(verts_angle(draw_line(img, holePunches, 1, 4)))
#top right
verts.append(verts_angle(draw_line(img, holePunches, 3, 5)))
#long right
verts.append(verts_angle(draw_line(img, holePunches, 3, 6)))
#bottom left
verts.append(verts_angle(draw_line(img, holePunches, 2, 4)))
#bottom right
verts.append(verts_angle(draw_line(img, holePunches, 5, 6)))
#for v in verts :
#print(v)
#for h in horiz :
# print(h)
# horiz_angle(h)
print(f'Found hole punches within {areaRange}% of largest')
#print(holePunches)
#cv2.drawContours(img, list(map(lambda hp : hp['contour'], holePunches)), -1, (0, 255, 0), 20)
#cv2.circle(img, (topLeft['x'], topLeft['y']), 50, (0, 0, 255), -1)
display(img)