def test_parallel(): l1 = Line() # X-axis l2 = Line(direction_vector=Vector([4, 0, 0]), point=Point(8, 0, 0)) l3 = Line.from_points(Point(1, 1, 1), Point(2, 2, 2)) l4 = Line.from_points(Point(0, 0, 0), Point(-1, -1, -1)) assert l1.is_parallel(l2) assert not l1.is_parallel(l3) assert l3.is_parallel(l4)
def test_contains_point(): l1 = Line.from_points(Point(1, 1, 1), Point(2, 2, 2)) assert l1.contains_point(Point(3, 3, 3)) assert l1.contains_point(Point(0, 0, 0)) assert not l1.contains_point(Point(2, 3, 4)) l2 = Line.from_points(Point(0, 0, 0), Point(2, 0, 0)) assert l2.contains_point(Point(4, 0, 0)) assert l2.contains_point(Point(-3, 0, 0)) assert not l2.contains_point(Point(0, 1, 0))
def test_line_generation(): Line() Line(direction_vector=Vector([1, 1, 1]), point=Point(2, 2, 2)) with pytest.raises(TypeError): Line(direction_vector=Point(1, 1, 1)) with pytest.raises(ValueError): Line(direction_vector=Vector([0, 0, 0])) Line.from_points(Point(1, 1, 1), Point(2, 2, 2))
def full_lines(AH, lines, v): C0 = max(lines, key=lambda l: l.right() - l.left()) v_lefts = [ Line.from_points(v, l[0].left_bot()) for l in lines if l is not C0 ] v_rights = [ Line.from_points(v, l[-1].right_bot()) for l in lines if l is not C0 ] C0_lefts = [l.text_line_intersect(C0)[0] for l in v_lefts] C0_rights = [l.text_line_intersect(C0)[0] for l in v_rights] mask = np.logical_and(C0_lefts <= C0.left() + AH, C0_rights >= C0.right() - AH) return compress(lines, mask)
def estimate_directrix(lines, v, n_points_w): vx, vy = v domain, C0, C1 = widest_domain(lines, v, N_POINTS) C0_points = np.vstack([domain, C0(domain)]) longitudes = [Line.from_points(v, p) for p in C0_points.T] C1_points = np.array([l.closest_poly_intersect(C1.model, p) \ for l, p in zip(longitudes, C0_points.T)]).T lambdas = (vy - C0_points[1]) / (C1_points[1] - C0_points[1]) alphas = MU * lambdas / (MU + lambdas - 1) C_points = (1 - alphas) * C0_points + alphas * C1_points C = C_points.T.mean(axis=0) theta = acos(f / sqrt(vx**2 + vy**2 + f**2)) print('theta:', theta) A = np.array([[1, C[0] / f * -sin(theta)], [0, cos(theta) - C[1] / f * sin(theta)]]) D_points = inv(A).dot(C_points) D_points_arc, _ = arc_length_points(D_points) C_points_arc = A.dot(D_points_arc) # plot_norm(np.vstack([domain, C0(domain)]).T, label='C0') # plot_norm(np.vstack([domain, C1(domain)]).T, label='C1') # plot_norm(C_points.T, label='C20') # plot_norm(D_points.T, label='D') # plot_norm(C_points_arc.T, label='C') # # plt.plot(C_points.T, label='C20') # # plt.plot(C_points_arc.T, label='C') # plt.axes().legend() # plt.show() return D_points_arc, C_points_arc
def generate_mesh(all_lines, lines, C_arc, v, n_points_h): vx, vy = v C_arc_T = C_arc.T C0, C1 = C0_C1(lines, v) # first, calculate necessary mu. global mu_debug mu_debug = cv2.cvtColor(bw, cv2.COLOR_GRAY2BGR) mu_bottom = necessary_mu(C0, C1, v, all_lines, MuMode.BOTTOM) mu_top = necessary_mu(C0, C1, v, all_lines, MuMode.TOP) lib.debug_imwrite('mu.png', mu_debug) longitude_lines = [Line.from_points(v, p) for p in C_arc_T] longitudes = [] mus = np.linspace(mu_top, mu_bottom, n_points_h) for l, C_i in zip(longitude_lines, C_arc_T): p0 = l.closest_poly_intersect(C0.model, C_i) p1 = l.closest_poly_intersect(C1.model, C_i) lam = (vy - p0[1]) / (p1[1] - p0[1]) alphas = mus * lam / (mus + lam - 1) longitudes.append(np.outer(1 - alphas, p0) + np.outer(alphas, p1)) result = np.array(longitudes) debug = cv2.cvtColor(bw, cv2.COLOR_GRAY2BGR) for l in result[::50]: for p in l[::50]: cv2.circle(debug, tuple(p.astype(int)), 6, BLUE, -1) trace_baseline(debug, C0, RED) trace_baseline(debug, C1, RED) lib.debug_imwrite('mesh.png', debug) return np.array(longitudes).transpose(1, 0, 2)
def widest_domain(lines, v, n_points): C0, C1 = C0_C1(lines, v) v_lefts = [ Line.from_points(v, l[0].left_bot()) for l in lines if l is not C0 ] v_rights = [ Line.from_points(v, l[-1].right_bot()) for l in lines if l is not C0 ] C0_lefts = [l.text_line_intersect(C0)[0] for l in v_lefts] C0_rights = [l.text_line_intersect(C0)[0] for l in v_rights] x_min = min(C0.left(), min(C0_lefts)) x_max = max(C0.left(), max(C0_rights)) domain = np.linspace(x_min, x_max, n_points) debug = cv2.cvtColor(bw, cv2.COLOR_GRAY2BGR) for l in lines: cv2.line(debug, tuple(l[0].left_bot().astype(int)), tuple(l[-1].right_bot().astype(int)), GREEN, 2) Line.from_points(v, (x_min, C0(x_min))).draw(debug) Line.from_points(v, (x_max, C0(x_max))).draw(debug) lib.debug_imwrite('domain.png', debug) return domain, C0, C1
def vanishing_point(lines, v0, O): C0 = lines[-1] if v0[1] < 0 else lines[0] others = lines[:-1] if v0[1] < 0 else lines[1:] domain = np.linspace(C0.left(), C0.right(), N_LONGS + 2)[1:-1] C0_points = np.array([domain, C0.model(domain)]).T longitudes = [Line.from_points(v0, p) for p in C0_points] lefts = [longitudes[0].text_line_intersect(line)[0] for line in others] rights = [longitudes[-1].text_line_intersect(line)[0] for line in others] valid_mask = [line.left() <= L and R < line.right() \ for line, L, R in zip(others, lefts, rights)] valid_lines = [C0] + compress(others, valid_mask) derivs = [line.model.deriv() for line in valid_lines] print('valid lines:', len(others)) convergences = [] for longitude in longitudes: intersects = [ longitude.text_line_intersect(line) for line in valid_lines ] tangents = [Line.from_point_slope(p, d(p[0])) \ for p, d in zip(intersects, derivs)] convergences.append(Line.best_intersection(tangents)) # x vx + y vy + f^2 = 0 # m = -vx / vy # b = -f^2 / vy L = Line.fit(convergences) # shift into O-origin coords L_O = L.offset(-O) vy = -(f**2) / L_O.b vx = -vy * L_O.m v = np.array((vx, vy)) + O debug = cv2.cvtColor(bw, cv2.COLOR_GRAY2BGR) for t in tangents: t.draw(debug, color=RED) for longitude in longitudes: longitude.draw(debug) L.draw(debug, color=GREEN) lib.debug_imwrite('vanish.png', debug) return v, f, L
def necessary_mu(C0, C1, v, all_lines, mode): vx, vy = v line = all_lines[mode.index()] points = np.array([mode.point(l) for l in line]) for p in points: global mu_debug cv2.circle(mu_debug, tuple(p.astype(int)), 6, GREEN, -1) longitudes = [Line.from_points(v, p) for p in points] C0_points = np.array([l.text_line_intersect(C0) for l in longitudes]).T C1_points = np.array([l.text_line_intersect(C1) for l in longitudes]).T lambdas = (vy - C0_points[1]) / (C1_points[1] - C0_points[1]) alphas = (points[:, 1] - C0_points[1]) / (C1_points[1] - C0_points[1]) mus = alphas * (1 - lambdas) / (alphas - lambdas) return mus.max() + 0.01 if np.median(mus) >= 0.5 else mus.min() - 0.01
def aspect_ratio(im, lines, D, v, O): vx, vy = v C0, C1 = C0_C1(lines, v) im_h, im_w = im.shape m = -(vx - O[0]) / (vy - O[1]) L0 = Line.from_point_slope(C0.first_base(), m) L1 = Line.from_point_slope(C1.first_base(), m) perp = L0.altitude(v) p0, p1 = L0.intersect(perp), L1.intersect(perp) h_img = norm(p0 - p1) L = Line(m, -m * O[0] - (f**2) / (vy - O[1])) F = L.altitude(v).intersect(L) _, x0r, y0r, w0r, h0r = lines[-1][-1] p0r = np.array([x0r + w0r / 2.0, y0r + h0r]) F_C0r = Line.from_points(F, p0r) q0 = F_C0r.intersect(L0) l_img = norm(q0 - p0) debug = cv2.cvtColor(im, cv2.COLOR_GRAY2BGR) L0.draw(debug) L1.draw(debug) L.draw(debug, color=GREEN) F_C0r.draw(debug, color=RED) lib.debug_imwrite('aspect.png', debug) # Convergence line perp to V=(vx, vy, f) # y = -vx / vy * x + -f^2 / vy alpha = atan2(norm(p1 - O), f) theta = acos(f / sqrt((vx - O[0])**2 + (vy - O[1])**2 + f**2)) beta = pi / 2 - theta lp_img = abs(D[0][-1] - D[0][0]) wp_img = norm(np.diff(D.T, axis=0), axis=1).sum() print('h_img:', h_img, 'l\'_img:', lp_img, 'alpha:', alpha) print('l_img:', l_img, 'w\'_img:', wp_img, 'beta:', beta) r = h_img * lp_img * cos(alpha) / (l_img * wp_img * cos(alpha + beta)) return r
def approx_line(self): return Line.from_points(self.first_base(), self.last_base())