1""" 2img_to_path_dots.py 3Andrew Lorimer, November 2024 4Monash University 5 6Converts a path in a monochrome image to a series of points 7in a defined format for laser writing with the confocal 8setup. Configuration is done in img_to_path.ini. 9Uses an array of dots instead of line scanning. For use with 10LabView script. 11""" 12 13import configparser as cp 14import cv2 15import numpy as np 16import sys 17 18CONFIG_SECTION ="Main" 19DEFAULTS = {CONFIG_SECTION: {'speed':'10', 20'dimensions':'100, 100', 21'z':'0', 22'beam_size':'0.1'}} 23DEFAULT_CONFIG_PATH ="img_to_path.ini" 24 25# TODO make proper config values 26padding =10# um 27resolution =0.5 28 29defrow(x, y, z, on, v): 30""" 31 Format a data row. Note on/off value defines whether the laser turns on/off 32 at the end of the line. 33 """ 34return"1\t{:.3f}\t{:.3f}\t{:.3f}\t{:.3f}\t{:d}\n".format(x, y, z, on, v) 35 36defim_to_real(x, y): 37"""Convert (x, y) image coordinates (px) to real world coordinates (um)""" 38return np.array((x, y)) / im_dim[0] * real_dim 39 40 41if __name__ =="__main__": 42 43# Get config file path from arguments or use default path 44iflen(sys.argv) >1and sys.argv[1]: 45 config_path = sys.argv[1] 46else: 47 config_path = DEFAULT_CONFIG_PATH 48 49# Set up config parser 50 config = cp.ConfigParser() 51 config['DEFAULT'] = DEFAULTS 52 config.read_file(open(config_path)) 53 54# Set config values 55 speed = config.getint(CONFIG_SECTION,'speed') 56 real_dim = np.fromstring(config.get(CONFIG_SECTION,'dimensions'), dtype=float, sep=",") 57 z = config.getfloat(CONFIG_SECTION,'z') 58 beam_size = config.getfloat(CONFIG_SECTION,'beam_size') 59 input_path = config.get(CONFIG_SECTION,'input') 60 output_path = config.get(CONFIG_SECTION,'output') 61 62# Read image 63 im = cv2.imread(input_path, cv2.IMREAD_GRAYSCALE) 64 im_dim = im.shape 65 66# Check if aspect ratios match 67if(im_dim[0] / im_dim[1] != real_dim[0]/real_dim[1]): 68print("Warning: input and output aspect ratios do not match - result will be distorted") 69 70# Resize image to produce the required dot resolution 71 im = cv2.resize(im, (int(real_dim[0]/resolution),int(real_dim[1]/resolution))) 72 im_dim = im.shape 73 74# Threshold image to binary 75 _, im = cv2.threshold(im,127,255, cv2.THRESH_BINARY) 76 77# Convert to 0 or 1 78 im = im /255.0 79if np.median(im) >0.5: 80 im = -(im -1) 81 82 cv2.imshow("display", im) 83 cv2.waitKey(0) 84 85 86# Initialise output 87 output ="" 88 89# Go to origin point with laser off 90 output +=row(0.0,0.0, z,0.0, speed) 91 92# Iterate through pixels 93 direction =0 94 current_pos = (0,0) 95for i inrange(im_dim[0]): 96 direction = current_pos[1] > im_dim[1]*resolution 97# if direction == 0: 98 start =0 99 stop = im_dim[0] 100 step =1 101# else: 102# start = im_dim[0] 103# stop = 0 104# step = -1 105for j inrange(start, stop, step): 106if(im[i,j] ==1): 107 output +=row(i*resolution, j*resolution, z,0.0, speed) 108 output +=row(i*resolution, j*resolution, z,1.0, speed) 109 output +=row(i*resolution, j*resolution, z,0.0, speed) 110 current_pos = (i*resolution, j*resolution) 111 112# Turn laser off at current position at go back to origin 113 output +=row(0.0,0.0, z,0.0, speed) 114 115# Write output 116withopen(output_path,'w')as f: 117 f.write(output)