def test_farid_h_horizontal(): """Horizontal Farid on an edge should be a horizontal line.""" i, j = np.mgrid[-5:6, -5:6] image = (i >= 0).astype(float) result = filters.farid_h(image) # Check if result match transform direction assert np.all(result[i == 0] == result[i == 0][0]) assert_allclose(result[np.abs(i) > 2], 0, atol=1e-10)
def test_farid_h_horizontal(): """Horizontal Farid on an edge should be a horizontal line.""" i, j = np.mgrid[-5:6, -5:6] image = (i >= 0).astype(float) result = filters.farid_h(image) # Fudge the eroded points i[np.abs(j) == 5] = 10000 assert np.all(result[i == 0] == result[i == 0][0]) assert_allclose(result[np.abs(i) > 2], 0, atol=1e-10)
def test_farid_h_vertical(): """Horizontal Farid on a vertical edge should be zero.""" i, j = np.mgrid[-5:6, -5:6] image = (j >= 0).astype(float) * np.sqrt(2) result = filters.farid_h(image) assert_allclose(result, 0, atol=1e-10)
def test_farid_h_mask(): """Horizontal Farid on a masked array should be zero.""" result = filters.farid_h(np.random.uniform(size=(10, 10)), np.zeros((10, 10), dtype=bool)) assert (np.all(result == 0))
def test_farid_h_zeros(): """Horizontal Farid on an array of all zeros.""" result = filters.farid_h(np.zeros((10, 10)), np.ones((10, 10), dtype=bool)) assert (np.all(result == 0))
# #Farid_and_Simoncelli_Derivatives x, y = np.mgrid[-10:10:255j, -10:10:255j] img = np.sin(x**2 + y**2) imgx = 2 * x * np.cos(x**2 + y**2) imgy = 2 * y * np.cos(x**2 + y**2) def angle(dx, dy): return np.mod(np.arctan2(dy, dx), np.pi) true_angle = angle(imgx, imgy) angle_farid = angle(farid_h(img), farid_v(img)) angle_sobel = angle(sobel_h(img), sobel_v(img)) angle_scharr = angle(scharr_h(img), scharr_v(img)) angle_prewitt = angle(prewitt_h(img), prewitt_v(img)) def diff_angle(angle_1, angle_2): return np.minimum(np.pi - np.abs(angle_1 - angle_2), np.abs(angle_1 - angle_2)) diff_farid = diff_angle(true_angle, angle_farid) diff_sobel = diff_angle(true_angle, angle_sobel) diff_scharr = diff_angle(true_angle, angle_scharr) diff_prewitt = diff_angle(true_angle, angle_prewitt)
x, y = np.mgrid[-10:10:255j, -10:10:255j] image_rotinv = np.sin(x**2 + y**2) image_x = 2 * x * np.cos(x**2 + y**2) image_y = 2 * y * np.cos(x**2 + y**2) def angle(dx, dy): """Calculate the angles between horizontal and vertical operators.""" return np.mod(np.arctan2(dy, dx), np.pi) true_angle = angle(image_x, image_y) angle_farid = angle(filters.farid_h(image_rotinv), filters.farid_v(image_rotinv)) angle_sobel = angle(filters.sobel_h(image_rotinv), filters.sobel_v(image_rotinv)) angle_scharr = angle(filters.scharr_h(image_rotinv), filters.scharr_v(image_rotinv)) angle_prewitt = angle(filters.prewitt_h(image_rotinv), filters.prewitt_v(image_rotinv)) def diff_angle(angle_1, angle_2): """Calculate the differences between two angles.""" return np.minimum(np.pi - np.abs(angle_1 - angle_2), np.abs(angle_1 - angle_2))
def main( image_path, filename, paper_size: str = '11x17 inches', border: float = 20, # mm image_rescale_factor: float = 0.25, smooth_disk_size: int = 2, hist_clip_limit=0.1, hist_nbins=32, intensity_min=0., intensity_max=1., hatch_spacing_min=0.3, # mm hatch_spacing_max=1., # mm pixel_width=0.9, # mm pixel_height=0.9, # mm angle_jitter='0', # degrees pixel_rotation='0', # degrees merge_tolerances=[0.3, 0.4, 0.5], # mm simplify_tolerances=[0.2], # mm savedir='/mnt/c/code/side/plotter_images/oned_outputs'): # make page paper = Paper(paper_size) drawbox = paper.get_drawbox(border) # load img = rgb2gray(io.imread(Path(image_path))) img_rescale = rescale(img, image_rescale_factor) # img_renorm = exposure.equalize_adapthist(img_rescale, clip_limit=hist_clip_limit, nbins=hist_nbins) # calc dominant angle selem = disk(smooth_disk_size) filt_img = filters.rank.mean(img_renorm, selem) angle_farid = local_angle(filters.farid_h(filt_img), filters.farid_v(filt_img)) # make pixel polys prms = [] for y, row in tqdm(enumerate(img_renorm)): for x, intensity in enumerate(row): p = gp.centered_box(Point(x, y), width=pixel_width, height=pixel_height) a = np.degrees(angle_farid[y, x]) prm = { 'geometry': p, 'x': x, 'y': y, 'raw_pixel_width': pixel_width, 'raw_pixel_height': pixel_height, 'intensity': intensity, 'angle': a, 'group': 'raw_hatch_pixel', } prms.append(prm) raw_hatch_pixels = geopandas.GeoDataFrame(prms) # rescale polys to fit in drawbox bbox = box(*raw_hatch_pixels.total_bounds) _, transform = gp.make_like(bbox, drawbox, return_transform=True) A = gp.AffineMatrix(**transform) scaled_hatch_pixels = raw_hatch_pixels.copy() scaled_hatch_pixels['geometry'] = scaled_hatch_pixels.affine_transform( A.A_flat) scaled_hatch_pixels['scaled_pixel_height'] = scaled_hatch_pixels[ 'geometry'].apply(gp.get_height) scaled_hatch_pixels['scaled_pixel_width'] = scaled_hatch_pixels[ 'geometry'].apply(gp.get_width) # distributions etc angle_jitter_gen = gp.make_callable(eval(angle_jitter)) pixel_rotation_gen = gp.make_callable(eval(pixel_rotation)) scaled_hatch_pixels['angle_jitter'] = angle_jitter_gen( len(scaled_hatch_pixels)) scaled_hatch_pixels['hatch_angle'] = scaled_hatch_pixels[ 'angle'] + scaled_hatch_pixels['angle_jitter'] scaled_hatch_pixels['pixel_rotation'] = pixel_rotation_gen( len(scaled_hatch_pixels)) example_height = scaled_hatch_pixels.loc[0, 'scaled_pixel_height'] example_width = scaled_hatch_pixels.loc[0, 'scaled_pixel_width'] print(f'pixel size = {example_width:.2}x{example_height:.2}mm') spacing_func = functools.partial(np.interp, xp=[intensity_min, intensity_max], fp=[ hatch_spacing_max, hatch_spacing_min, ]) scaled_hatch_pixels['spacing'] = spacing_func( 1 - scaled_hatch_pixels['intensity']) new_rows = [] for i, row in tqdm(scaled_hatch_pixels.iterrows(), total=len(scaled_hatch_pixels)): r = row.copy() p = r['geometry'] if abs(r['pixel_rotation']) > np.finfo(float).eps: p = sa.rotate(p, r['pixel_rotation']) f = gp.hatchbox(p, spacing=r['spacing'], angle=r['hatch_angle']) r['geometry'] = f new_rows.append(r) fills = geopandas.GeoDataFrame(new_rows) fills = fills[fills.length > 0] fill_layer = gp.merge_LineStrings(fills.geometry) sk = vsketch.Vsketch() sk.size(paper.page_format_mm) sk.scale('1mm') sk.stroke(1) sk.geometry(fill_layer) sk.vpype('linesort') for tolerance in merge_tolerances: sk.vpype(f'linemerge --tolerance {tolerance}mm') for tolerance in simplify_tolerances: sk.vpype(f'linesimplify --tolerance {tolerance}mm') sk.vpype('linesort') savepath = Path(savedir).joinpath(filename).as_posix() sk.save(savepath)