1
$\begingroup$

I'm aware there are numerous posts/questions already been raised on this, but upon reading the previous posts, I'm not quite able to find exactly what I'm looking for. So apologies if there's a duplicate post that already answered this. Basically, I have a CSV file with 3 columns = x coordinate, y coordinate and pixel value (based on 255 greyscale). All I want to do is import this CSV file in Blender and plot the points as vertices, using python script. That's it. So if there are 3 points in the CSV file, I want those 3 points created/plotted in their respective xy coordinates as vertices in Blender. I've seen examples of python scripts for adding mesh objects. But I simply want to plot the points given the xy coordinates in the CSV file, as vertices. Not add existing 3D objects/meshes.

This is the code I have so far:

import bpy
import csv

with open(r'file path\img_pixel_coor.csv') as csvfile:
    csvread = csv.reader(csvfile)
    for i, row in enumerate (csvread):
        print("i = "+str(i)+". row = "+str(row))

This prints:

i = 0. row = ['494', '216', '86']
i = 1. row = ['494', '217', '86']
i = 2. row = ['494', '218', '86']
i = 3. row = ['494', '219', '85']
i = 4. row = ['494', '220', '84']
i = 5. row = ['494', '221', '87']
i = 6. row = ['494', '222', '87']
i = 7. row = ['494', '223', '88']
i = 8. row = ['494', '224', '92']

The print is just to show what's in the file (logging purposes).

Also, would it be possible to put this script in a python file, and run it from a python file, without having to manually open Blender, i.e. can you control externally from a python file, to open Blender and run the script, without having to actually open Blender software manually yourself?

Any help would be greatly appreciated.

Update:

Here's a sample of how the CSV file looks like in the first few rows, to demonstrate how the x, y and pixel values are structured:

enter image description here

Finally, how do I smooth the vertices more. As you can see from the image below, the surface of the mesh is very spikey. I used the code below, but it's still very rough/spikey surface.

for p in ob.data.polygons: #Set smooth shading (if needed)
    p.use_smooth = True

enter image description here

Many thanks in advance for any help.

Illustration (my understanding):

of the code:

# Vertices store the color values as Z
vertices = [Vector( (x, y, int(z_max * random.random())) ) for x, y in product( range(x_size), range(y_size) )]

# Get base face indices
face_basis = ((x * y_size) + y for (x, y) in product( range(x_size-1), range(y_size-1) ))

# Each face is a square for the base index turning around counterclockwise
faces = [(v, v + 1, v + y_size + 1, v + y_size) for v in face_basis]

enter image description here

$\endgroup$
6
  • 1
    $\begingroup$ See here blender.stackexchange.com/questions/76535/… $\endgroup$
    – lemon
    Commented Sep 10, 2019 at 6:03
  • $\begingroup$ Thank you for your response and referring your answer. Really appreciated. I have a question. In the code, I think it treats the 3rd column of the csv file, i.e. float(r[2]) as the z coordinates. However, the 3rd column, in the csv file, is in fact the greyscale pixel value (I think it's also referred to as the brightness intensity value) 0-255. So is there a way to plot this in Blender as such, rather than as the z coordinate? $\endgroup$
    – Hazzaldo
    Commented Sep 10, 2019 at 18:33
  • $\begingroup$ Vertex colors in Blender are stored as face loop. That means you can not assign a vertex color if there is no face (nearly the same for materials). So here you'll need some rules to make it colored. Is for instance (x,y) map a regular grid? $\endgroup$
    – lemon
    Commented Sep 11, 2019 at 6:36
  • $\begingroup$ Apologies, I'm a bit junior in Blender. I'm not sure if I understood your question correctly. I'll try to answer based on how I interpreted it. I'll show you a sample of how the csv file starts in the first few rows, so you can see if x,y map to a regular grid. Basically when plotting the data from the csv it forms into a rectangular frame. But the content on the inside of that rectangular frame I base it on the third column pixel value. Actually, looking at it, I'm happy to go along with plotting the third column pixel value as the z coor, as it provides the depth. However ... $\endgroup$
    – Hazzaldo
    Commented Sep 11, 2019 at 20:11
  • $\begingroup$ I'm still wondering how to use the same third column (representing 0-255) to use its values as the material colours? I've update my question above to show how the first rows of the CSV look like in terms of x, y and pixel values. Hope this helps in answering your question. $\endgroup$
    – Hazzaldo
    Commented Sep 11, 2019 at 20:14

1 Answer 1

2
$\begingroup$

I suppose the input data is a 2D grid with known max values.

Here, we start with a random input but seeing your question you know how to load data from a file.

The script below does the following:

  • Create random inputs (you'll use file data instead)
  • Create vertices and store the color value as Z coordinate
  • Create the face vertex indices
  • Make a mesh object from that
  • Scale the object along Z
  • Create a vertex colors layer
  • Assign the Z value of the vertices as vertex color
  • Link a prepared material to the object

That gives the following result:

enter image description here

import bpy
import bmesh
from mathutils import Vector, Matrix
from itertools import product
import random

# Generate a random grid of the given file
x_size = 20
y_size = 30
z_max = 256

# Vertices store the color values as Z
vertices = [Vector( (x, y, int(z_max * random.random())) ) for x, y in product( range(x_size), range(y_size) )]

# Get base face indices
face_basis = ((x * y_size) + y for (x, y) in product( range(x_size-1), range(y_size-1) ))

# Each face is a square for the base index turning around counterclockwise
faces = [(v, v + 1, v + y_size + 1, v + y_size) for v in face_basis]

# Create resulting object
name = "grid"
mesh = bpy.data.meshes.new( name ) 
obj = bpy.data.objects.new( name, mesh )

obj.data.from_pydata( vertices, [], faces ) 

# Scale it along Z
scale = 1.0 / z_max # Or set 0.0 here
obj.matrix_world = Matrix.Scale( scale, 4, (0, 0, 1) ) @ obj.matrix_world

# Smooth faces
for face in obj.data.polygons: 
    face.use_smooth = True

# Get or create vertex colors data of the given name
vcol_name = "VCol"
vcol = obj.data.vertex_colors.get( vcol_name )
if not vcol:
    vcol = obj.data.vertex_colors.new( name = vcol_name )

# Assigns z values as vertex colors
for face in obj.data.polygons:
    for vertex_index, loop_index in zip( face.vertices, face.loop_indices ):
        intensity = obj.data.vertices[vertex_index].co.z / z_max
        vcol.data[loop_index].color = (intensity, intensity, intensity, 1)

# Get the prepared material
material_name = "Material"
material = bpy.data.materials.get( material_name )

# If found assign it to the object
if material:
    obj.data.materials.append( material )

# Link the object to the scene
bpy.context.scene.collection.objects.link( obj )

The material is the following:

It uses the created vertex color as input for a color ramp and use this color for shading:

enter image description here

As your question was about plotting vertices, you may want to rework the mesh manually or modify the script to have this kind of results:

enter image description here

Note:

An illustration for

# Vertices store the color values as Z
vertices = [Vector( (x, y, int(z_max * random.random())) ) for x, y in product( range(x_size), range(y_size) )]

# Get base face indices
face_basis = ((x * y_size) + y for (x, y) in product( range(x_size-1), range(y_size-1) ))

enter image description here

$\endgroup$
1
  • $\begingroup$ Comments are not for extended discussion; this conversation has been moved to chat. $\endgroup$ Commented Sep 15, 2019 at 22:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .