import argparse import sys import cv2 import numpy as np from os.path import exists, basename from json import dumps from common import display, draw_text, read_json IN=25.4 DPI=600 W=215.9 H=279.4 ACTIONS=['generate', 'calibrate', 'scale'] MEASUREMENTS={ 'A' : { 'x' : 10.0 }, # X 10mm 'B' : { 'x' : 50.0 }, # X 50mm 'C' : { 'x' : 100.0 }, # X 100mm 'D' : { 'y' : 10.0 }, # Y 10mm 'E' : { 'y' : 50.0 }, # Y 50mm 'F' : { 'y' : 100.0 } # Y 100mm } def create_blank(width, height): rgb_color=(255,255,255) image = np.zeros((height, width, 3), np.uint8) color = tuple(reversed(rgb_color)) image[:] = color return image def generate (args) : if args.output is None: print(f'Please include an -o/--output image') exit(1) print('generate') print('--------') dpi = DPI if args.dpi is not None : dpi = args.dpi dpmm = dpi / IN print(f'DPI:{dpi}') print(f'DPMM:{dpmm}') w = int(W * dpmm) h = int(H * dpmm) blank = create_blank(w, h) topLeftX = int(round(w * 0.2)) topLeftY = int(round(h * 0.2)) bottomRightX = int(round(w * 0.8)) bottomRightY = int(round(h * 0.8)) hundred = int(round(100.0 * dpmm)) five = int(round(2.5 * dpmm)) cv2.line(blank, (topLeftX, topLeftY,), (topLeftX + hundred, topLeftY,), [0, 0, 0], 1) cv2.line(blank, (topLeftX, topLeftY,), (topLeftX, topLeftY + hundred,), [0, 0, 0], 1) for i in MEASUREMENTS.keys() : if 'x' in MEASUREMENTS[i] is not None: x = int(round(MEASUREMENTS[i]['x'] * dpmm)) cv2.line(blank, (topLeftX + x, topLeftY + five,), (topLeftX + x, topLeftY - five,), [0, 0, 0], 1) draw_text(blank, (topLeftX + x, topLeftY - five - int(2 * dpmm),), f'{i}', dpi) elif 'y' in MEASUREMENTS[i] is not None: y = int(round(MEASUREMENTS[i]['y'] * dpmm)) cv2.line(blank, (topLeftX + five, topLeftY + y,), (topLeftX - five, topLeftY + y,), [0, 0, 0], 1) draw_text(blank, (topLeftX + five + int(2 * dpmm), topLeftY + y,), f'{i}', dpi) cv2.imwrite(args.output, blank) def calculate_scale (obj) : xReal = 0 xMeasured = 0 yReal = 0 yMeasured = 0 for i in MEASUREMENTS.keys() : if 'x' in MEASUREMENTS[i] is not None: xReal += MEASUREMENTS[i]['x'] xMeasured += obj[i] elif 'y' in MEASUREMENTS[i] is not None: yReal += MEASUREMENTS[i]['y'] yMeasured += obj[i] return xReal / xMeasured, yReal / yMeasured def merge (original, newImg) : oH, oW = original.shape[:2] nH, nW = newImg.shape[:2] if nH == oH and nW == oW : return newImg if nH > oH and nW > oW : # total crop offsetX = int((nW - oW) / 2) offsetY = int((nH - oH) / 2) return newImg[offsetY:offsetY+oH, offsetX:offsetX+oW] if nH < oH and nW < oW : # total placement offsetX = int((oH - nH) / 2) offsetY = int((oW - nW) / 2) original[offsetY:offsetY+nH, offsetX:offsetX+nW] = newImg return original if nH > oH and nW <= oW : offsetX = int((oW - nW) / 2) offsetY = int((nH - oH) / 2) crop = newImg[offsetY:offsetY+oH,0:nW] original[0:oH, offsetX:offsetX+nW] = crop return original if nH <= oH and nW > oW : offsetX = int((nW - oW) / 2) offsetY = int((oH - nH) / 2) crop = newImg[0:nH,offsetX:offsetX+oW] original[offsetY:offsetY+nH, 0:oW] = crop return original def calibrate (args) : print('calibrate') print('---------') json = {} name = input('Printer name: ') json['name'] = name for m in MEASUREMENTS.keys(): val = input(f'{m}: ') json[m] = float(val) x, y = calculate_scale(json) json['x'] = x json['y'] = y txt=dumps(json, sort_keys = True, indent = 4) if args.output is None : print(f'{txt}') else : print(f'Wrote file to {args.output}') with open(args.output, 'w') as output: output.write(txt) def scale (args) : print('scale') print('-----') if args.calibration is None : print(f'Please provide a calibration file (-c/--calibration)') exit(1) if args.input is None : print(f'Please provide an input file (-i/--input)') exit(2) if args.output is None: print(f'Please provide an output file (-o/--output)') exit(3) obj = read_json(args.calibration) img = cv2.imread(args.input) height, width = img.shape[:2] output = create_blank(width, height) newWidth = int(round(width * obj['x'])) newHeight = int(round(height * obj['y'])) dim = (newWidth, newHeight) resized = cv2.resize(img, dim, interpolation = cv2.INTER_AREA) output = merge(output, resized) cv2.imwrite(args.output, output) def main () : parser = argparse.ArgumentParser(description='Create a calibration file, apply to a scanned page, or scale image to desired DPI.') parser.add_argument('action', help='The action to perform', choices=ACTIONS) parser.add_argument('--dpi', '-d', help='DPI to generate', required=False, type=int) parser.add_argument('--input', '-i', help='Input file', required=False) parser.add_argument('--output', '-o', help='Output file', required=False) parser.add_argument('--calibration', '-c', help='Calibration file', required=False) args = parser.parse_args() if args.action == 'generate' : generate(args) elif args.action == 'calibrate' : calibrate(args) elif args.action == 'scale' : scale(args) main()