bl_info = {
"name" : "Composite Scene into Matte",
"description": "An operator that configures the compositor to substitute the 3D scene into a chroma-keyed subset of the matte image chosen by the operator",
"author" : "Robert Forsman <blender@thoth.purplefrog.com>",
"version": (0,1),
"blender": (2,74,0),
#"location": "????",
"warning": "",
#"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/???",
"category": "Node",
}
import bpy
from math import *
def get_image(path):
matches = [ img for img in bpy.data.images if img.filepath==path]
if len(matches)>0:
return matches[0]
rval = bpy.data.images.load(path)
return rval
def matches( c1, c2, epsilon = 0.02):
for i in range(len(c1)):
if i<len(c2):
b = c2[i]
else:
b=1
if epsilon < abs(c1[i]- b):
return False
return True
def find_green_rectangle(img, chroma_key):
# hold down the left mouse button in the UV/Image editor window to get the values for chroma_key
width = img.size[0]
#print (img.pixels[:4])
pix = img.pixels[:]
min_x = None
max_x = None
min_y = None
max_y = None
for i in range(0,len(pix), 4):
one_pixel = pix[i:(i + 4)]
if matches(one_pixel, chroma_key):
x = floor(i/4)% width
y = floor(i/4/ width)
if min_x is None or x<min_x:
min_x = x
print([ i,x,y , one_pixel])
if max_x is None or x>max_x:
max_x = x
if min_y is None or y<min_y:
min_y = y
if max_y is None or y > max_y:
max_y = y
#if i%100000 ==0:
# print(i)
return [ min_x, min_y, max_x, max_y, width, img.size[1]]
def convert_bounds_to_node_parameters(scn, x1, y1, x2, y2, W, H):
translate_x = (x2+x1-W)/2 /W
translate_y = (y2+y1-H)/2 /H
scale_x = (x2-x1)/W
scale_y = (y2-y1)/H
#scale_nodes = [ n for n in scn.node_tree.nodes if n.type=='SCALE']
# use the N-panel in the compositor nodes to give your scale node this name
scale_nodes = [ n for n in scn.node_tree.nodes if n.name=='matte scale']
translate_nodes = [ n for n in scn.node_tree.nodes if n.name == 'matte translate']
scale_nodes[0].inputs[1].default_value = scale_x
scale_nodes[0].inputs[2].default_value = scale_y
translate_nodes[0].inputs[1].default_value = translate_x
translate_nodes[0].inputs[2].default_value = translate_y
translate_nodes[0].use_relative = True
def wipe_and_rebuild_compositor_nodes(scn, img, wipe=True):
scn.use_nodes = True
while wipe and len(scn.node_tree.nodes)>0:
scn.node_tree.nodes.remove(scn.node_tree.nodes[0])
nodes = scn.node_tree.nodes
links = scn.node_tree.links
dx = 200
image_n = nodes.new("CompositorNodeImage")
image_n.location = (0,0)
image_n.image = img
#matte_n = nodes.new("CompositorNodeColorMatte")
#matte_n.location = (dx,0)
#links.new(matte_n.inputs[0], image_n.outputs[0])
scale1_n = nodes.new("CompositorNodeScale")
scale1_n.location = (2*dx,0)
links.new(scale1_n.inputs[0], image_n.outputs[0])
#links.new(scale1_n.inputs[0], matte_n.outputs[0])
if True:
scale1_n.space = 'RENDER_SIZE'
scale1_n.frame_method = 'STRETCH'
else:
scale1_n.inputs[1].default_value = scn.render.resolution_x / img.size[0]
scale1_n.inputs[2].default_value = scn.render.resolution_y / img.size[1]
y2=-250
layer_n = nodes.new('CompositorNodeRLayers')
layer_n.location = (0,y2)
scale2_n = nodes.new("CompositorNodeScale")
scale2_n.location = (dx,y2)
scale2_n.name = "matte scale"
links.new(scale2_n.inputs[0], layer_n.outputs[0])
translate_n = nodes.new("CompositorNodeTranslate")
translate_n.location = (2*dx, y2)
translate_n.name = "matte translate"
links.new(translate_n.inputs[0], scale2_n.outputs[0])
mix_n = nodes.new("CompositorNodeAlphaOver")
mix_n.location = (3*dx, 0)
links.new(mix_n.inputs[1], scale1_n.outputs[0])
links.new(mix_n.inputs[2], translate_n.outputs[0])
output = nodes.new('CompositorNodeComposite')
output.location = (4*dx,0)
links.new(output.inputs[0], mix_n.outputs[0])
#
#
class CompositeSceneIntoMatte(bpy.types.Operator):
bl_idname = "compositor.scene_into_matte"
bl_label = "Composite Scene Into Matte"
bl_options = {'REGISTER', 'UNDO'}
matte_filename = bpy.props.StringProperty(name="Matte file path",
description="path to the image that provides the matte image",
#default="/var/tmp/matte.png",
subtype='FILE_PATH')
matte_color = bpy.props.FloatVectorProperty(
name="Matte chroma key",
subtype='COLOR',
default=(0, 1, 0),
min=0.0, max=1.0,
description="color from the matte image that marks where the 3D scene should be overlaid"
)
def execute(self, ctx):
try:
try :
img = get_image(self.matte_filename)
except :
self.report({'WARNING'}, "failed to load image from filename %r"%self.matte_filename)
return {'FINISHED'}
bounds = find_green_rectangle(img, self.matte_color)
if bounds[2] is None:
self.report({'WARNING'}, "matte color %r does not appear in image"%self.matte_color)
return {'FINISHED'}
wipe_and_rebuild_compositor_nodes(ctx.scene, img)
convert_bounds_to_node_parameters(ctx.scene, bounds[0], bounds[1], bounds[2]+1, bounds[3]+1, bounds[4], bounds[5])
return {'FINISHED'}
except BaseException as e:
self.report({'ERROR'}, e.args[0])
return {'CANCELLED'}
#
#
def register():
bpy.utils.register_module(__name__)
def unregister():
bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
unregister()
register()
if False:
bounds = find_green_rectangle(get_image("/var/tmp/matte.png"))
print(bounds)
scn = bpy.context.scene
convert_bounds_to_node_parameters(scn, bounds[0], bounds[1], bounds[2]+1, bounds[3]+1, bounds[4], bounds[5])
|
Blender python API quick-start
Syntax highlighting by Pygments.