简体   繁体   中英

python (pygame and pyopenGL) Convert 3D models (. obj file) into a sequence of gray image

Currently I'm working on object recognition systems, which need a whole lot of training data.

I am trying to convert a 3D model into a sequence of gray images, rotating the model and sampling the 2D image with a certain time interval.

Because I am mainly working on python, so I try to solve this problem based on pygame and pyopenGL, I found this example for loading an .obj file, but it won't work at the very beginning, which took me quite long time to figure out where is the problem.

And now the core problem somehow reduce to as follow:

class Point3D:

def __init__(self, x = 0, y = 0, z = 0):
    self.x, self.y, self.z = float(x), float(y), float(z)

def rotateX(self, angle):
    """ Rotates the point around the X axis by the given angle in degrees. """
    rad = angle * math.pi / 180
    cosa = math.cos(rad)
    sina = math.sin(rad)
    y = self.y * cosa - self.z * sina
    z = self.y * sina + self.z * cosa
    return Point3D(self.x, y, z)

def rotateY(self, angle):
    """ Rotates the point around the Y axis by the given angle in degrees. """
    rad = angle * math.pi / 180
    cosa = math.cos(rad)
    sina = math.sin(rad)
    z = self.z * cosa - self.x * sina
    x = self.z * sina + self.x * cosa
    return Point3D(x, self.y, z)

def rotateZ(self, angle):
    """ Rotates the point around the Z axis by the given angle in degrees. """
    rad = angle * math.pi / 180
    cosa = math.cos(rad)
    sina = math.sin(rad)
    x = self.x * cosa - self.y * sina
    y = self.x * sina + self.y * cosa
    return Point3D(x, y, self.z)

def project(self, win_width, win_height, fov, viewer_distance):
    """ Transforms this 3D point to 2D using a perspective projection. """
    factor = fov / (viewer_distance + self.z)
    x = self.x * factor + win_width / 2
    y = -self.y * factor + win_height / 2
    return Point3D(x, y, self.z)

class Simulation:

    def __init__(self, win_width = 640, win_height = 480):
    pygame.init()

    self.screen = pygame.display.set_mode((win_width, win_height))
    pygame.display.set_caption("Simulation of a rotating 3D Cube (http://codeNtronix.com)")

    self.clock = pygame.time.Clock()

    self.vertices = [
        Point3D(-1,1,-1),
        Point3D(1,1,-1),
        Point3D(1,-1,-1),
        Point3D(-1,-1,-1),
        Point3D(-1,1,1),
        Point3D(1,1,1),
        Point3D(1,-1,1),
        Point3D(-1,-1,1)
    ]

    # Define the vertices that compose each of the 6 faces. These numbers are
    # indices to the vertices list defined above.
    self.faces  = [(0,1,2,3),(1,5,6,2),(5,4,7,6),(4,0,3,7),(0,4,5,1),(3,2,6,7)]

    # Define colors for each face
    self.colors = [(255,0,255),(255,0,0),(0,255,0),(0,0,255),(0,255,255),(255,255,0)]

    self.angle = 0

def run(self):
    """ Main Loop """
    while 1:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

        self.clock.tick(50)
        self.screen.fill((0,32,0))

        # It will hold transformed vertices.
        t = []

        for v in self.vertices:
            # Rotate the point around X axis, then around Y axis, and finally around Z axis.
            r = v.rotateX(self.angle).rotateY(self.angle).rotateZ(self.angle)
            # Transform the point from 3D to 2D
            p = r.project(self.screen.get_width(), self.screen.get_height(), 256, 4)
            # Put the point in the list of transformed vertices
            t.append(p)

        # Calculate the average Z values of each face.
        avg_z = []
        i = 0
        for f in self.faces:
            z = (t[f[0]].z + t[f[1]].z + t[f[2]].z + t[f[3]].z) / 4.0
            avg_z.append([i,z])
            i = i + 1

        # Draw the faces using the Painter's algorithm:
        # Distant faces are drawn before the closer ones.
        for tmp in sorted(avg_z,key=itemgetter(1),reverse=True):
            face_index = tmp[0]
            f = self.faces[face_index]
            pointlist = [(t[f[0]].x, t[f[0]].y), (t[f[1]].x, t[f[1]].y),
                         (t[f[1]].x, t[f[1]].y), (t[f[2]].x, t[f[2]].y),
                         (t[f[2]].x, t[f[2]].y), (t[f[3]].x, t[f[3]].y),
                         (t[f[3]].x, t[f[3]].y), (t[f[0]].x, t[f[0]].y)]
            pygame.draw.polygon(self.screen,self.colors[face_index],pointlist)


        self.angle += 1

        pygame.display.flip()

if name == " main ": Simulation().run()

The example above draws a cube and keep rotating it, then how can I get the pixel data directly? What library or package can provide me the ability of getting the pixel data of the 2D project directly. (IPL ? or pyopenGL ?)

THX

You could take a 'screenshot' using glreadpixels. You can then pass it to the python image library which saves it as a file to disk: https://stackoverflow.com/a/4122290/2422450

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM