import math from ijutils import * import ij.process.Blitter as Blitter COVER_SIZE_MM = 707.0 DISK_SIZE_MM = 260.0 TARGET_SIZE_MM = 40.0 TARGET_HOLES = False def set_circle_mask(ip, center_x, center_y, radius, bitwise=False): w, h = ip.getWidth(), ip.getHeight() if bitwise: for y in range(h): for x in range(w): distance = math.hypot(x - center_x, y - center_y) if distance >radius: ip.putPixel(x, y, 0) else: mask = ip.createProcessor(w, h) # Creates a new blank ImageProcessor mask.setColor(255) # Set the drawing color to white (255) mask.fillOval(int(center_x - radius), int(center_y - radius), int(2 * radius), int(2 * radius)) # Draw the circular ROI mask.autoThreshold() # Ensures the mask is binary (if needed) ip.copyBits(mask, 0, 0, Blitter.AND) # Apply the mask using a bitwise AND last_target_detection = None use_target_cache = False def detect_cover_position( ip, center=None, diam_target=95, diam_disk=670, diam_dewar=1800, mask_disk=0.8, mask_dewar=0.98, border_dewar=0.7, offset_threshold=10,\ target_time_tolerance=0.0, open_strategy = "both", print_table=False, output_image=False, threshold_method="IsoData", debug=False): global last_target_detection, use_target_cache use_target_cache = False if output_image==True: output_image= "outlines" if ip.getProcessor().isGrayscale(): ig = ip else: ig = grayscale(ip, in_place=False) w, h = ip.getWidth(), ip.getHeight() if center is None: center = (int(w/2), int(h/2)) if mask_dewar>0: set_circle_mask(ip.getProcessor(), center_x=center[0], center_y=center[1], radius=diam_dewar*(mask_dewar/2.0), bitwise=False) if debug: ImageBuffer.saveImage(ip.getProcessor().getBufferedImage(), os.path.abspath(expand_path("{images}/Masked.png")), "png") #Suggested Methods: (Check AutoThresholder.getMethods()) #"Default", 'Huang', "IsoData", "Moments", "Otsu" it = auto_threshold(ig, dark_background=True, method=threshold_method, in_place=False) ip = it.getProcessor() #if mask_dewar>0: # set_circle_mask(ip, center_x=center[0], center_y=center[1], radius=diam_dewar*(mask_dewar/2.0), bitwise=False) #it.show() if open_strategy in ("black", "both"): #Refine inner (target) binary_open(it, dark_background=True, iterations=1, count=1); if open_strategy in ("white", "both"): #Refine outer (disk) binary_open(it, dark_background=False, iterations=1, count=1); #it.repaintWindow() if debug: ImageBuffer.saveImage(ip.getBufferedImage(), os.path.abspath(expand_path("{images}/DiskDetect.png")), "png") #Detect outer white circle: disk px = int(pow(diam_disk/2,2) * math.pi) (res2,out2)=analyse_particles(it, px/2, px*2, \ fill_holes = True, exclude_edges = True, print_table=print_table, \ output_image = output_image, minCirc = 0.8, maxCirc = 1.0) if res2.size() != 1: msg = "Disk detection error: " + ("none" if res2.size()==0 else "") for i in range( res2.size()): msg = msg + "(" + str(res2.getValue("XM", 0)) + ", " + str( res2.getValue("YM", 0)) + ")" raise Exception( msg ) x2,y2 = res2.getValue("XM", 0), res2.getValue("YM", 0) invert(it, in_place=True) if debug: ImageBuffer.saveImage(ip.getBufferedImage(), os.path.abspath(expand_path("{images}/TargetDetectBeforeMask.png")), "png") if mask_disk>0: set_circle_mask(ip, center_x=x2, center_y=y2, radius=diam_disk*(mask_disk/2.0), bitwise=False) if debug: ImageBuffer.saveImage(ip.getBufferedImage(), os.path.abspath(expand_path("{images}/TargetDetect.png")), "png") #Detect inner black circle: target px = int(pow(diam_target/2,2) * math.pi) (res1,out1)=analyse_particles(it, px/2, px*2, \ fill_holes = True, exclude_edges = True, print_table=print_table, \ output_image = output_image, minCirc = 0.8 if TARGET_HOLES else 0.8 , maxCirc = 1.0) if res1.size() != 1: x1, y1, timestamp = last_target_detection if (last_target_detection is not None) else (0,0,0) #Uses previoes inner position if close to center of outter, for during certain time if (target_time_tolerance<=0) or (time.time() - timestamp > target_time_tolerance): msg = "Target detection error: " + ("none" if res1.size()==0 else "") for i in range( res1.size()): msg = msg + "(" + str(res1.getValue("XM", 0)) + ", " + str( res2.res1("YM", 0)) + "), " raise Exception( msg ) use_target_cache = True else: x1,y1 = res1.getValue("XM", 0), res1.getValue("YM", 0) last_target_detection = (x1,y1, time.time()) if abs(x1-x2) > offset_threshold or abs(y1-y2) > offset_threshold: msg = "Disk/Target offset error: " + "(" + str(int(x1-x2)) + ", " + str(int(y1-y2)) + ")" raise Exception( msg ) border_dewar = 0.9 distance = math.hypot(x1-center[0], y1-center[1]) distance_threshold = border_dewar * diam_dewar /2 if distance > distance_threshold: msg = "Cover position outside dewar: " + "(" + str(int(x1)) + ", " + str(int(y1)) + ")" raise Exception( msg ) return x1,y1 def detect_no_cover( ip, center=None, diam_dewar=1800, border_dewar=0.7, open_strategy = "none", print_table=False, output_image=False, threshold_method="IsoData", debug=False): if output_image==True: output_image= "outlines" if ip.getProcessor().isGrayscale(): ig = ip else: ig = grayscale(ip, in_place=False) w, h = ip.getWidth(), ip.getHeight() if center is None: center = (int(w/2), int(h/2)) radius =diam_dewar*(border_dewar/2.0) * 1.2 set_circle_mask(ip.getProcessor(), center_x=center[0], center_y=center[1], radius=radius*1.05, bitwise=False) if debug: ImageBuffer.saveImage(ip.getProcessor().getBufferedImage(), os.path.abspath(expand_path("{images}/NoCoverMasked.png")), "png") #it = auto_threshold(ig, dark_background=True, method=threshold_method, in_place=False) it = threshold(ig, 15, 255, in_place=True) ip = it.getProcessor() if open_strategy in ("black", "both"): #Refine inner (target) binary_open(it, dark_background=True, iterations=1, count=1); if open_strategy in ("white", "both"): #Refine outer (disk) binary_open(it, dark_background=False, iterations=1, count=1); if debug: ImageBuffer.saveImage(ip.getBufferedImage(), os.path.abspath(expand_path("{images}/NoCoverBinary.png")), "png") px = int(pow(radius,2) * math.pi) (res2,out2)=analyse_particles(it, px*0.8, px*1.3, \ fill_holes = True, exclude_edges = True, print_table=print_table, \ output_image = output_image, minCirc = 0.7, maxCirc = 1.0) if res2.size() == 1: return True return False