예제 #1
0
def normals_label(tans, qs, keep, labels, s, local_normals, labels_frame):
    label = 1
    for i in range(len(keep) - 1):
        j = keep[i]
        k = s + i
        if labels[j] != 0:
            labels_frame[k] = label
        else:
            labels_frame[k] = 0

        normal = Geom.cross3(tans[j], qs[j])
        mag = Geom.norm3(normal)
        if mag == 0:
            local_normals[k] = 1, 0, 0
            labels_frame[k] = 0
        else:
            normal /= mag
            local_normals[k] = normal

        if labels[j + 1] != labels[j]:
            label += 1

    j = keep[-1]
    normal = Geom.cross3(tans[j], qs[j])
    normal /= Geom.norm3(normal)
    local_normals[k] = normal

    local_normals[s + len(keep) - 1] = normal
    labels_frame[s + len(keep) - 1] = 0
예제 #2
0
def render_frame(im, object_mesh, occlusion_mesh, poly_mesh, R, t, cam, light=None, color=None, poly_color=None):
    if light is None:
        # lazi, lalt = np.deg2rad(30), np.deg2rad(60)
        lazi, lalt = np.deg2rad(30), np.deg2rad(45)
        light = np.r_[cos(lazi)*cos(lalt), sin(lazi)*cos(lalt), sin(lalt)].astype(np.float32)
        light /= Geom.norm3(light)

        light = dot(R.T, light).astype(np.float64)
        # light = light.astype(np.float64)
    #     raise Exception("TODO: Light")

    view = -dot(R.T, t)

    pts_obj = object_mesh.project_verts(R, t, cam)

    obj_map = np.full(im.shape[:2], np.inf, np.float32)
    render_depth(obj_map, pts_obj, object_mesh)

    # --- Buffer occlusion lines ----
    if color is None:
        color = np.r_[0, 155, 255]
    pts_occl = occlusion_mesh.project_verts(R, t, cam)
    norm_proj = dot(occlusion_mesh.normals, R.T)

    if len(occlusion_mesh.edges) == 0:
        line_buf = buffer_points(pts_occl, color, alpha=0.1, size=3)
    else:
        line_buf = buffer_lines(pts_occl, norm_proj, occlusion_mesh, color, view, light, alpha=0.1, shade_method=NORMAL)

    if poly_mesh is not None:
        if poly_color is None:
            poly_color = np.r_[255, 166, 0]
        pts_poly = poly_mesh.project_verts(R, t, cam)
        norm_poly = dot(poly_mesh.normals, R.T)

        poly_buf = buffer_lines(pts_poly, norm_poly, poly_mesh, poly_color, view, light, linewidth=4, shade_method=FLAT)
        poly_buf[:, 2] = 0.001
    else:
        poly_buf = np.empty((0, line_buf.shape[1]), line_buf.dtype)

    # Make buffer out of object depth map, and append to line buffer
    I, J = np.where(obj_map != np.inf)
    depths = 1.02*obj_map[I, J]
    object_buf = empty((len(I), line_buf.shape[1]), line_buf.dtype)
    object_buf[:, 0] = I
    object_buf[:, 1] = J
    object_buf[:, 2] = depths
    object_buf[:, 3] = 0.4
    object_buf[:, 4:] = 255, 255, 255

    final_buf = np.vstack((line_buf, poly_buf, object_buf))

    render_buffer(im, final_buf, bg=255)
예제 #3
0
def normals_from_ray_pairs(Qs):
    '''
    Each sequential ray is treated as bases for normals
    '''
    N = Qs.shape[0]
    normals = np.empty_like(Qs)

    for i in range(0, N - 1):
        n = Geom.cross3(Qs[i + 1], Qs[i])
        mag = Geom.norm3(n)
        for j in range(3):
            normals[i, j] = n[j] / mag

    normals[-1] = normals[-2]

    return normals
예제 #4
0
def smooth_polys(verts, starts, sizes, support=10):
    poly_dir = np.empty_like(verts)
    S = len(starts)
    for p in range(S):
        start = starts[p]
        size = sizes[p]
        poly = verts[start:start + size]

        N = len(poly)
        for i in range(N):
            s = max(0, i - support)
            e = min(N - 1, i + support)

            v = poly[e] - poly[s]
            v /= Geom.norm3(v)
            poly_dir[start + i] = v

    return poly_dir
예제 #5
0
def buffer_lines(pts, norms_proj, mesh, color, view, light, alpha=1.0, shade_method=PHONG, linewidth=1):
    '''
    Use the depth buffer, dbuf, to figure out whether the object needs to be "washed out"
    when drawing.
    Use the normal information to make clear the normal direction of the line.
    '''
    edges = mesh.edges
    normals = mesh.normals
    E = edges.shape[0]

    # Output: [i, j, d, alpha, r, g, b]
    size = 1024
    P = 7
    out = empty((size, P), np.float32)
    N = 0

    for e in range(E):
        edge = edges[e]
        x1, y1, z1 = pts[edge[0]]
        x2, y2, z2 = pts[edge[1]]

        view_local = (view - mesh.verts[edge[0]]).astype(np.float64)

        # n1, n2 = normals[edge[0]], normals[edge[1]]
        normal = normals[e].astype(np.float64)
        normal_l = norms_proj[e].astype(np.float64)
        normal_l /= Geom.norm3(normal_l)
        # light_angle = abs(dot(normal, light))*1.5 + 0.3
        # print(light_angle)

        I, J, a = Drawing.line_aa(x1, y1, x2, y2, linewidth)
        M = len(I)
        depths = np.linspace(z1, z2, M)

        # Resize if necessary
        resize = False
        while size < N + M:
            size *= 2
            resize = True
        if resize:
            newout = empty((size, P), np.float32)
            newout[:N] = out[:N]
            out = newout

        if shade_method == PHONG:
            out_color = phong_shade(color, light, normal, view_local)
        elif shade_method == NORMAL:
            out_color = normal_shade(light, normal, normal_l)
        else:
            out_color = color.astype(np.float64)

        # Copy it in
        for i, n in enumerate(range(N, N + M)):
            out[n, 0] = I[i]
            out[n, 1] = J[i]
            out[n, 2] = depths[i]
            out[n, 3] = a[i] * alpha
            out[n, 4:] = out_color

        N += M

    return out[:N]
예제 #6
0
def detect_loop(ray_inds, Cs, Qs, pluckers, planes, labels, frames, raygrid,
                config, score, total, curv_mean, m2, depths_out, radii_out,
                inlier_out, edge_angles_out, neighbors, status):
    '''
    score: Output, integer array classifying the type of each segment
    '''
    # Each valid segment is labelled with a non-zero label
    # tim = Util.LoopTimer()
    # loop_i = 0
    for ray_ind in ray_inds:
        # tim.loop_start(loop_i)
        # loop_i += 1

        if labels[ray_ind] == 0:
            status[ray_ind] = -1
            score[ray_ind] = 0
            continue

        # First find other segments that are nearby, and might overlap
        # The RayVoxel.Grid class offers very fast lookups at the cost of memory
        near_grid = raygrid.rays_near_ind(ray_ind)
        # tim.add("RayGrid Search")

        if len(near_grid) < 10:
            status[ray_ind] = -1
            continue

        # Filter frame support
        near = filter_frames(near_grid, frames, ray_ind, config.frame_support)
        # close_frames = np.abs(frames[near_grid] - frames[ray_ind]) <= config.frame_support
        # near = near_grid[close_frames]
        # tim.add("Filter frames")

        # Intersect the shortlisted segments with this segment
        # ps, us describe the intersection locations of the other segments'
        # start- and end-points.
        ps1, us, intersecting = find_intersections(Cs, Qs, pluckers, ray_ind,
                                                   planes, near)
        # print("Near:", len(near))
        # tim.add("Find intersections")
        if len(intersecting) < 10:
            status[ray_ind] = -1
            continue

        ray = 0.5 * (Qs[ray_ind] + Qs[ray_ind + 1])
        ray /= Geom.norm3(ray)
        plane = planes[ray_ind]
        normal = plane[:3]
        tangent = Geom.cross3(ray, normal)

        # Create rotation matrix to orthoganally project intersections
        # into plane of this segment. This plane is tangent to the edge
        R_tang = empty((2, 3), ps1.dtype)
        R_tang[0] = ray
        R_tang[1] = tangent

        center = Cs[ray_ind]
        ps2d = dot(R_tang, (ps1 - center).T)
        us2d = dot(R_tang, us.T)
        px, py = ps2d[0], ps2d[1]
        ux, uy = us2d[0], us2d[1]

        # Solve for the intersection with the center of the segment
        # [x, 0] = p + t*u
        uy[uy == 0] = 1e-10
        ts = -py / uy
        depths = px + ts * ux
        # Project the intersecting segments into the normal plane.
        # This plane's normal is roughly aligned with the edge direction.
        R_norm = empty((3, 3), ps1.dtype)
        R_norm[0] = ray
        R_norm[1] = normal
        R_norm[2] = tangent
        centers = dot(R_norm, (Cs[intersecting] - center).T)

        # plane_angles = np.arctan(centers[1]/centers[2])

        # Check where start and end points straddles center ray of this segment
        crossing = py * (py + uy) < 0
        good_depths = (depths > 0.2) & (depths < 1e6)
        # close_frames = np.abs(frames[intersecting] - frames[ray_ind]) <= config.frame_support
        # in_normal_plane = np.abs(plane_angles) <= config.planar_support

        sel = np.where(good_depths & crossing)[0]
        # sel = np.where(good_depths & crossing & (close_frames | in_normal_plane))[0]
        # tim.add("Intersect filter")
        # print("Sel:", len(sel))

        # We're looking for clusters of line segments in the tangent plane
        # These indicate a high likelihood of a persistent edge
        # frames = cloud.frames[ intersecting[sel] ]
        # p = ps2d[:,sel]
        u = us2d[:, sel]
        d = depths[sel]

        c_sel = centers[:, sel]
        rays = empty((2, len(sel)), centers.dtype)
        rays[0] = d - c_sel[0]
        rays[1] = -c_sel[1]

        rays /= CircleRays.norm_ax(rays, axis=0)
        # tim.add("Prepare clustering")

        dthresh = config.depth_thresh
        # Cluster based on circle space
        cluster_inds, radius, depth, dual_centers, dual_rays, inlier_frac = find_cluster_line4(
            c_sel, rays, depth_thresh=dthresh, percentile=config.inlier_thresh)

        # tim.add("Clustering")

        cluster_full = intersecting[sel[cluster_inds]]
        M = min(neighbors.shape[1], len(cluster_full))

        if inlier_frac > 0.02:
            if abs(radius) < config.min_radius:
                # Hard edge
                status[ray_ind] = 1
                score[ray_ind] += len(cluster_full)
            else:
                status[ray_ind] = 2
                score[ray_ind] += len(cluster_full)

            # Want to estimate the depths of the rays on either side of the segment
            u_cluster = u[:, cluster_inds]
            intersect_angles = np.arctan(-u_cluster[0] / u_cluster[1])
            # Zero is verticle
            alpha = np.median(intersect_angles)
            # Find angle between rays
            theta = 0.5 * arccos(dot(Qs[ray_ind], Qs[ray_ind + 1]))
            d1 = depth * sin(PI / 2 + alpha) / sin(PI / 2 - alpha - theta)
            d2 = depth * sin(PI / 2 - alpha) / sin(PI / 2 + alpha - theta)
            depths_out[ray_ind, 0] = d1
            depths_out[ray_ind, 1] = d2
            depths_out[ray_ind, 2] = depth

            # depths_out[ray_ind] = depth
            radii_out[ray_ind] = radius
            inlier_out[ray_ind] = inlier_frac
            edge_angles_out[ray_ind] = alpha

            ray_c = rays[:, cluster_inds]
            cluster_angles = np.abs(np.arctan(ray_c[1] / ray_c[0]))

            closest = Util.argsort(cluster_angles)
            neighbors[ray_ind, :M] = cluster_full[closest[:M]]

        else:
            status[ray_ind] = -1
            score[ray_ind] = 0
            labels[ray_ind] = 0
            continue
예제 #7
0
def cache_segment(Cs, Qs, planes, pluckers, frames, labels, raygrid, inds,
                  eps):
    starts = []
    deltas = []
    depths = []
    sideps = []
    sideds = []
    ray_frames = []
    planar_angles = []
    sel_inds = []
    j = 0

    M = len(inds)
    for ind in range(M):
        ray_ind = inds[ind]
        j += 1
        print(j)

        print("Checking ray_ind:", ray_ind)
        # TODO: Check that this is still working correctly for the triangles
        in_cone = raygrid.rays_near_ind(ray_ind)

        print("Near: {}/{}".format(len(in_cone), raygrid.n_rays))

        if len(in_cone) == 0:
            print("Total grid for ray:", raygrid.ray2vox_count[ray_ind])

        center = Cs[ray_ind]
        ray = Qs[ray_ind:ray_ind + 2].mean(axis=0)
        ray /= Geom.norm3(ray)
        plane = planes[ray_ind]
        normal = plane[:3]
        tangent = cross3(ray, normal)

        print("Intersect planes")
        # TODO: Use Plucker coords to quickly calculate intersection dual ray segments (infinite triangles?)
        # Will need labels. Precalc Plucker before (do same as the planes)
        # ps -> us, should describe how the other segment intersects this plane
        # in terms of it's width
        ps, us, intersecting = find_intersections(Cs, Qs, pluckers, ray_ind,
                                                  plane, in_cone)

        print("Project")
        R = empty((3, 3), ps.dtype)
        R[0] = ray
        R[1] = tangent
        R[2] = normal

        ps2d = dot(R[:2], (ps - center).T)
        us2d = dot(R[:2], us.T)

        # Solve for the intersection with the center of the segment
        # [x, 0] = p + t*u
        us2d[1, us2d[1] == 0] = 1e-10
        ts = -ps2d[1] / us2d[1]
        ds = ps2d[0] + ts * us2d[0]

        # Keep only lines that are more vertical
        # vert = np.abs(us2d[0] / (np.abs(us2d[1]) + 1e-12)) < 0.4
        crossing = ps2d[1] * (ps2d[1] + us2d[1]) < 0
        vert = np.arctan(us2d[0] / us2d[1]) < 0.85
        # near = np.abs(ps2d[1]) < eps*ps2d[0]
        forward = (ds > 0.2) & (ds < 1e6)

        intersecting = in_cone[intersecting]
        centers = dot(R, (Cs[intersecting] - center).T)
        sidep = empty((2, len(intersecting)), Cs.dtype)
        sidep[0] = centers[0]
        sidep[1] = centers[2]

        rays = empty((3, len(intersecting)), Cs.dtype)
        rays[0] = ds - centers[0]
        rays[1] = -centers[2]
        rays[2] = -centers[1]
        # rays = dot(R, Qs[intersecting].T)
        sided = np.empty_like(sidep)
        sided[0] = rays[0]
        sided[1] = rays[1]

        # hori = np.abs(sided[1] / sided[0]) < 1.5*eps
        sel = np.where(forward & crossing)[0]

        ps2d = ps2d[:, sel]
        us2d = us2d[:, sel]

        starts.append(ps2d)
        deltas.append(us2d)
        depths.append(ds[sel])
        ray_frames.append(frames[intersecting[sel]])
        sideps.append(sidep[:, sel])
        sideds.append(1.5 * sided[:, sel])

        planar_angles.append(np.arctan(centers[1, sel] / centers[2, sel]))
        # ray_dot = rays[1, sel] / norm(rays[:,sel], axis=0)
        # planar_angles.append( np.arctan(ray_dot) )

        sel_inds.append(intersecting[sel])

    return starts, deltas, depths, ray_frames, sideps, sideds, sel_inds, planar_angles