Building a 3d Mesh using python and blender
The Blender application is a leading free tool for 3D modeling for various applications. The 3d models can be saved in a specific format for later use in various developments for example, in game development.
The application's start window is shown below. It contains 3 initial objects, each of which has specified properties: size, color, coordinates, etc. These objects can also be built using a Python script, specifying all the necessary parameters for each object. Let's take a closer look at this.
To work with Blender via the Python programming language, you need to use the bpy library. The first step to creating a new object using bpy is to import the bpy module. To do this, click on the Scripting tab, then New and add the next code line:
- import bpy
This will give you access to the Blender workspace through code, the ability to manipulate current objects and create new ones. This library contains many methods for creating standard shapes, but to build a complex object using coordinates, you need to create a Mesh object. To do this, use the method bpy.data.meshes.new(<Mesh name>). Then create a new object which contains this mesh - bpy.data.objects.new(<Object name>, mesh)
Next, to build a Mesh figure using the available coordinates, you need to use the method mesh.from_pydata(verts, edges, faces), where verts, edges and faces are arrays of coordinates of the vertices, edges and surfaces of the figure, respectively.
First parameter - verts - is used to get all points which are included in the mesh. For example, it can be populated with these values:
- verts = [ (0,0,0), (0,2,0), (0,1,2), (0,3,2) ]
The other two parameters are needed to connect the points with lines or planes, depending on what should be in the figure. For example, if you fill the faces parameter with these values, it will build 2 flat triangles connecting points numbered 1, 2, and 3, as well as 2, 3, and 4 (according to the index numbers of the verts array):
- faces = [ (0,1,2), (1,3,2) ]
This is enough to build a parallelogram shape using coordinates, but you can add lines connecting the selected points so that you can then edit them manually as object elements.
- edges = [ (0,1), (1,2), (2,0), (1,3), (3, 2) ]
Full code fragment is provided below:
And the result looks like this:
This example shows how to build a flat parallelogram figure using fixed coordinates of points. The same code is suitable for building more complex objects of any shape in 3D space, you just need to set the coordinates of the points and connect them. In our example, I will change the coordinates to turn the 2D shape into 3D.
This script builds a 3D figure consisting of 8 points and 6 faces, and each face is a quadrilateral. The final 3D figure looks like this
In the same way, you can build more complex 3D objects. To do this, it is enough to know the coordinates of the points and the order in which they are connected to build flat faces. Each face can be edited using Blender's manual tools if necessary. However, it is worth remembering that a large number of figure elements requires a lot of memory. Therefore, it is advisable to use an algorithm to reduce the array of coordinates used to obtain the desired object.
If you need to save a 3D object in a file, you can do it manually or use a method of bpy library. It contains many parameters, but only one required:
- bpy.ops.wm.obj_export(filepath="<path to target file with .obj format>")
Below there is an example of creating a 3D object obtained from a png image. In addition to bpy, this will require the bmesh, cv2, mathutils and numpy libraries.
As example, we’ll use this image of human with green background
The first step is to get a list of coordinates of all points of the contour of the object on a green background. This will require the cv2 library. As a result, a list of coordinates of human contour points will be obtained. This list will be used later when building a mesh.
The second step is to build a mesh from the points coordinates. The result should be a human outline like this.
The following code is used to get this result
Now it is necessary to obtain a closed image of a person by adding a face to the resulting contour. Use the method:
The result now looks like this:
To complete the construction of a 3D object, it is necessary to extrude a plane with the selected thickness value. Use the method bpy.ops.mesh.extrude_region_move:
As the result, you’ll get something like this:
The full code will be provided below.
Prerequisites for code execution:
- Need to install library cv2 which may not be pre-installed in Blender. You can try to use this code in Blender:
import pip
pip.main(['install', 'cv2'])
- If the installation is not successful, you will need to install the module from Terminal and add it to the Blender application. To install the cv2 module, open your Terminal in VS Code, where you execute Python scripts. Execute this command
pip install opencv-python
Then you need to open your path which contains all python libraries. For example, my path looks like this: C:\Users\jbUser\AppData\Local\Programs\Python\Python312\Lib\site-packages and it should include 2 folders named cv2 and opencv_python-4.9.0.80.dist-info. Copy these folders to the folder which contains all installed python libraries of your Blender app. In my case, it’s: C:\Program Files\Blender Foundation\Blender 4.2\4.2\python\lib\site-packages
After that, libraries should work in Blender scripts. If it shows an error, may need to use other version of python or its libraries.
Script for Blender is provided here:
import bpy
import bmesh
import mathutils
import numpy as np
import cv2
def remove_green_background(image_path):
image = cv2.imread(image_path)
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
lower_green = np.array([40 - 30, 40, 40])
upper_green = np.array([40 + 30, 255, 255])
mask = cv2.inRange(hsv, lower_green, upper_green)
mask_inv = cv2.bitwise_not(mask)
result = cv2.bitwise_and(image, image, mask=mask_inv)
contours, _ = cv2.findContours(mask_inv, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if contours:
largest_contour = max(contours, key=cv2.contourArea)
contour_coords = largest_contour.reshape(-1, 2).tolist()
return contour_coords
else:
return None
def build_from_contour(points, export_path, HEIGHT, SCALE):
mesh = bpy.data.meshes.new("HumanMesh")
obj = bpy.data.objects.new("HumanObj", mesh)
bpy.context.collection.objects.link(obj)
bm = bmesh.new()
verts = [bm.verts.new((x, y, 0)) for x, y in points]
center = mathutils.Vector((0, 0, 0))
for v in verts:
center += v.co
center /= -len(verts) * SCALE
if len(verts) > 2:
for i in range(len(verts)):
bm.edges.new((verts[i], verts[(i + 1) % len(verts)]))
bm.to_mesh(mesh)
bm.free()
bpy.context.view_layer.objects.active = obj
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.edge_face_add()
bpy.ops.mesh.extrude_region_move(MESH_OT_extrude_region={"use_normal_flip":False,
"use_dissolve_ortho_edges":False,
"mirror":False},
TRANSFORM_OT_translate={"value":(0, 0, -HEIGHT),
"orient_type":'NORMAL',
"orient_matrix":((-1, 0, 0), (0, -1, 0), (0, 0, 1)),
"orient_matrix_type":'NORMAL',
"constraint_axis":(False, False, True),
"mirror":False,
"use_proportional_edit":False,
"proportional_edit_falloff":'SMOOTH',
"proportional_size":1,
"use_proportional_connected":False,
"use_proportional_projected":False,
"snap":False,
"snap_elements":{'INCREMENT'},
"use_snap_project":False,
"snap_target":'CLOSEST',
"use_snap_self":True,
"use_snap_edit":True,
"use_snap_nonedit":True,
"use_snap_selectable":False,
"snap_point":(0, 0, 0),
"snap_align":False,
"snap_normal":(0, 0, 0),
"gpencil_strokes":False,
"cursor_transform":False,
"texture_space":False,
"remove_on_cancel":False,
"use_duplicated_keyframes":False,
"view2d_edge_pan":False,
"release_confirm":False,
"use_accurate":False,
"use_automerge_and_split":False})
bpy.ops.object.mode_set(mode='OBJECT')
obj.location = center
obj.scale /= SCALE
bpy.ops.wm.obj_export(filepath = export_path)
# Change path to your image with green background
IMAGE_PATH = 'C:\Work\Projects\PythonScripts\VideoFrames\Frames\Green_Human.avi\\0000000000.png'
#Change path to your target path to save .obj file
EXPORT_PATH = 'C:\Work\Projects\PythonScripts\VideoFrames\Frames\Human.obj'
HEIGHT = 50
SCALE = 10
points = remove_green_background(IMAGE_PATH)
if points != None:
build_from_contour(points, EXPORT_PATH, HEIGHT, SCALE)
In this example, the background color is green because it is brighter than the colors of the subject. For better quality, avoid wearing green clothing when photographing the subject.
This approach allows you to build a 3D object using only the image contour points in order to optimize the load of the Blender application. The script greatly simplifies the process of building an object, replacing manual actions with tools for transforming the shape of objects.

