import sys import cv2 import numpy as np 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) 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}') img = cv2.imread(scanImage) 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) : M = cv2.moments(contour) cX = int(M["m10"] / M["m00"]) cY = int(M["m01"] / M["m00"]) 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 for i in range(len(areaList)) : area = areaList[i] if area > maxArea: maxArea = area maxIndex = i count = 0 holePunches = [] centers = [] centersStr = [] areaRange = 0 # 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 : M = cv2.moments(contourList[i]) cX = int(M["m10"] / M["m00"]) cY = int(M["m01"] / M["m00"]) strC = f'{cX},{cY}' if strC in centersStr : continue centersStr.append(strC) centers.append((cX, cY)) print(f'{cX},{cY}') cv2.circle(img, (cX, cY), 40, (255, 0, 0), -1) holePunches.append(contourList[i]) count+=1 print(f'Found hole punches within {areaRange}% of largest') cv2.drawContours(img, holePunches, -1, (0, 255, 0), 20) display(img)