5

I am making a chroma keyer in the VSE and wondered if it possible to access the control point data of the Hue Sat modifier? I would like to build a GUI for easier control of the curve slope but cannot find a reference to these values.

enter image description here

They seem to have coordinates but no data structure, perhaps this is because you cannot animate their value. But I only want to make interacting with them easier (like the points of a ramp or blend texture).

3pointedit
  • 8,938
  • 1
  • 22
  • 48
  • 2
    You can try bpy.data.scenes['Scene'].sequence_editor.active_strip.modifiers['Hue Correct'].curve_mapping.curves which returns 3 CurveMaps. I assume these are the curves for H S V. CurveMaps contain CurveMapPoints and those have x y location values as far I can see for now, (I can't test it at the moment) see the datablocks: http://i.stack.imgur.com/PSPnl.png – p2or Feb 12 '16 at 15:42
  • Works so far https://gist.github.com/p2or/1f2b725a8c25ce82d69c, but it seems that the curve won't update automatically, might be a viewport issue, not sure. – p2or Feb 12 '16 at 18:56
  • Why don't you post this as an answer? – Samoth Feb 12 '16 at 19:57
  • @Samoth Since the OP wants to generate a custom curve there is a lot more to cover - creating and removing points, set the interpolation type etc. :) I don't have so much time at the moment and I also think the answer would be incomplete until we've found a way to update the curve.Unfortunately calling scene.update() does not work on linux nor on windows. Anyway, thanks! – p2or Feb 13 '16 at 15:53
  • @poor: Well, he didn't ask for a perfect solution, but whether it's possible and you already posted how in this comments and linked some code - you can (for a first step) just pack it together in an answer explaining the open problems as well. And probably you might edit your answer later to show solutions to these problems or explain why it won't be possible in the end. You seem to long for a perfect answer, but this might already help him perfectly without the need to be more perfectionistic. ;-) – Samoth Feb 13 '16 at 21:59

1 Answers1

6

You can access the 'Control Points' via CurveMap attribute of the respective Hue Correct Modifier:

>>> h, s, v = bpy.context.scene.sequence_editor.active_strip.modifi‌​ers['Hue Correct'].curve_mapping.curves
>>> print (h.points, s.points, v.points)
>>> [p.location for p in s.points]  # print saturation vector control points
>>> s.points[3].location[1] = 0.001 # assignment (y location)

To update the representation of the Curve within the UI call CurveMapping.update() after any assignment. However this does not update the Viewer, so toggling the 'visibility' enter image description here of the modifier is probably the easiest and fastest way to update the Curve and refreshing the Viewer at once.

Desaturate blue(s)

enter image description here

import bpy

scn = bpy.context.scene act_strip = scn.sequence_editor.active_strip hue_modifier = act_strip.modifiers["Hue Correct"]

get the mapping

.../bpy.types.CurveMapping.html#bpy.types.CurveMapping

mapping = hue_modifier.curve_mapping

get the curve maps

.../bpy.types.CurveMap.html#bpy.types.CurveMap

hue, sat, val = mapping.curves

iterate through saturation control points

for count, point in enumerate(sat.points): x, y = point.location

# desaturate blue
if 0.55 <= x <= 0.7: # check if x is within the blue range
    point.location.y = 0.01

print (count, point.location)

direct assignment via index operator

#sat.points[5].location[1] = 0 # desaturate blue

update the curve

../bpy.types.CurveMapping.html#bpy.types.CurveMapping.update

mapping.update()

force viewer update (optional)

hue_modifier.mute = True hue_modifier.mute = False

Custom curves

To apply a custom Curve iterate through CurveMap.points and assign a Vector((x, y)) to each Point.location (0-1 float range). The following operator allows to reset the number of points as well as the point locations to the default values for demonstration purposes:

enter image description here Click to enlarge

Reset Curves Operator (Blender 2.8+)

import bpy
from bpy.props import BoolProperty, EnumProperty
from bpy.types import Operator
from mathutils import Vector

def reset_curve(curvemap):

default_points = [Vector((0.0, 0.5)), Vector((0.125, 0.5)), Vector((0.25, 0.5)), 
                 Vector((0.375, 0.5)), Vector((0.5, 0.5)), Vector((0.625, 0.5)), 
                 Vector((0.75, 0.5)), Vector((0.875, 0.5)), Vector((1.0, 0.5))]

if len(curvemap.points) > len(default_points):  # remove waste
    n = 0
    while len(curvemap.points) > len(default_points):
        curvemap.points.remove(curvemap.points[n])
        n += 1

if len(curvemap.points) < len(default_points): # generate missing points
    n = 0
    while len(curvemap.points) < len(default_points):
        curvemap.points.new(0.1, 0.5)
        n +=1

# set values to default
for c, point in enumerate(curvemap.points):
    point.location = default_points[c]


class SEQUENCER_OT_resetHueCorrect(Operator): bl_idname="sequencer.reset_hue_correct" bl_label="Reset Hue Correct" bl_options = {'REGISTER', 'UNDO'}

# properties
def modifier_callback(self, context):
    sel_strip = context.scene.sequence_editor.active_strip                    
    hue_modifiers = [(str(c), item.name.title(), '') for 
        c, item in enumerate(sel_strip.modifiers) if 
        item.type == "HUE_CORRECT"]
    return hue_modifiers

mod: EnumProperty(name="Modifier", items=modifier_callback)
hue: BoolProperty(default=True, name="Hue") 
sat: BoolProperty(default=True, name="Saturation")
val: BoolProperty(default=True, name="Value")

@classmethod
def poll(cls, context):
    spc = context.space_data
    act_clip = context.scene.sequence_editor.active_strip
    return (spc.type == 'SEQUENCE_EDITOR' and act_clip.select)

def execute(self, context):

    # get the active strip
    sel_strip = context.scene.sequence_editor.active_strip

    # tagging the area for redraw to update the curve edits
    context.region.tag_redraw() #context.area.tag_redraw()

    #for m in sel_strip.modifiers:
    m = sel_strip.modifiers[int(self.mod)]

    # get the mapping 
    # .../bpy.types.CurveMapping.html#bpy.types.CurveMapping
    mapping = m.curve_mapping

    # get the curve maps
    # .../bpy.types.CurveMap.html#bpy.types.CurveMap
    h, s, v = mapping.curves

    # reset hue
    if self.hue: reset_curve(h)

    # reset saturation
    if self.sat: reset_curve(s)

    # reset value
    if self.val: reset_curve(v)

    # update the curve
    m.curve_mapping.update()

    # toggle modifier visibility to update the viewer
    # -> way faster than sequencer.refresh_all()
    m.mute = not m.mute # respect the state
    m.mute = not m.mute   

    self.report({'INFO'}, "Successfully reset {}".format(m.name))
    return {'FINISHED'}

def invoke(self, context, event):
    wm = context.window_manager
    sel_strip = context.scene.sequence_editor.active_strip
    if bool([m for m in sel_strip.modifiers if m.type == "HUE_CORRECT"]):
        return wm.invoke_props_dialog(self)
    else:
        self.report({"INFO"}, "strip has no hue correct modifier")
        return {'FINISHED'}

def draw(self, context):         
    row = self.layout
    sel_strip = context.scene.sequence_editor.active_strip
    if len([m for m in sel_strip.modifiers if m.type == "HUE_CORRECT"]) > 1:
        row.prop(self, "mod")
    row.prop(self, "hue")
    row.prop(self, "sat")
    row.prop(self, "val")


def register(): bpy.utils.register_class(SEQUENCER_OT_resetHueCorrect)

def unregister(): bpy.utils.unregister_class(SEQUENCER_OT_resetHueCorrect)

if name == "main": register()

p2or
  • 15,860
  • 10
  • 83
  • 143
  • 2
    Oh wow @poor thanks for taking the time. TBH I had mostly forgot this was here. I'll have to try this code out! – 3pointedit Oct 06 '16 at 22:22
  • Hmm can't register or run the script? On 2.76 with adjustment layer and hue modifier. But cannot search for sequencer>Hue reset either. Info bar says it runs without warning however? – 3pointedit Oct 06 '16 at 22:35
  • Did you ever get a working addon for this? I have been wanting to be able to easily chroma key from the VSE as well. – doakey3 Apr 09 '18 at 15:00