ChrisWu1997 / PQ-NET

code for our CVPR 2020 paper "PQ-NET: A Generative Part Seq2Seq Network for 3D Shapes"
MIT License
116 stars 19 forks source link

how to view the bouding-box? #15

Closed duzhenjiang113 closed 3 years ago

duzhenjiang113 commented 3 years ago

Hi, could you please tell me how to view the shape's bounding-box? like this image thanks a lot

ChrisWu1997 commented 3 years ago

Hope the code below can help you.

def minmax2points(minmax):
    minp = minmax[:3]
    maxp = minmax[3:]
    P = np.asarray([minp,
         [maxp[0], minp[1], minp[2]],
         [maxp[0], minp[1], maxp[2]],
         [minp[0], minp[1], maxp[2]],
         [minp[0], maxp[1], minp[2]],
         [maxp[0], maxp[1], minp[2]],
         maxp,
         [minp[0], maxp[1], maxp[2]],
         ])
    P = P[:, [2, 1, 0]]  # FIXME: switch axis
    return P

def points2verts(Z):
    verts = [[Z[0], Z[1], Z[2], Z[3]],
             [Z[4], Z[5], Z[6], Z[7]],
             [Z[0], Z[1], Z[5], Z[4]],
             [Z[2], Z[3], Z[7], Z[6]],
             [Z[1], Z[2], Z[6], Z[5]],
             [Z[4], Z[7], Z[3], Z[0]]]
    return verts

def draw_parts_bbox(bboxes, ax, limit=64, transparency=0.6):
    """draw AABB of part box assembly with transparent face"""
    from mpl_toolkits.mplot3d.art3d import Poly3DCollection, Line3DCollection
    n_parts = bboxes.shape[0]
    colors = [[255, 105, 180],
              [30, 144, 255],
              [127, 255, 212],
              [255, 215, 0],
              [139, 69, 19],
              [205, 102, 29],
              [255, 231, 186],
              [238, 197, 145],
              [139, 35, 35]]
    colors = np.asarray(colors) / 255
    # points = np.round(points).astype(np.int)
    for idx in range(n_parts):
        bbox = bboxes[idx]
        points = minmax2points(bbox)
        verts = points2verts(points)

        pc = Poly3DCollection(verts, linewidths=0.5, edgecolors='k', alpha=transparency)
        pc.set_facecolor(colors[idx % len(colors)])
        ax.add_collection3d(pc)

        # size = (bbox[3:] - bbox[:3]).tolist()
        # for s, e in combinations(np.array(list(product(bbox[[2, 5]], bbox[[1, 4]], bbox[[0, 3]]))), 2):
        #     if np.sum(np.abs(s - e)) in size:
        #         ax.plot3D(*zip(s, e), color=colors[idx % len(colors)], alpha=transparency)

    ax.set_xlim(0, limit)
    ax.set_ylim(0, limit)
    ax.set_zlim(0, limit)

def vis_box(paths, save_image=False):
    """visualize axis-aligned bounding box(AABB) for part assembly of format 'npy' 
       each npy of shape (K, 6), K the number of parts, 6 the coordinates of min/max points
       (min.x, min.y, min.z, max.x, max.y, max.z)
    """
    import matplotlib.pyplot as plt
    from mpl_toolkits.mplot3d import Axes3D

    for path in paths:
        file_format = path.split('.')[-1]
        if file_format != 'npy':
            print("skip file: {}".format(path))
            continue

        print("vis box: {}".format(path))

        box_minmax = np.load(path)
        fig = plt.figure()
        ax1 = fig.gca(projection='3d')
        draw_parts_bbox(box_minmax, ax1)
        ax1.view_init(elev=40, azim=-40) # set initial view angle position
        plt.axis('off')  # hide axis

        if save_image:
            save_path = os.path.join(path[:-4] + '-box.png')
            plt.savefig(save_path, transparent=True)
        plt.show()
        plt.close()
duzhenjiang113 commented 3 years ago

Hope the code below can help you.

def minmax2points(minmax):
    minp = minmax[:3]
    maxp = minmax[3:]
    P = np.asarray([minp,
         [maxp[0], minp[1], minp[2]],
         [maxp[0], minp[1], maxp[2]],
         [minp[0], minp[1], maxp[2]],
         [minp[0], maxp[1], minp[2]],
         [maxp[0], maxp[1], minp[2]],
         maxp,
         [minp[0], maxp[1], maxp[2]],
         ])
    P = P[:, [2, 1, 0]]  # FIXME: switch axis
    return P

def points2verts(Z):
    verts = [[Z[0], Z[1], Z[2], Z[3]],
             [Z[4], Z[5], Z[6], Z[7]],
             [Z[0], Z[1], Z[5], Z[4]],
             [Z[2], Z[3], Z[7], Z[6]],
             [Z[1], Z[2], Z[6], Z[5]],
             [Z[4], Z[7], Z[3], Z[0]]]
    return verts

def draw_parts_bbox(bboxes, ax, limit=64, transparency=0.6):
    """draw AABB of part box assembly with transparent face"""
    from mpl_toolkits.mplot3d.art3d import Poly3DCollection, Line3DCollection
    n_parts = bboxes.shape[0]
    colors = [[255, 105, 180],
              [30, 144, 255],
              [127, 255, 212],
              [255, 215, 0],
              [139, 69, 19],
              [205, 102, 29],
              [255, 231, 186],
              [238, 197, 145],
              [139, 35, 35]]
    colors = np.asarray(colors) / 255
    # points = np.round(points).astype(np.int)
    for idx in range(n_parts):
        bbox = bboxes[idx]
        points = minmax2points(bbox)
        verts = points2verts(points)

        pc = Poly3DCollection(verts, linewidths=0.5, edgecolors='k', alpha=transparency)
        pc.set_facecolor(colors[idx % len(colors)])
        ax.add_collection3d(pc)

        # size = (bbox[3:] - bbox[:3]).tolist()
        # for s, e in combinations(np.array(list(product(bbox[[2, 5]], bbox[[1, 4]], bbox[[0, 3]]))), 2):
        #     if np.sum(np.abs(s - e)) in size:
        #         ax.plot3D(*zip(s, e), color=colors[idx % len(colors)], alpha=transparency)

    ax.set_xlim(0, limit)
    ax.set_ylim(0, limit)
    ax.set_zlim(0, limit)

def vis_box(paths, save_image=False):
    """visualize axis-aligned bounding box(AABB) for part assembly of format 'npy' 
       each npy of shape (K, 6), K the number of parts, 6 the coordinates of min/max points
       (min.x, min.y, min.z, max.x, max.y, max.z)
    """
    import matplotlib.pyplot as plt
    from mpl_toolkits.mplot3d import Axes3D

    for path in paths:
        file_format = path.split('.')[-1]
        if file_format != 'npy':
            print("skip file: {}".format(path))
            continue

        print("vis box: {}".format(path))

        box_minmax = np.load(path)
        fig = plt.figure()
        ax1 = fig.gca(projection='3d')
        draw_parts_bbox(box_minmax, ax1)
        ax1.view_init(elev=40, azim=-40) # set initial view angle position
        plt.axis('off')  # hide axis

        if save_image:
            save_path = os.path.join(path[:-4] + '-box.png')
            plt.savefig(save_path, transparent=True)
        plt.show()
        plt.close()

thanks a lot

duzhenjiang113 commented 3 years ago

Hope the code below can help you.

def minmax2points(minmax):
    minp = minmax[:3]
    maxp = minmax[3:]
    P = np.asarray([minp,
         [maxp[0], minp[1], minp[2]],
         [maxp[0], minp[1], maxp[2]],
         [minp[0], minp[1], maxp[2]],
         [minp[0], maxp[1], minp[2]],
         [maxp[0], maxp[1], minp[2]],
         maxp,
         [minp[0], maxp[1], maxp[2]],
         ])
    P = P[:, [2, 1, 0]]  # FIXME: switch axis
    return P

def points2verts(Z):
    verts = [[Z[0], Z[1], Z[2], Z[3]],
             [Z[4], Z[5], Z[6], Z[7]],
             [Z[0], Z[1], Z[5], Z[4]],
             [Z[2], Z[3], Z[7], Z[6]],
             [Z[1], Z[2], Z[6], Z[5]],
             [Z[4], Z[7], Z[3], Z[0]]]
    return verts

def draw_parts_bbox(bboxes, ax, limit=64, transparency=0.6):
    """draw AABB of part box assembly with transparent face"""
    from mpl_toolkits.mplot3d.art3d import Poly3DCollection, Line3DCollection
    n_parts = bboxes.shape[0]
    colors = [[255, 105, 180],
              [30, 144, 255],
              [127, 255, 212],
              [255, 215, 0],
              [139, 69, 19],
              [205, 102, 29],
              [255, 231, 186],
              [238, 197, 145],
              [139, 35, 35]]
    colors = np.asarray(colors) / 255
    # points = np.round(points).astype(np.int)
    for idx in range(n_parts):
        bbox = bboxes[idx]
        points = minmax2points(bbox)
        verts = points2verts(points)

        pc = Poly3DCollection(verts, linewidths=0.5, edgecolors='k', alpha=transparency)
        pc.set_facecolor(colors[idx % len(colors)])
        ax.add_collection3d(pc)

        # size = (bbox[3:] - bbox[:3]).tolist()
        # for s, e in combinations(np.array(list(product(bbox[[2, 5]], bbox[[1, 4]], bbox[[0, 3]]))), 2):
        #     if np.sum(np.abs(s - e)) in size:
        #         ax.plot3D(*zip(s, e), color=colors[idx % len(colors)], alpha=transparency)

    ax.set_xlim(0, limit)
    ax.set_ylim(0, limit)
    ax.set_zlim(0, limit)

def vis_box(paths, save_image=False):
    """visualize axis-aligned bounding box(AABB) for part assembly of format 'npy' 
       each npy of shape (K, 6), K the number of parts, 6 the coordinates of min/max points
       (min.x, min.y, min.z, max.x, max.y, max.z)
    """
    import matplotlib.pyplot as plt
    from mpl_toolkits.mplot3d import Axes3D

    for path in paths:
        file_format = path.split('.')[-1]
        if file_format != 'npy':
            print("skip file: {}".format(path))
            continue

        print("vis box: {}".format(path))

        box_minmax = np.load(path)
        fig = plt.figure()
        ax1 = fig.gca(projection='3d')
        draw_parts_bbox(box_minmax, ax1)
        ax1.view_init(elev=40, azim=-40) # set initial view angle position
        plt.axis('off')  # hide axis

        if save_image:
            save_path = os.path.join(path[:-4] + '-box.png')
            plt.savefig(save_path, transparent=True)
        plt.show()
        plt.close()

By the way, the .npy you are using is the translation vector and size vector extracted from the h5 file?

ChrisWu1997 commented 3 years ago

Not exactly. This is a general scripts to draw boxes. The loaded .npy should provide the minimum and maximum points of the bounding box for each part, so additional code to transform (translation + size) to (min point, max point) is needed.

duzhenjiang113 commented 3 years ago

Not exactly. This is a general scripts to draw boxes. The loaded .npy should provide the minimum and maximum points of the bounding box for each part, so additional code to transform (translation + size) to (min point, max point) is needed.

ok, thanks