2
$\begingroup$

I wrote a script based on Exiftool that reads RollAngle, PitchAngle, FocalLength, ImageWidth, ImageHeight and Timestamp #tags from a digital photography's EXIF data. It then matches Blender's camera X and Y rotation and focal length, X and Y res and Sun Position's date and time parameters with values read from the EXIF.

So when adding a mesh, it's 'automagically' aligned with the real-life picture/world. Using it as a camera background allows for (almost) seamless inserting of 3D objects in 'reality'. Check the odd thing on the stage, in the attached image.

I try to img = bpy.something.background_image.pathand getVal(img) because Blender doesn't load EXIF data, and of course my getVal() function relies on them. But so far, the API reference, tooltips and button context menu research didn't help. It works if I manually assign the path to a variable within the code, but it's a pain.

Poorly textured but correctly aligned cheese

`import bpy
 import sys
 import os
 import math
 from exiftool import ExifToolHelper
 lv=[0]# liste valeurs
 def getVal(im) :
 with ExifToolHelper() as et:
    try :
        for d in et.get_tags(im,tags =   ["RollAngle","PitchAngle","FocalLengthIn35mmFormat","ImageWidth","ImageHeight","TimeStamp"]):
            for  v in d.values():
                lv.append(v)
    except :
        pass
return (lv) 

rad = math.radians
cam=bpy.data.objects['Camera']
cam.data.show_background_images=True
# using this block doesn't work and returns 'list index out of range'
items = bpy.data.cameras['Camera'].background_images.items()
camera_image = items[0][1]
filepath = camera_image.image.filepath
prms = getVal(filepath)# if I 'print(prms)' prints '[0]'

#this block works, provided my camera object is selected
#Img = "/home/user/Images/2019/20191030/P1040273.jpg"
#prms = getVal(Img)

cam.rotation_euler[0] = rad(prms[2])+rad(90)# zero RL camera roll = 90° rotation on X axis in Blender
cam.rotation_euler[1] = rad(prms[3])# y rotation
cam.rotation_euler[2] = 0 # my cameras don't have magnetic sensors
bpy.data.objects["Camera"].lock_rotation[0]# this doesn't work either
bpy.data.objects["Camera"].lock_rotation[1]
bpy.data.objects["Camera"].lock_location[2]
cam.location[0] = 0
cam.location[1] = 0
cam.location[2] = 1.7# my eyes' height
#print(prms)
bpy.data.cameras["Camera"].lens = prms[4]
bpy.data.scenes["Scene"].render.resolution_x=prms[5]
bpy.data.scenes["Scene"].render.resolution_y=prms[6]
stamp = prms[-1].split(' ')
date = stamp[0].split(':')
time = stamp[1].split(':')
hours = time[0]
mins = time[1]
secs = time[2]
#########sun pos date##########
bpy.context.scene.sun_pos_properties.year = int(date[0])
bpy.context.scene.sun_pos_properties.month = int(date[1])
bpy.context.scene.sun_pos_properties.day = int(date[2])
#########sun pos time##########
decimals = (int(mins)*60+int(secs))/3600
bpy.context.scene.sun_pos_properties.time = float(hours)+decimals
#bpy.context.scene.sun_pos_properties.latitude = 43.152
#bpy.context.scene.sun_pos_properties.longitude = -3.1

`

$\endgroup$
6
  • $\begingroup$ Thanks, I tried that but using bgImg = bpy.data.cameras['Camera'].background_images.filepath, I got an error saying 'AttributeError: 'bpy_prop_collection' object has no attribute 'filepath'. I guess it's about context, but I can't find anything. $\endgroup$
    – morphik
    Commented Jun 15, 2022 at 7:18
  • $\begingroup$ if you add print(filepath just before the call to getval what gets printed? $\endgroup$ Commented Jun 16, 2022 at 13:47
  • $\begingroup$ Marty, I tried and got exactly this : //../../../../Images/2019/20191030/P1040273.jpg... $\endgroup$
    – morphik
    Commented Jun 17, 2022 at 9:33
  • $\begingroup$ I've updated the answer. You need to change your code to prms = getVal(bpy.path.abspath(filepath)) $\endgroup$ Commented Jun 17, 2022 at 19:37
  • 1
    $\begingroup$ It works ! Thank you so much Marty. I didn't know there was a bpy.path thing... $\endgroup$
    – morphik
    Commented Jun 18, 2022 at 4:34

1 Answer 1

3
$\begingroup$

You need to find the bpy.data.images entry for the image. If you know the name of the image but not the path you can use bpy.data.images[NAME]

Once you know the entry, the full file path is in the filepath member, so something like bpy.data.images['foo.png'].filepath will return the full path to the image.

If you don't know the name, but you know you have only a single camera background image, you can use bpy.data.cameras['Camera'].background_images.items() to fetch a list of all of the background images associated with the camera. Here's what the list looks like when there is only one image:

[(0, bpy.data.cameras['Camera']...CameraBackgroundImage)]

You can find the bpy.data.Images entry from the second member of the tuple, so

items = bpy.data.cameras['Camera'].background_images.items()
camera_image = items[0][1]
filepath = camera_image.image.filepath

Will give you the full path to the first camera background image. For an non-camera background image you need to find the empty associated with the background image. Here's how to get the filepath for a background that's associated with an empty with the default name

filepath = bpy.data.objects['Empty'].data.filepath

UPDATE: about relative paths

If you have blender set up to use relative paths, filepath will be a path that starts '//' indicating that it is relative to the directory where your blend file is stored. To pass this as an absolute path to functions that require such things, instead of filepath, use bpy.path.abspath(filepath).

$\endgroup$
5
  • $\begingroup$ Thank you, I tried that, but it does the same thing as my today's hack : the stored value is //../../../../Images/2019/20191030/P1040273.jpg, and the function only returns [0]. I read somewhere that Blender has kind of its own path system, so until I understand that I guess I'll keep on hardcoding the path. $\endgroup$
    – morphik
    Commented Jun 15, 2022 at 16:36
  • $\begingroup$ I don’t understand your comment. The stored value is the path to the file relative to the directory your blend file is in. $\endgroup$ Commented Jun 15, 2022 at 16:38
  • $\begingroup$ Well, I don't understand why this happens, but i does. Maybe it's because I installed Blender in a non-standard location. $\endgroup$
    – morphik
    Commented Jun 15, 2022 at 17:02
  • $\begingroup$ It's not because you installed Blender in a non-standard location. It's because I don't understand your problem well enough to explain how to solve it. Perhaps if you added an example blend file to your question? (How to add a blend file) But why isn't the relative filepath good enough? You can use Python functions to convert it to an absolute filepath if you have to. Also, there's no way that items should return [0], so perhaps paste your Python code as is into your question. $\endgroup$ Commented Jun 15, 2022 at 17:09
  • $\begingroup$ Just posted my code. Agreed, it shouldn't do that, but I did try a hack, removing the string's first '//../../../' before appending to it another string containing the '/home/user/' missing part. Then trying to use that string, it threw the list 'index out of range' error, and when printing, it showed a different '/./././home/user/Images/foo.png' path (different in terms of slashes and dots number) and the prms variable still only contained '[0]' ; it shows the function couldn't access EXIF data, while if I just use a string variable with the full path in it, the script does the job. $\endgroup$
    – morphik
    Commented Jun 16, 2022 at 6:12

You must log in to answer this question.

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