def downsample_for_isotropy(imp, extra_downsample_factor=2.0, info=None): """downsample x, y pixel directions to get ~cubic voxels""" title = imp.getTitle(); cal = imp.getCalibration(); if info is None: pix_w = cal.pixelWidth; pix_h = cal.pixelHeight; pix_d = cal.pixelDepth; else: pix_w = info.get_xy_pixel_size_um(); pix_h = pix_w; pix_d = info.get_z_plane_spacing_um(); im_w = imp.getWidth(); im_h = imp.getHeight(); im_d = imp.getNSlices(); print("original pixel whd = ({}, {}, {})".format(pix_w, pix_h, pix_d)); print("original image whd = ({}, {}, {})".format(im_w, im_h, im_d)); im_nch = imp.getNChannels(); if im_nch > 1: split_ch = ChannelSplitter().split(imp); else: split_ch = [imp]; print("downsampling {} and making isotropic...".format(title)); IJ.showStatus("Downsampling and making ~isotropic..."); xy_scale = pix_h / (pix_d * extra_downsample_factor); xy_scaled_h = int(xy_scale * im_h); xy_scaled_w = int(xy_scale * im_w); z_scale = 1/ extra_downsample_factor; z_scaled_h = int(z_scale * im_d); out_imps = []; for ch_imp in split_ch: print(ch_imp.getTitle()); sp = StackProcessor(ch_imp.getStack()); print((xy_scaled_w, xy_scaled_h)); stack = sp.resize(xy_scaled_w, xy_scaled_h, True); xz_stack = rot_around_x(stack); xz_sp = StackProcessor(xz_stack); xz_stack = xz_sp.resize(xy_scaled_w, z_scaled_h, True); out_stack = rot_around_x(xz_stack); out_imps.append(ImagePlus("Isotropic downsampled {}".format(title), out_stack)); cal.setUnit('um'); cal.pixelWidth = im_w/xy_scaled_w * pix_w; cal.pixelHeight = im_h/xy_scaled_h * pix_h; cal.pixelDepth = im_d/z_scaled_h * pix_d; print("new pixel whd = ({}, {}, {})".format(cal.pixelWidth, cal.pixelHeight, cal.pixelDepth)); imp.changes = False; imp.close(); for ch_imp in split_ch: ch_imp.close(); if len(out_imps) > 1: out_imp = RGBStackMerge().mergeChannels(out_imps, False); else: out_imp = out_imps[0]; out_imp.setCalibration(cal); print("new image whd = ({}, {}, {})".format(out_imp.getWidth(), out_imp.getHeight(), out_imp.getNSlices())); print("...done downsampling {} and making isotropic. ".format(title)); IJ.showStatus("...done downsampling and making ~isotropic. "); return out_imp;
def do_tubefitting(im_path=im_test_path, metadata_path=metadata_test_path, output_path=output_path, save_output=False): # todo: fix things so that all operations use a consistent definition of background rather than changing Prefs on the fly... Prefs.blackBackground = False info = PrescreenInfo() info.load_info_from_json(metadata_path) z_xy_ratio = abs( info.get_z_plane_spacing_um()) / info.get_xy_pixel_size_um() #z_xy_ratio = 1.0; bfimp = bf.openImagePlus(im_path) imp = bfimp[0] imp.show() IJ.run(imp, "Set Scale...", "distance=0 known=0 pixel=1 unit=pixel") imp = utils.downsample_for_isotropy(imp, extra_downsample_factor=1.0, info=info) rot_seg_imp, rot_proj_imp, egfp_mch_imps = split_and_rotate(imp, info) depth = rot_seg_imp.getNSlices() if rot_seg_imp.getNSlices( ) > rot_seg_imp.getNFrames() else rot_seg_imp.getNFrames() width = rot_seg_imp.getWidth() height = int(round(rot_seg_imp.getHeight() * z_xy_ratio)) # Apply 3d MEDIAN FILTER to denoise and emphasise vessel-associated voxels fit_basis_imp = threshold_and_binarise(rot_seg_imp, z_xy_ratio) fit_basis_imp.setTitle("fit_basis_imp") fit_basis_imp.show() # plane-wise, use binary-outline # say the non-zero points then make up basis for fitting to be performed per http://nicky.vanforeest.com/misc/fitEllipse/fitEllipse.html rois = [] centres = [] major_axes = [] roi_imp = IJ.createImage("rois", width, height, depth, 32) pts_stack = ImageStack(width, height + 1) IJ.run(imp, "Line Width...", "line=3") for zidx in range(fit_basis_imp.getNSlices()): fit_basis_imp.setZ(zidx + 1) IJ.run(fit_basis_imp, "Outline", "slice") IJ.run(fit_basis_imp, "Create Selection", "") roi = fit_basis_imp.getRoi() fit_basis_imp.killRoi() pts = [(pt.x, pt.y) for pt in roi.getContainedPoints()] clean_pts = convex_hull_pts(pts) clean_pts = [(x, z_xy_ratio * y) for (x, y) in clean_pts] # make a stack of clean points... ip = FloatProcessor(width, height + 1) pix = ip.getPixels() for pt in clean_pts: pix[int(pt[1]) * width + int(pt[0])] = 128 pts_stack.addSlice(ip) centre, angle, axl = ellipse_fitting.fit_ellipse(clean_pts) major_axes.append(max(axl)) centres.append(centre) rot_seg_imp.setZ(zidx + 1) ellipse_roi = ellipse_fitting.generate_ellipse_roi(centre, angle, axl) rois.append(ellipse_roi) IJ.run(imp, "Line Width...", "line=1") cal = imp.getCalibration() smooth_centres, tangent_vecs = generate_smoothed_vessel_axis( centres, pixel_size_um=cal.pixelDepth) for zidx in range(fit_basis_imp.getNSlices()): centre = smooth_centres[zidx] major_axis = major_axes[zidx] ellipse_roi = EllipseRoi(centre[0] - 2, centre[1], centre[0] + 2, centre[1], 1.0) roi_imp.setZ(zidx + 1) roi_imp.setRoi(ellipse_roi) IJ.run(roi_imp, "Set...", "value=" + str(roi_imp.getProcessor().maxValue()) + " slice") pts_stack_imp = ImagePlus("Cleaned points", pts_stack) pts_stack_imp.setTitle("pts_stack_imp") pts_stack_imp.show() rot_seg_imp.changes = False rot_seg_imp.close() egfp_imp = egfp_mch_imps[0] mch_imp = egfp_mch_imps[1] imps_to_combine = [egfp_mch_imps[1], egfp_mch_imps[0], roi_imp] egfp_imp.show() mch_imp.show() roi_imp.show() print("box height um = " + str(roi_imp.getNSlices() * info.get_xy_pixel_size_um())) IJ.run( egfp_imp, "Size...", "width=" + str(width) + " height=" + str(height) + " depth=" + str(depth) + " average interpolation=Bilinear") IJ.run( mch_imp, "Size...", "width=" + str(width) + " height=" + str(height) + " depth=" + str(depth) + " average interpolation=Bilinear") #IJ.run("Merge Channels...", "c1=[" + mch_imp.getTitle() + # "] c2=[" + egfp_imp.getTitle() + # "] c7=[" + roi_imp.getTitle() + "] create keep"); composite_imp = RGBStackMerge().mergeChannels(imps_to_combine, False) print(composite_imp) composite_imp.show() print("end of vessel centerline id step, image dims = ({}x{}x{})".format( composite_imp.getWidth(), composite_imp.getHeight(), composite_imp.getNSlices())) WaitForUserDialog("pause").show() # do qc here? #WM.getImage("Composite").addImageListener(UpdateRoiImageListener(rois)); IJ.run(roi_imp, "8-bit", "") if save_output: FileSaver(composite_imp).saveAsTiffStack( os.path.join(output_path, "segmentation result.tif")) print(roi_imp) FileSaver(roi_imp).saveAsTiff( os.path.join(output_path, "vessel axis.tif")) egfp_imp.changes = False mch_imp.changes = False roi_imp.changes = False fit_basis_imp.changes = False pts_stack_imp.changes = False egfp_imp.close() mch_imp.close() #roi_imp.close(); fit_basis_imp.close() pts_stack_imp.close() zcoords = [i for i in range(composite_imp.getNSlices())] xyz_smooth_centres = [(x, y, z) for ((x, y), z) in zip(smooth_centres, zcoords)] composite_imp2 = straighten_vessel(composite_imp, xyz_smooth_centres, save_output=True) composite_imp3 = straighten_vessel(composite_imp2, xyz_smooth_centres, it=2, save_output=True) return composite_imp3