def shape_from_blob_moments(blob, response, expand_factor=np.sqrt(2)): ''' Use blob properties to define a region, then correct its shape by using the response surface ''' yy, xx = np.mgrid[:response.shape[0], :response.shape[1]] mask = Ellipse2D.evaluate(yy, xx, True, blob[0], blob[1], expand_factor * blob[2], expand_factor * blob[3], blob[4]).astype(np.int) resp = response.copy() # We don't care about the negative values here, so set to 0 resp[resp < 0.0] = 0.0 props = regionprops(mask, intensity_image=resp)[0] # Now use the moments to refine the shape wprops = weighted_props(props) y, x, major, minor, pa = wprops new_mask = Ellipse2D.evaluate(yy, xx, True, y, x, major, minor, pa).astype(bool) # Find the maximum value in the response max_resp = np.max(response[new_mask]) # print(blob) # print((y, x, major, minor, pa, max_resp)) # import matplotlib.pyplot as p # p.imshow(response, origin='lower', cmap='afmhot') # p.contour(mask, colors='r') # p.contour(new_mask, colors='g') # p.draw() # import time; time.sleep(0.1) # raw_input("?") # p.clf() return np.array([y, x, major, minor, pa, max_resp])
def shape_from_blob_moments(blob, response, expand_factor=np.sqrt(2)): ''' Use blob properties to define a region, then correct its shape by using the response surface ''' yy, xx = np.mgrid[:response.shape[0], :response.shape[1]] mask = Ellipse2D.evaluate(yy, xx, True, blob[0], blob[1], expand_factor * blob[2], expand_factor * blob[3], blob[4]).astype(np.int) resp = response.copy() # We don't care about the negative values here, so set to 0 resp[resp < 0.0] = 0.0 props = regionprops(mask, intensity_image=resp)[0] # Now use the moments to refine the shape wprops = weighted_props(props) y, x, major, minor, pa = wprops new_mask = Ellipse2D.evaluate(yy, xx, True, y, x, major, minor, pa).astype(bool) # Find the maximum value in the response max_resp = np.max(response[new_mask]) # print(blob) # print((y, x, major, minor, pa, max_resp)) # import matplotlib.pyplot as p # p.imshow(response, origin='lower', cmap='afmhot') # p.contour(mask, colors='r') # p.contour(new_mask, colors='g') # p.draw() # import time; time.sleep(0.1) # raw_input("?") # p.clf() return np.array([y, x, major, minor, pa, max_resp])
def _ellipse_overlap(blob1, blob2, grid_space=0.5, return_corr=False): ''' Ellipse intersection are difficult. But counting common pixels is not! This routine creates arrays up-sampled from the original pixel scale to better estimate the overlap fraction. ''' ellip1_area = np.pi * blob1[2] * blob1[3] ellip2_area = np.pi * blob2[2] * blob2[3] if ellip1_area >= ellip2_area: large_blob = blob1 small_blob = blob2 large_ellip_area = ellip1_area small_ellip_area = ellip2_area else: large_blob = blob2 small_blob = blob1 large_ellip_area = ellip2_area small_ellip_area = ellip1_area bound1 = Ellipse2D(True, 0.0, 0.0, large_blob[2], large_blob[3], large_blob[4]).bounding_box bound2 = Ellipse2D(True, small_blob[1] - large_blob[1], small_blob[0] - large_blob[0], small_blob[2], small_blob[3], small_blob[4]).bounding_box # If there is no overlap in the bounding boxes, there is no overlap if bound1[0][1] <= bound2[0][0] or bound1[1][1] <= bound2[1][0]: return 0.0 # Now check if the smaller one is completely inside the larger low_in_large = bound1[0][0] <= bound2[0][0] and \ bound1[0][1] >= bound2[0][1] high_in_large = bound1[1][0] <= bound2[1][0] and \ bound1[1][1] >= bound2[1][1] if low_in_large and high_in_large: if return_corr: # Aover / sqrt(A1 * A2) = A1 / sqrt(A1 * A2) = sqrt(A1/A2) return np.sqrt(small_ellip_area / large_ellip_area) return 1.0 # Only evaluate the overlap between the two. ybounds = (max(bound1[0][0], bound2[0][0]), min(bound1[0][1], bound2[0][1])) xbounds = (max(bound1[1][0], bound2[1][0]), min(bound1[1][1], bound2[1][1])) yy, xx = \ np.meshgrid(np.arange(ybounds[0] - grid_space, ybounds[1] + grid_space, grid_space), np.arange(xbounds[0] - grid_space, xbounds[1] + grid_space, grid_space)) ellip1 = Ellipse2D.evaluate(xx, yy, True, 0.0, 0.0, large_blob[2], large_blob[3], large_blob[4]) ellip2 = Ellipse2D.evaluate(xx, yy, True, small_blob[1] - large_blob[1], small_blob[0] - large_blob[0], small_blob[2], small_blob[3], small_blob[4]) overlap_area = np.sum(np.logical_and(ellip1, ellip2)) * grid_space**2 if return_corr: return overlap_area / np.sqrt(small_ellip_area * large_ellip_area) return overlap_area / small_ellip_area
def _ellipse_overlap(blob1, blob2, grid_space=0.5, return_corr=False): ''' Ellipse intersection are difficult. But counting common pixels is not! This routine creates arrays up-sampled from the original pixel scale to better estimate the overlap fraction. ''' ellip1_area = np.pi * blob1[2] * blob1[3] ellip2_area = np.pi * blob2[2] * blob2[3] if ellip1_area >= ellip2_area: large_blob = blob1 small_blob = blob2 large_ellip_area = ellip1_area small_ellip_area = ellip2_area else: large_blob = blob2 small_blob = blob1 large_ellip_area = ellip2_area small_ellip_area = ellip1_area bound1 = Ellipse2D(True, 0.0, 0.0, large_blob[2], large_blob[3], large_blob[4]).bounding_box bound2 = Ellipse2D(True, small_blob[1]-large_blob[1], small_blob[0]-large_blob[0], small_blob[2], small_blob[3], small_blob[4]).bounding_box # If there is no overlap in the bounding boxes, there is no overlap if bound1[0][1] <= bound2[0][0] or bound1[1][1] <= bound2[1][0]: return 0.0 # Now check if the smaller one is completely inside the larger low_in_large = bound1[0][0] <= bound2[0][0] and \ bound1[0][1] >= bound2[0][1] high_in_large = bound1[1][0] <= bound2[1][0] and \ bound1[1][1] >= bound2[1][1] if low_in_large and high_in_large: if return_corr: # Aover / sqrt(A1 * A2) = A1 / sqrt(A1 * A2) = sqrt(A1/A2) return np.sqrt(small_ellip_area / large_ellip_area) return 1.0 # Only evaluate the overlap between the two. ybounds = (max(bound1[0][0], bound2[0][0]), min(bound1[0][1], bound2[0][1])) xbounds = (max(bound1[1][0], bound2[1][0]), min(bound1[1][1], bound2[1][1])) yy, xx = \ np.meshgrid(np.arange(ybounds[0] - grid_space, ybounds[1] + grid_space, grid_space), np.arange(xbounds[0] - grid_space, xbounds[1] + grid_space, grid_space)) ellip1 = Ellipse2D.evaluate(xx, yy, True, 0.0, 0.0, large_blob[2], large_blob[3], large_blob[4]) ellip2 = Ellipse2D.evaluate(xx, yy, True, small_blob[1]-large_blob[1], small_blob[0]-large_blob[0], small_blob[2], small_blob[3], small_blob[4]) overlap_area = np.sum(np.logical_and(ellip1, ellip2)) * grid_space ** 2 if return_corr: return overlap_area / np.sqrt(small_ellip_area * large_ellip_area) return overlap_area / small_ellip_area