animation/fourcell/calibrate.py

137 lines
3.7 KiB
Python

import sys
import cv2
import numpy as np
import math
from os.path import exists, basename
from common import image_resize, display, normalize_angle
from json import load
#clockwise from top left
order = [ 0, 2, 3, 5, 4, 1 ]
matchMethods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR', 'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
def read_text (textPath) :
holePunches = {}
with open(textPath) as json:
holePunches = load(json)
return holePunches
#
# CALIBRATE
#
if len(sys.argv) < 2:
print('Please provide path of normalized scan to calibrate to')
exit(1)
if len(sys.argv) < 3:
print('Please provide path to output svg template')
exit(2)
normalImage = sys.argv[-2]
if not exists(normalImage) :
print('Normalized scan does not exist, please provide one that does')
exit(2)
normalText = normalImage + '.json'
if not exists(normalText) :
print('Corresponding normalized scan text does not exist, please generate one')
exit(3)
outputTmpl = sys.argv[-1]
print(f'Calibrating to scan {basename(normalImage)}')
registrationMark = cv2.imread('./registrationMark.png', 0)
w, h = registrationMark.shape[:2]
holePunches = read_text(normalText)
original = cv2.imread(normalImage)
img = original.copy()
height, width = img.shape[:2]
orientation = height > width
marks = []
if not orientation :
print(f'Scan is not in portrait mode, exiting...')
exit(3)
print(holePunches)
def get_distance(ref, point):
# print('ref: {} , point: {}'.format(ref, point))
x1, y1 = ref[0], ref[1]
x2, y2 = point[0], point[1]
return math.hypot(x2 - x1, y2 - y1)
def group_points(points):
groups = {}
groupnum = 0
while len(points) > 1:
groupnum += 1
key = str(groupnum)
groups[key] = []
ref = points.pop(0)
for i, point in enumerate(points):
d = get_distance(ref, point)
if d < 30:
groups[key].append(points[i])
points[i] = None
points = list(filter(lambda x: x is not None, points))
return list([[int(np.mean(list([x[0] for x in groups[arr]]))), int(np.mean(list([x[1] for x in groups[arr]])))] for arr in groups])
def find_closest (pt, pts) :
return pts[min(range(len(pts)), key = lambda i: get_distance(pts[i], pt))]
def find_in_half (half) :
halfGray = cv2.cvtColor(half, cv2.COLOR_BGR2GRAY)
res = cv2.matchTemplate(halfGray, registrationMark, cv2.TM_CCOEFF_NORMED)
threshold = 0.7
loc = np.where( res >= threshold)
for pt in zip(*loc[::-1]):
cv2.rectangle(half, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)
return list(zip(*loc[::-1]))
ttly = holePunches['0']['y']-round(height*0.05)
ttlx = holePunches['0']['x']
topHalf = img[ttly:holePunches['1']['y']+round(height*0.1), ttlx:holePunches['2']['x']]
topHalfPts = find_in_half(topHalf)
thpts = group_points(topHalfPts)
for pt in thpts :
#print(f'{ttlx + pt[0]},{ttly + pt[1]}')
marks.append((ttlx + pt[0] + round(w / 2), ttly + pt[1] + round(h / 2),))
print(f'Found {len(thpts)} points')
#display(topHalf)
btly = holePunches['4']['y']-round(height*0.1)
btlx = holePunches['3']['x']
bottomHalf = img[btly:holePunches['5']['y']+round(height*0.05), btlx:holePunches['4']['x']]
bottomHalfPts = find_in_half(bottomHalf)
bhpts = group_points(bottomHalfPts)
for pt in bhpts :
#print(f'{btlx + pt[0]},{btly + pt[1]}')
marks.append((btlx + pt[0] + round(w / 2), btly + pt[1] + round(h / 2), ))
clean = original.copy()
for pt in marks :
print(pt)
cv2.circle(clean, pt, 50, (0,0,255), -1)
print(f'Found {len(bhpts)} points')
if len(marks) != 16 :
print(f'{len(marks)} != 16 marks')
exit(1)
print(find_closest((0,0,), marks))
print(find_closest((width,0,), marks))
print(find_closest((0,height,), marks))
print(find_closest((width,height,), marks))
display(clean)