7
$\begingroup$

How to access pixel values in a video footage frames from python API? Sequence or clip editor? Or loading data directly perhaps?

I'd like to make a primitive laser 3D scanning addon utilizing same principle as http://en.myinventions.pl/index.php?page=3Dscanner

Edit: Ok, half way there - able to load file, but can read only the first frame. Is there a way to change frame?

import bpy
img = bpy.data.images.load('H:\\Data\\_blender\\Fluid\\Video_Edit.mov')
print(img.frame_duration)

#getting data
pixels = list(img.pixels)

#testing data
tmp = bpy.data.images.new(name="sample"+str(frame), width=w, height=h, alpha=False, float_buffer=False)
tmp.pixels = pixels
$\endgroup$
  • 1
    $\begingroup$ Note, while Im sure this is possible to do, this is not at all something the Python API was designed to do, so probably some workarounds to force updates for an image will be needed to have this working as you would want. $\endgroup$ – ideasman42 Oct 28 '13 at 2:06
  • $\begingroup$ @ideasman42 It seems it's not possible directly: projects.blender.org/tracker/… Still, probably there's some way through canvas of image or sequence editor? Don't know if those are accessible. Sure, API of a 3D app wasn't developed for that :) But it can give quite interesting possibilities. $\endgroup$ – kivig Oct 28 '13 at 12:41
4
$\begingroup$

Though not officially possible (https://projects.blender.org/tracker/index.php?func=detail&aid=37216&group_id=9&atid=498), I found a dirty workaround:

import bpy

frameStart = 1
frameEnd = 155
frameStep = 50
viewer_area = None
viewer_space = None

for area_search in bpy.context.screen.areas:
    if viewer_area == None and area_search.type == 'IMAGE_EDITOR':
        viewer_area = area_search
        break

if viewer_area == None:
    viewer_area = bpy.context.screen.areas[0]
    viewer_area.type = "IMAGE_EDITOR"

for space in viewer_area.spaces:
    if space.type == "IMAGE_EDITOR":
        viewer_space = space

path = 'H:\\Data\\_blender\\Fluid\\Video_Edit.mov'
img = bpy.data.images.load(path)
w = img.size[0]
h = img.size[1]
viewer_space.image = img

frame = 1
for frame in range(frameStart, frameEnd, frameStep):
    viewer_space.image_user.frame_offset = frame
    #switch back and forth to force refresh
    viewer_space.draw_channels = 'COLOR_ALPHA'
    viewer_space.draw_channels = 'COLOR'
    pixels = list(viewer_space.image.pixels)
    tmp = bpy.data.images.new(name="sample"+str(frame), width=w, height=h, alpha=False, float_buffer=False)
    tmp.pixels = pixels

img.user_clear()
bpy.data.images.remove(img)
$\endgroup$
1
$\begingroup$

I managed to get the pixels of a certain frame, but several condition have to be met (it's a bit obscure why all this is needed):

  1. The Image datablock needs to be used by an 'IMAGE' texture
  2. That texture needs to be selected in the Properties Editor's texture tab
    (doesn't matter if an object is selected or if it's the world texture context)
  3. Properties Editor's Texture tab needs to be activated (before every frame change!)
    Area.spaces[0].context = 'TEXTURE'
  4. Set Texture.image_user.frame_duration to the desired frame
  5. Read the pixels like Texture.image.pixels[:]

Maybe it's worth to rather create a sequence and set the timeline frame instead...

$\endgroup$
  • 1
    $\begingroup$ It seems texture images don't get updated until script finishes, thus frame change has no effect. Also it seems there's no way to define what frame to get through image. I wonder if its just overlooked function or there's internal obstacle for this. $\endgroup$ – kivig Oct 26 '13 at 16:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.