# Select vertex if vertex color is dark

I've baked AO to vertex colors and would like to use the smooth modifier only on vertices that have a vertex color darker than 0.1 (for example).

How can I select vertices whose colors are below that threshold? I'd then create a vertex group from that and use it in the modifier.

I know you can access the vertex colors with bpy.context.object.data.vertex_colors.active.data[0].color.

• It's possible that 1 vertex has at 2 or more (4..5..6) different colors associated with it (for each of the corners of the surrounding faces). – zeffii Aug 6 '13 at 14:40
• If your script is only going to check greyscale, you can just check the value of the red: if bpy.context.object.data.vertex_colors.active.data[0].color[1] < .1: – CharlesL Aug 6 '13 at 14:49
• There are currently two questions here, "how to convert Vertex Colors to Groups" and "how to subtract values below a value from a Vertex Group". While they can be done in one step in a script, I think they should still be asked separately. – Aldrik Aug 6 '13 at 15:52
• I think it's still valid as a single question: how to parametrically assign a vertex to a vertex group, in this case the parameter is the vertex's own color. – Adhi Aug 6 '13 at 16:10
• I'm inclined to agree with Aldrik, that perhaps unbeknownst to GregZaal this question requires somewhat elaborate answers. 1) getting the colors attached to a vertex (do you select weighted average or mean?) then 2) selecting verts based on some critera (trivial) 3) the smooth modifier portion / vertex group portion. Essentially making a complete answer very long. Rather split your questions into atomic/modular parts, so that others may benefit from the individual sections of these answers. – zeffii Aug 7 '13 at 8:41

This will give you a dictionary of colors attached to each vertex:

in the form {vertex_index : [ color(s) ] ,... } .

import bpy

mesh = bpy.context.active_object.data
color_layer = mesh.vertex_colors['Col']

tk = {}
i = 0
for poly in mesh.polygons:
for idx in poly.loop_indices:
loop = mesh.loops[idx]
v = loop.vertex_index
i += 1

print(tk)


There are nicer ways to write this, using collections.defaultdict. In this example I also import pprint to nicely display the vertex<-->colors dict (tk).

import bpy
from collections import defaultdict

tk = defaultdict(list)

mesh = bpy.context.active_object.data
color_layer = mesh.vertex_colors['Col']

i = 0
for poly in mesh.polygons:
for idx in poly.loop_indices:
loop = mesh.loops[idx]
color = color_layer.data[i].color
tk[loop.vertex_index].append(color)
i += 1

# you must cast this as a dict manually like  tk = dict(tk) ,
# if you need it as a dict, but defaultdict will behave mostly the same
import pprint
pprint.pprint(tk)


This will get you as far as being able to average the colors. The output for this Col (for sake of simplicity i use a 9 vertex planar surface)

is

{0: [Color((0.800000011920929, 0.4313725531101227, 0.04313725605607033))],
1: [Color((0.11372549086809158, 0.800000011920929, 0.0))],
2: [Color((0.27450981736183167, 0.27843138575553894, 0.27843138575553894))],
3: [Color((0.7882353067398071, 0.7921568751335144, 0.800000011920929))],
4: [Color((0.800000011920929, 0.4313725531101227, 0.04313725605607033)),
Color((0.27450981736183167, 0.27843138575553894, 0.27843138575553894))],
5: [Color((0.11372549086809158, 0.800000011920929, 0.0)),
Color((0.7882353067398071, 0.7921568751335144, 0.800000011920929))],
6: [Color((0.7882353067398071, 0.7921568751335144, 0.800000011920929)),
Color((0.27450981736183167, 0.27843138575553894, 0.27843138575553894))],
7: [Color((0.800000011920929, 0.4313725531101227, 0.04313725605607033)),
Color((0.11372549086809158, 0.800000011920929, 0.0))],
8: [Color((0.800000011920929, 0.4313725531101227, 0.04313725605607033)),
Color((0.11372549086809158, 0.800000011920929, 0.0)),
Color((0.7882353067398071, 0.7921568751335144, 0.800000011920929)),
Color((0.27450981736183167, 0.27843138575553894, 0.27843138575553894))]}


To complete this, here's an example of how to average a list of colors (naturally, for greyscale colors you only have to concentrate on 1 component as R,G and B should all be the same.

import pprint
from mathutils import Color

cols = tk[8]   # unadulterated color list for that vertex
pprint.pprint(cols)

def avg_col(cols):
avg_col = Color((0.0, 0.0, 0.0))
for col in cols:
avg_col += col/len(cols)
return avg_col

print('average')
col = avg_col(cols)
print(col)


Now using the defaultdict that represents the vertices and their occurrence in vertex_colors you can average them, or do whatever calculations and create a new dict with a dict comprehension.

import pprint
import bpy

vcol_averages = {k: avg_col(v) for k, v in tk.items()}
pprint.pprint(vcol_averages)

''' outputs, nicely the averages.
{0: Color((0.800000011920929, 0.4313725531101227, 0.04313725605607033)),
1: Color((0.11372549086809158, 0.800000011920929, 0.0)),
2: Color((0.27450981736183167, 0.27843138575553894, 0.27843138575553894)),
3: Color((0.7882353067398071, 0.7921568751335144, 0.800000011920929)),
4: Color((0.5372549295425415, 0.3549019694328308, 0.16078431904315948)),
5: Color((0.45098039507865906, 0.7960784435272217, 0.4000000059604645)),
6: Color((0.5313725471496582, 0.5352941155433655, 0.5392156839370728)),
7: Color((0.45686274766921997, 0.615686297416687, 0.021568628028035164)),
8: Color((0.4941176474094391, 0.5754902362823486, 0.2803921699523926))}
'''


From this you might create a list of vertex indices following a threshold test.

vertices_of_interest = [k for k, v in vcol_averages.items() if v.r < 0.5]

pprint.pprint(vertices_of_interest)
# [1, 2, 5, 7, 8]


Selecting vertices, is easy once you get to this point.

Once you have your weight group there are a couple of ways to modify it:

1. You can use the group remove setting of the Vertex Weight Edit Modifier.

Group Remove

Removes vertices with a final weight below Rem Threshold from the vertex group.

2. Alternatively you could use the Weights | Clean operator: bpy.ops.object.vertex_group_clean.