2
$\begingroup$

I have a large body of video (dozens of hours) containing stretches of mostly frozen video. I've been able to detect these sections with compositor nodes resulting in an (incredibly inefficient) all black or all white screen as a Boolean. How can I use this node system to include or exclude frames from my source video set to pair down my data set? (I eventually want to compile these into a time lapse video.)

$\endgroup$

1 Answer 1

2
$\begingroup$

You can do some cuts programmatically with Python and it should be well possible to use this black/white information as a source for the timing of these cuts. I've already done such cutting of sequences with Audacity Text markers from a file:

import bpy

f = open('cuts.txt', 'r', encoding='utf-8')
data = f.readlines()
data = [w.replace(',', '.') for w in data]
f.close()

#bpy.data.scenes['Scene'].timeline_markers.clear()

for s in bpy.data.scenes['Scene'].sequence_editor.sequences_all:
    s.select = False

for i in range(0, len(data)):
    entry = data[i].split()
    start = int(bpy.utils.time_to_frame(float(entry[0]), fps=None, fps_base=None))
    end   = int(bpy.utils.time_to_frame(float(entry[1]), fps=None, fps_base=None))
    print(entry[2] + ': ' + str(start) + ' ' + str(end))

    for s in bpy.data.scenes['Scene'].sequence_editor.sequences_all:
        if s.frame_final_start < start and s.frame_final_end > end and s.channel == 2:
            print(s.name)
            s.select = True
            bpy.ops.sequencer.cut(frame=start, type='SOFT', side='RIGHT')
            for s2 in bpy.data.scenes['Scene'].sequence_editor.sequences_all:
                if s2.select:
                    s2.mute = False
            bpy.ops.sequencer.cut(frame=end,  type='SOFT', side='RIGHT')
            for s2 in bpy.data.scenes['Scene'].sequence_editor.sequences_all:
                if s2.select:
                    s2.mute = True

Now the only problem remaining should be the detection of the black/white stuff. There's a great solution from W-Sfax: Blender: Access Render Results pixels directly from Python

import bpy
import numpy as np

# switch on nodes
bpy.context.scene.use_nodes = True
tree = bpy.context.scene.node_tree
links = tree.links

# clear default nodes
for n in tree.nodes:
tree.nodes.remove(n)

# create input render layer node
rl = tree.nodes.new('CompositorNodeRLayers')      
rl.location = 185,285

# create output node
v = tree.nodes.new('CompositorNodeViewer')   
v.location = 750,210
v.use_alpha = False

# Links
links.new(rl.outputs[0], v.inputs[0])  # link Image output to Viewer input

# render
bpy.ops.render.render()

# get viewer pixels
pixels = bpy.data.images['Viewer Node'].pixels
print(len(pixels)) # size is always width * height * 4 (rgba)

# copy buffer to numpy array for faster manipulation
arr = np.array(pixels[:])
$\endgroup$
1
  • $\begingroup$ Sounds like a good direction to go in... Any idea how I can speed up my compositing node system that drives this? I thought about rendering it to a 16x9 (or even 1x1) pixel scene, but I don't believe blender supports scenes in the same project with differing image dimensions. Could the second code snippet you included work off a box-select render (Ctrl-B in the 3D viewport) to only render a small region? Would this still utilize the compositor nodes. (To render the output correctly, the whole image must be used as input, but only a small region needs to generate final pixel data.) $\endgroup$ Commented Jan 13, 2017 at 10:29

You must log in to answer this question.

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