def generate_attraction_points(self, N): """ drop shape from: https://math.stackexchange.com/a/481988/660780 """ i = 0 points = [] while i < N: x, y, z = np.random.rand(3) x = remap(x, 0, 1, -1, 1) y = remap(y, 0, 1, -1, 1) z = remap(z, 0, 1, -1, 0) in_drop_shape = (x**2 + y**2 + z**4 - z**2 <= 0) if in_drop_shape: points.append((x, remap(z, -1, 0, 1, 2), y)) i += 1 return points
def run(args): MIN_LEN = 10 MAX_LEN = 70 dx_noise = OpenSimplex(42) dx_noise_mult = 0.010 dy_noise = OpenSimplex(211) dy_noise_mult = 0.010 img = cv2.imread(args.pic) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) H, W = gray.shape[:2] pos = np.random.randint(0, min(H, W), size=2).astype(np.float64) path = [pos.copy()] i = 0 ITER = 50000 pbar = tqdm.tqdm(total=ITER) while i < ITER: # direction = np.random.rand(2) - 0.5 dx = dx_noise.noise2d(x=pos[0] * dx_noise_mult, y=pos[1] * dx_noise_mult) dy = dy_noise.noise2d(x=pos[0] * dy_noise_mult, y=pos[1] * dy_noise_mult) direction = np.array([dy, dx]) direction /= np.linalg.norm(direction) try: value = gray[int(np.round(pos[0])), int(np.round(pos[1]))] except IndexError: value = 255 length = remap(value, 0, 255, MIN_LEN, MAX_LEN) length = MAX_LEN new_pos = pos + direction * length if np.any(new_pos < 0) or np.any(new_pos >= (H, W)): direction = np.array([H / 2, W / 2]) - pos direction /= np.linalg.norm(direction) pos += direction * length path.append(pos.copy()) i += 1 pbar.update() pbar.close() vis = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR) path = np.round(path).astype(np.int32) print('path.shape: {}'.format(path.shape)) # print('path: {}'.format(path)) for i in range(1, path.shape[0]): cv2.line(vis, tuple(path[i - 1, ::-1]), tuple(path[i, ::-1]), (0, 0, 255), 1) # cv2.imshow("cv: img", img) # cv2.imshow("cv: gray", gray) cv2.imshow("cv: vis", vis) while True: c = cv2.waitKey(0) if c == ord('q'): break return 0
def squiggle(points, r=10): r_noise = OpenSimplex(42) angle_noise = OpenSimplex(211) result = [] r_noise_mult = 0.01 angle_noise_mult = 0.02 angles = [] pts = np.concatenate((points[-1, np.newaxis, :], points), axis=0).astype(np.float32) prev_dist = 0 for i in tqdm.tqdm(range(1, len(pts))): prev_pt = pts[i - 1, :] pt = pts[i, :] dist = np.linalg.norm(prev_pt - pt) for step in np.linspace(0, 1, 100): cur_dist = step * dist + (1 - step) * prev_dist x = prev_pt[0] + step * (pt[0] - prev_pt[0]) y = prev_pt[1] + step * (pt[1] - prev_pt[1]) new_r = remap( r_noise.noise2d(x=x * r_noise_mult, y=y * r_noise_mult), -1, 1, cur_dist / 2, cur_dist, ) new_angle = remap( angle_noise.noise2d(x=x * angle_noise_mult, y=y * angle_noise_mult), -1, 1, 0, 2 * np.pi, ) # new_angle = angle angles.append(new_angle) x = new_r * np.cos(new_angle) + prev_pt[0] + step * (pt[0] - prev_pt[0]) y = new_r * np.sin(new_angle) + prev_pt[1] + step * (pt[1] - prev_pt[1]) result.append((x, y)) prev_dist = dist return np.array(result)
def d_sep_fn(pos): x, y = clip_to_img(np.round(pos), gray).astype(np.int32) val = gray[y, x] / 255 val = val**2 return remap(val, 0, 1, 0.8, 10)
def chiu2015tone_scribble(points, r=1, speed_img=None, edge_dist_img=None): points = points.astype(np.float32) r_abs_min = 10 r_min = 20 r_max = r r = r # disk radius # state tracer = PolylineTracer(points) pos = tracer.step(0) angle = 0 angular_velocity = np.pi / 10 # radians per time unit # min_pos_velocity = 0.1 # pixels per time unit # max_pos_velocity = 5 # pixels per time unit min_pos_velocity = 0.1 # pixels per time unit max_pos_velocity = 13 # pixels per time unit step_frequency = 1 # steps per time unit def velocity_at_pos(x): if speed_img is None: coeff = 1 else: int_pos = clip_to_img(np.int32(np.round(x)), speed_img) coeff = speed_img[int_pos[1], int_pos[0]] # coeff = piecewise_linear(coeff, # (0, 0.0), # (0.2, 0.1), # (0.21, 1), # (1, 1)) # coeff = 0.2 velocity = min_pos_velocity + coeff * (max_pos_velocity - min_pos_velocity) return velocity def radius_at_pos(x): int_pos = clip_to_img(np.int32(np.round(x)), speed_img) coeff = speed_img[int_pos[1], int_pos[0]] # coeff = piecewise_linear(coeff, # (0, 0.0), # (0.6, 0.1), # (0.61, 1), # (1, 1)) radius = r_min + coeff * (r_max - r_min) if edge_dist_img is None: return radius else: edge_dist = edge_dist_img[int_pos[1], int_pos[0]] radius = np.clip(radius, r_min, edge_dist) radius = np.clip(radius, r_abs_min, r_max) return radius theta_noise = OpenSimplex(42) flat_noise = OpenSimplex(211) step = 0 output_pts = [] while pos is not None: step += 1 # if step > 1000: # break current_velocity = velocity_at_pos(pos) current_radius = radius_at_pos(pos) theta = remap(theta_noise.noise2d(x=0, y=step * 1e-2 / step_frequency), -1, 1, 0, 2 * np.pi) flatness = remap( flat_noise.noise2d(x=0, y=step * 1e-2 / step_frequency), -1, 1, 0.2, 1) R = rotation_matrix(theta) scribble_pos = np.array((flatness * current_radius * np.cos(angle), current_radius * np.sin(angle))) scribble_pos = np.matmul(R, scribble_pos) scribble_pos = pos + scribble_pos output_pts.append(scribble_pos) pos = tracer.step(current_velocity / step_frequency) # pos = tracer.step(4) angle += angular_velocity / step_frequency output_pts = np.array(output_pts) return output_pts
def rev_geomspace(start, stop, num): return remap(np.geomspace(start, stop, num), start, stop, stop, start)
def run(args): N_per_layer = 8 N_per_blob = 21 N_layers = 12 r_min_layer = 5.5 r_layer_step = 1.6 N_per_circle = 30 r_circle_min = 0.05 r_circle_max = 1.1 paths = [] for i_layer in range(N_layers): r_layer = r_min_layer + i_layer * r_layer_step center_angles = np.linspace(0, 2 * np.pi, N_per_blob * N_per_layer, endpoint=False) # center_angles -= np.exp(remap(i_layer, 0, N_layers-1, # 0, 0.6)) # center_angles -= np.exp(i_layer*1.618 / N_layers) center_angles -= remap(i_layer, 0, N_layers - 1, 0, np.radians(120)) # center_angles += 1.618033 * i_layer for i_blob in range(N_per_layer): for i_circle in range(N_per_blob): center_x = r_layer * np.cos( center_angles[i_blob * N_per_blob + i_circle]) center_y = r_layer * np.sin( center_angles[i_blob * N_per_blob + i_circle]) # r_circle = remap(abs(i_circle - N_per_blob // 2), # 0, N_per_blob // 2, # r_circle_max, r_circle_min) r_circle = np.sin(remap(i_circle, 0, N_per_blob, 0, np.pi)) * r_circle_max + r_circle_min angle_start = np.random.rand() * 2 * np.pi angle_end = angle_start + 2 * np.pi angles = np.linspace(angle_start, angle_end, N_per_circle) sins = np.sin(angles) cosins = np.cos(angles) points = np.zeros((N_per_circle, 2)) points[:, 0] = cosins * r_circle + center_x points[:, 1] = sins * r_circle + center_y paths.append(points) # plt.axis('equal') # vis_drawing(paths, 'k-', linewidth=0.1) # plt.gca().invert_yaxis() # plt.show() x_margin_mm = 10 y_margin_mm = 10 H = 210 # A4 W = 297 # A4 to_draw = resize_and_center(paths, H, W, x_margin_mm, x_margin_mm, y_margin_mm, y_margin_mm) vis_drawing(to_draw, 'r-', linewidth=0.1) to_draw = optimize(to_draw, line_simplification_threshold=0.1) vis_drawing(to_draw, 'k-', linewidth=0.1) plt.plot([0, W, W, 0, 0], [0, 0, H, H, 0], 'k:') plt.axis('equal') plt.gca().invert_yaxis() plt.show() H = 210 # A4 W = 297 # A4 # baud = 115200 baud = 9600 with Plotter('/dev/ttyUSB0', baud) as p: p.load_config('config.json') p.set_input_limits((0, 0), (W, 0), (0, H), (W, H)) p.draw_polylines(to_draw) return 0