{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Load Pickle Models\nThis notebook is about how to load a car from pickle file and display it in 3D\n\nBecause the model file doesn't contain any color information, there's no obvious difference between pickle file and json file \n\n<b>So I think it's better to load a model from json!!!</b>\n"},{"metadata":{},"cell_type":"markdown","source":"## References\n<b>This is the first time I start kaggle, so if there are referencing mistakes, please let me know!!</b>\n\nThe obloader module is from github https://github.com/changhongjian/pygame-show-obj/blob/master/chj/ogl/objloader.py\n\nThe display scripts https://www.kaggle.com/ebouteillon/load-a-3d-car-model this is a notebook teach you how to load car models from json"},{"metadata":{},"cell_type":"markdown","source":"# lets begin\nLoad pygame module, to download this module, allow comstom packages and toggle on internet "},{"metadata":{"trusted":true},"cell_type":"code","source":"pip install pygame","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nimport pygame\nimport OpenGL\nimport os\nimport pickle\nfrom pygame.locals import *\nfrom OpenGL.GL import *\nfrom OpenGL.GLU import *\nfrom OpenGL.GLUT import *\nfrom OpenGL.GLUT.freeglut import *","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Define objloader module, this module comes from github link which listed in the reference part"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"%%writefile objloader.py\n\n# https://github.com/changhongjian/pygame-show-obj/blob/master/chj/ogl/objloader.py\n\n\n'''\nthe original is here https://www.pygame.org/wiki/OBJFileLoader\n@2018-1-2 author chj\nchange for easy use\n'''\n\nfrom OpenGL.GL import *\nfrom OpenGL.GL import shaders\nfrom OpenGL.GLU import *\n\n\nimport numpy as np\nimport pygame\nimport OpenGL\n\n'''\nthe original is here https://www.pygame.org/wiki/OBJFileLoader\n@2018-1-2 author chj\nchange for easy use\n'''\n\n\ndef MTL(fdir, filename):\n    contents = {}\n    mtl = None\n    for line in open(fdir + filename, \"r\"):\n        if line.startswith('#'):\n            continue\n        values = line.split()\n        if not values:\n            continue\n        if values[0] == 'newmtl':\n            mtl = contents[values[1]] = {}\n        elif mtl is None:\n            raise ValueError(\"mtl file doesn't start with newmtl stmt\")\n        elif values[0] == 'map_Kd':\n            # load the texture referred to by this declaration\n            mtl[values[0]] = values[1]\n            surf = pygame.image.load(fdir + mtl['map_Kd'])\n            image = pygame.image.tostring(surf, 'RGBA', 1)\n            ix, iy = surf.get_rect().size\n            texid = mtl['texture_Kd'] = glGenTextures(1)\n            glBindTexture(GL_TEXTURE_2D, texid)\n            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,\n                            GL_LINEAR)\n            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,\n                            GL_LINEAR)\n            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ix, iy, 0, GL_RGBA,\n                         GL_UNSIGNED_BYTE, image)\n        else:\n            #mtl[values[0]] = map(float, values[1:])\n\n            mtl[values[0]] = [float(x) for x in values[1:4]]\n    return contents\n\n\nclass OBJ:\n    def __init__(self, fdir, filename, swapyz=False):\n        \"\"\"Loads a Wavefront OBJ file. \"\"\"\n        self.vertices = []\n        self.normals = []\n        self.texcoords = []\n        self.faces = []\n\n        self.mtl = None\n\n        material = None\n        for line in open(fdir + filename, \"r\"):\n            if line.startswith('#'):\n                continue\n            values = line.split()\n            if not values:\n                continue\n            if values[0] == 'v':\n                #v = map(float, values[1:4])\n                v = [float(x) for x in values[1:4]]\n                if swapyz:\n                    v = v[0], v[2], v[1]\n                self.vertices.append(v)\n            elif values[0] == 'vn':\n                #v = map(float, values[1:4])\n                v = [float(x) for x in values[1:4]]\n                if swapyz:\n                    v = v[0], v[2], v[1]\n                self.normals.append(v)\n            elif values[0] == 'vt':\n                v = [float(x) for x in values[1:3]]\n\n                self.texcoords.append(v)\n            elif values[0] in ('usemtl', 'usemat'):\n                material = values[1]\n            elif values[0] == 'mtllib':\n                # print(values[1])\n                #self.mtl = MTL(fdir,values[1])\n                self.mtl = [fdir, values[1]]\n            elif values[0] == 'f':\n                face = []\n                texcoords = []\n                norms = []\n                for v in values[1:]:\n                    w = v.split('/')\n                    face.append(int(w[0]))\n                    if len(w) >= 2 and len(w[1]) > 0:\n                        texcoords.append(int(w[1]))\n                    else:\n                        texcoords.append(0)\n                    if len(w) >= 3 and len(w[2]) > 0:\n                        norms.append(int(w[2]))\n                    else:\n                        norms.append(0)\n                self.faces.append((face, norms, texcoords, material))\n\n    def create_bbox(self):\n        # self.vertices is not None\n        ps = np.array(self.vertices)\n        vmin = ps.min(axis=0)\n        vmax = ps.max(axis=0)\n\n        self.bbox_center = (vmax + vmin) / 2\n        self.bbox_half_r = np.max(vmax - vmin) / 2\n\n    def create_gl_list(self):\n        if self.mtl is not None:\n            print(self.mtl, \"---\")\n            self.mtl = MTL(*self.mtl)\n\n        self.gl_list = glGenLists(1)\n        glNewList(self.gl_list, GL_COMPILE)\n        glEnable(GL_TEXTURE_2D)\n        glFrontFace(GL_CCW)\n        # glCullFace(GL_BACK)\n        # glEnable(GL_CULL_FACE)\n\n        for face in self.faces:\n            vertices, normals, texture_coords, material = face\n\n            mtl = self.mtl[material]\n            if 'texture_Kd' in mtl:\n                # use diffuse texmap\n                glBindTexture(GL_TEXTURE_2D, mtl['texture_Kd'])\n            else:\n                # just use diffuse colour\n                # print(mtl['Kd'],\"----\")\n                glColor(*mtl['Kd'])\n\n            glBegin(GL_POLYGON)\n            for i in range(len(vertices)):\n                if normals[i] > 0:\n                    glNormal3fv(self.normals[normals[i] - 1])\n                if texture_coords[i] > 0:\n                    glTexCoord2fv(self.texcoords[texture_coords[i] - 1])\n                glVertex3fv(self.vertices[vertices[i] - 1])\n            glEnd()\n        glDisable(GL_TEXTURE_2D)\n        glEndList()\n\n\n'''\n@2018-3-13\n主要处理\nv x y z r g b\nf a b c\n'''\n\n\nclass CHJ_tiny_obj:\n    def __init__(self, fdir, filename, swapyz=False):\n        if filename is None:\n            return\n        \"\"\"Loads a Wavefront OBJ file. \"\"\"\n        self.vertices = []\n        self.normals = []\n        self.texcoords = []\n        self.faces = []\n        self.v_colors = {}\n\n        self.mtl = None\n\n        fname = fdir + filename\n        for line in open(fname, \"r\"):\n            if line.startswith('#'):\n                continue\n            values = line.split()\n            if not values:\n                continue\n            if values[0] == 'v':\n                # v = map(float, values[1:4])\n                v = [float(x) for x in values[1:4]]\n                if swapyz:\n                    v = [v[0], v[2], v[1]]\n                self.vertices.append(v)\n                if len(values) == 7:\n                    c = [float(x) for x in values[4:7]]\n                    # self.v_colors.append(c)\n                    self.v_colors[len(self.vertices) - 1] = c\n            elif values[0] == 'vn':\n                # v = list(map(float, values[1:4]))\n                v = [float(x) for x in values[1:4]]\n                if swapyz:\n                    v = [v[0], v[2], v[1]]\n                self.normals.append(v)\n            elif values[0] == 'vt':\n                v = [float(x) for x in values[1:3]]\n            elif values[0] == 'f':\n                v = [int(x) for x in values[1:4]]\n                self.faces.append(v)\n\n    def set_V_T_F(self, v, t, f):\n        self.vertices = v\n        self.v_colors = t\n        self.faces = f\n\n    def create_bbox(self):\n        # self.vertices is not None\n        ps = np.array(self.vertices)\n        vmin = ps.min(axis=0)\n        vmax = ps.max(axis=0)\n\n        self.bbox_center = (vmax + vmin) / 2\n        self.bbox_half_r = np.max(vmax - vmin) / 2\n\n    def create_gl_list(self):\n        self.gl_list = glGenLists(1)\n        glNewList(self.gl_list, GL_COMPILE)\n        glFrontFace(GL_CCW)\n        # glCullFace(GL_BACK)\n        # glEnable(GL_CULL_FACE)\n        # print(self.faces)\n        # print(self.v_colors)\n\n        for face in self.faces:\n            # print(face)\n            glBegin(GL_TRIANGLES)\n            # glBegin(GL_POLYGON)\n            for vid in face:\n                vid -= 1\n                # if self.v_colors[vid] is not None:\n                #     glColor3f(*self.v_colors[vid])\n                glVertex3fv(self.vertices[vid])  # 看好后面加了个v，只用传地址就行了\n            glEnd()\n\n        glEndList()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"from objloader import CHJ_tiny_obj","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Locally you can use pygame and OpenGL to display car models from pickle files, use light.py and 1.test_obj.py from [github link](https://github.com/changhongjian/pygame-show-obj) The author already shows how to run his objloader(CHJ_tiny_obj)\n\nFor kernel, pygame can't work well, but the data is same as json.\n\nSo, I directly used the script \"[Load a 3D car model](https://www.kaggle.com/ebouteillon/load-a-3d-car-model)\" kindly offered us. I have listed the link to this notebook in reference part."},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nimport pickle\nimport matplotlib.pyplot as plt\nfrom mpl_toolkits.mplot3d import Axes3D\n\ndef Test_Car_Models():\n    print(\"testing car models\")\n    target_path = \"../input/pku-autonomous-driving/car_models\"\n    data = []\n    # print(len(os.listdir(path=target_path)))\n    # for filename in os.listdir(target_path):\n    file_name = os.path.join(target_path, \"benchi-ML500.pkl\")\n    print(f\"file dir is {file_name}\")\n\n    with open(file_name, \"rb\") as f:\n        data = pickle.load(f)\n        vertices = np.array(data.vertices)/-100\n        for vertics in vertices:\n            vertics[2]*=-1\n        triangles = np.array(data.faces)-1\n        # print(f\"vertices are :{vertices}\")\n        # print(f\"triangles are : {triangles}\")\n        plt.figure(figsize=(20,10))    \n        ax = plt.axes(projection='3d')\n        ax.set_title('car_type: SUV')\n        ax.set_xlim([-3, 3])\n        ax.set_ylim([-3, 3])\n        ax.set_zlim([0, 3])\n        ax.plot_trisurf(vertices[:,0], vertices[:,2], triangles, -vertices[:,1], shade=True, color='grey')\n\n\nTest_Car_Models()\n\n","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":1}