Skip to content

Instantly share code, notes, and snippets.

@AndrewHazelden
Last active May 29, 2024 20:38
Show Gist options
  • Save AndrewHazelden/3147cdca2f35cc28c0869005136d4182 to your computer and use it in GitHub Desktop.
Save AndrewHazelden/3147cdca2f35cc28c0869005136d4182 to your computer and use it in GitHub Desktop.
A Resolve Studio/Fusion Studio Lua script to apply camera sensor information to Camera3D, uCamera, CameraTracker, Renderer3D, and uRenderer nodes.
--[[--
Camera Sensor Database v1 - 2024-05-29 05.30 PM (UTC -3)
Database By: Jacob Danell <[email protected]>
Fusion Studio GUI By: Andrew Hazelden <[email protected]>
Overview:
Apply camera sensor information to BMD Fusion Studio based Camera3D, uCamera, CameraTracker, Renderer3D, and uRenderer nodes.
Installation:
1. Copy the "Camera Sensor Database.lua" script to the "Reactor:/Deploy/Scripts/Comp/" PathMap folder.
2. If you are using this script offline, the "sensors.json" file is saved to the PathMap location of:
Reactor:/Deploy/Scripts/Support/sensors.json
For More Info:
To quickly view the data in a web browser, go to docs page:
https://emberlightvfx.github.io/Camera-Sensor-Database/
The GitHub downloaded sensors.json file is accessed at:
https://raw.githubusercontent.com/EmberLightVFX/Camera-Sensor-Database/main/data/sensors.json
Sample record:
{
mm = {
width = 23.76,
height = 13.37,
diagonal = 27.263
},
resolution = {
width = "",
height = ""
},
["focal length"] = "",
inches = {
width = 0.935,
height = 0.526,
diagonal = 1.073
}
}
Version History:
2024-05-29 - v1 Initial Release
By Jacob Danell & Andrew Hazelden
--]]--
local json = require("dkjson")
function Download()
local sourceURL = [[https://raw.githubusercontent.com/EmberLightVFX/Camera-Sensor-Database/main/data/sensors.json]]
local destFolder = fusion:MapPath("Reactor:/Deploy/Scripts/Support/")
local destFile = fusion:MapPath(destFolder .. "sensors.json")
if not bmd.direxists(destFolder) then
bmd.createdir(destFolder)
if not bmd.direxists(destFolder) then
error(string.format("[Create Dir] Failed to create directory: %s", destFolder))
end
end
ffi = require "ffi"
curl = require "lj2curl"
ezreq = require "lj2curl.CRLEasyRequest"
local req = ezreq(sourceURL)
local body = {}
req:setOption(curl.CURLOPT_SSL_VERIFYPEER, 0)
req:setOption(curl.CURLOPT_WRITEFUNCTION, ffi.cast("curl_write_callback",
function(buffer, size, nitems, userdata)
table.insert(body, ffi.string(buffer, size*nitems))
return nitems
end))
print("\n[Downloading JSON]\n" .. sourceURL)
ok, err = req:perform()
if ok then
local json_string = table.concat(body)
-- Write the file to disk
print("\n[Saving JSON]\n" .. destFile)
local file = io.open(destFile, "w")
file:write(json_string)
file:close();
return json.decode(json_string) or {}
else
-- Fallback to a locally cached file
local file = io.open(destFile, "r")
if file then
print("\n[Loading Cached JSON]\n" .. destFile)
local json_string = file:read("*all")
file:close()
return json.decode(json_string) or {}
else
print("\n[No Cached JSON] Please download the sensors.json file.\n")
return {}
end
end
end
function ProgramInfo()
print("\n------------------------------------------")
print("Camera Sensor Database - v1")
print("A collection of camera sensor information.")
print("------------------------------------------\n")
end
function VendorInfo(tbl)
-- List the vendors and cameras
if tbl and type(tbl) == "table" then
print("\n[Vendors]")
for vendor,vendorTbl in pairs(tbl) do
print(vendor)
for camera,cameraTbl in pairs(vendorTbl) do
print("\t" , camera)
end
end
end
end
function GUI(tbl)
local ui = app.UIManager
local disp = bmd.UIDispatcher(ui)
local width,height = 880,95
win = disp:AddWindow({
ID = "CameraSensorDatabase",
TargetID = "CameraSensorDatabase",
WindowTitle = "Camera Sensor Database",
Geometry = {100, 200, width, height},
ui:HGroup{
ID = "root",
-- Add your GUI elements here:
ui:VGroup {
Weight = 1,
ui:HGroup {
Weight = 1,
ui:HGroup {
ui:Label{
ID = "VendorLabel",
Weight = 0,
Text = "Vendor:",
Alignment = {
AlignHCenter = true,
AlignTop = true,
},
},
ui:ComboBox{
ID = "Vendor",
},
},
ui:HGroup {
ui:Label{
ID = "CameraLabel",
Weight = 0,
Text = "Camera:",
Alignment = {
AlignHCenter = true,
AlignTop = true,
},
},
ui:ComboBox{
ID = "Camera",
},
},
ui:HGroup {
ui:Label{
ID = "SensorLabel",
Weight = 0,
Text = "Sensor:",
Alignment = {
AlignHCenter = true,
AlignTop = true,
},
},
ui:ComboBox{
ID = "Sensor",
},
},
},
ui:HGroup {
Weight = 0,
ui:Label{
Weight = 0,
ID = "SensorDimensionsLabel",
Text = "Sensor Dimensions:",
Alignment = {
AlignHCenter = true,
AlignTop = true,
},
},
ui:LineEdit{
ID = "SensorDimensionsWidth",
Text = "",
PlaceholderText = "Width",
ReadOnly = true,
},
ui:Label{
Weight = 0,
ID = "SensorDimensionsXLabel",
Text = "X",
Alignment = {
AlignHCenter = true,
AlignTop = true,
},
},
ui:LineEdit{
ID = "SensorDimensionsHeight",
Text = "",
PlaceholderText = "Height",
ReadOnly = true,
},
ui:Label{
Weight = 0,
ID = "SensorDiagonalLabel",
Text = "Diagonal:",
Alignment = {
AlignHCenter = true,
AlignTop = true,
},
},
ui:LineEdit{
ID = "SensorDimensionsDiagonal",
Text = "",
PlaceholderText = "",
ReadOnly = true,
},
ui:HGroup {
ui:ComboBox{
Weight = 0.01,
ID = "Unit",
},
},
},
ui:HGroup {
Weight = 0,
ui:HGroup {
Weight = 0.25,
ui:Label{
ID = "FocalLengthLabel",
Weight = 0,
Text = "Focal Length:",
Alignment = {
AlignHCenter = true,
AlignTop = true,
},
},
ui:LineEdit{
ID = "FocalLength",
Text = "",
PlaceholderText = "",
ReadOnly = true,
},
},
ui:HGroup {
Weight = 0.75,
ui:Label{
Weight = 0,
ID = "ResolutionLabel",
Text = "Resolution:",
Alignment = {
AlignHCenter = true,
AlignTop = true,
},
},
ui:LineEdit{
ID = "ResolutionWidth",
Text = "",
PlaceholderText = "Width",
ReadOnly = true,
},
ui:Label{
Weight = 0,
ID = "ResolutionXLabel",
Text = "X",
Alignment = {
AlignHCenter = true,
AlignTop = true,
},
},
ui:LineEdit{
ID = "ResolutionHeight",
Text = "",
PlaceholderText = "Height",
ReadOnly = true,
},
ui:Label{
Weight = 0,
ID = "ResolutionPXLabel",
Text = "px",
Alignment = {
AlignHCenter = true,
AlignTop = true,
},
},
},
},
},
ui:HGroup{
Weight = 0,
ui:Button{
Weight = 0,
ID = "ApplyButton",
Default = true,
Text = "Apply to Selection",
},
},
},
})
-- Add your GUI element based event functions here:
itm = win:GetItems()
-- The window was closed
function win.On.CameraSensorDatabase.Close(ev)
disp:ExitLoop()
end
vItemsTbl = {}
for vendor,vendorTbl in pairs(tbl) do
table.insert(vItemsTbl, vendor)
end
table.sort(vItemsTbl)
itm.Vendor:Clear()
itm.Vendor:AddItems(vItemsTbl)
itm.Unit:Clear()
itm.Unit:AddItem("mm")
itm.Unit:AddItem("inches")
-- The "Vendor" ComboBox value has changed
function win.On.Vendor.CurrentIndexChanged(ev)
local vendorName = itm.Vendor.CurrentText
local cItemsTbl = {}
for vendor,vendorTbl in pairs(tbl) do
if vendor == vendorName then
for camera,cameraTbl in pairs(vendorTbl) do
table.insert(cItemsTbl, camera)
end
end
end
table.sort(cItemsTbl)
itm.Camera:Clear()
itm.Camera:AddItems(cItemsTbl)
end
-- The "Camera" ComboBox value has changed
function win.On.Camera.CurrentIndexChanged(ev)
local vendorName = itm.Vendor.CurrentText
local cameraName = itm.Camera.CurrentText
local sensorName = itm.Sensor.CurrentText
sItemsTbl = {}
for vendor,vendorTbl in pairs(tbl) do
if vendor == vendorName then
for camera,cameraTbl in pairs(vendorTbl) do
if camera == cameraName then
sensorDimensionsTbl = cameraTbl["sensor dimensions"] or {}
for sensor,sensorTbl in pairs(sensorDimensionsTbl) do
table.insert(sItemsTbl, sensor)
end
end
end
end
end
table.sort(sItemsTbl)
itm.Sensor:Clear()
itm.Sensor:AddItems(sItemsTbl)
end
-- The "Sensor" ComboBox value has changed
function win.On.Sensor.CurrentIndexChanged(ev)
local vendorName = itm.Vendor.CurrentText
local cameraName = itm.Camera.CurrentText
local sensorName = itm.Sensor.CurrentText
sItemsTbl = {}
for vendor,vendorTbl in pairs(tbl) do
if vendor == vendorName then
for camera,cameraTbl in pairs(vendorTbl) do
if camera == cameraName then
sensorDimensionsTbl = cameraTbl["sensor dimensions"] or {}
for sensor,sensorTbl in pairs(sensorDimensionsTbl) do
if sensor == sensorName then
if sensorTbl["resolution"] and sensorTbl["focal length"] then
itm.FocalLength.Text = tostring(sensorTbl["focal length"])
end
if sensorTbl["resolution"] and sensorTbl["resolution"]["width"] and sensorTbl["resolution"]["height"] then
itm.ResolutionWidth.Text = tostring(sensorTbl["resolution"]["width"])
itm.ResolutionHeight.Text = tostring(sensorTbl["resolution"]["height"])
end
if itm.Unit.CurrentText == "inches" and sensorTbl["inches"] and sensorTbl["inches"]["width"] and sensorTbl["inches"]["height"] and sensorTbl["inches"]["diagonal"] then
itm.SensorDimensionsWidth.Text = tostring(sensorTbl["inches"]["width"])
itm.SensorDimensionsHeight.Text = tostring(sensorTbl["inches"]["height"])
itm.SensorDimensionsDiagonal.Text = tostring(sensorTbl["inches"]["diagonal"])
elseif itm.Unit.CurrentText == "mm" and sensorTbl["mm"] and sensorTbl["mm"]["width"] and sensorTbl["mm"]["height"] and sensorTbl["mm"]["diagonal"] then
itm.SensorDimensionsWidth.Text = tostring(sensorTbl["mm"]["width"])
itm.SensorDimensionsHeight.Text = tostring(sensorTbl["mm"]["height"])
itm.SensorDimensionsDiagonal.Text = tostring(sensorTbl["mm"]["diagonal"])
end
end
end
end
end
end
end
end
-- The "Unit" ComboBox value has changed
function win.On.Unit.CurrentIndexChanged(ev)
local vendorName = itm.Vendor.CurrentText
local cameraName = itm.Camera.CurrentText
local sensorName = itm.Sensor.CurrentText
sItemsTbl = {}
for vendor,vendorTbl in pairs(tbl) do
if vendor == vendorName then
for camera,cameraTbl in pairs(vendorTbl) do
if camera == cameraName then
sensorDimensionsTbl = cameraTbl["sensor dimensions"] or {}
for sensor,sensorTbl in pairs(sensorDimensionsTbl) do
if sensor == sensorName then
if sensorTbl["resolution"] and sensorTbl["focal length"] then
itm.FocalLength.Text = tostring(sensorTbl["focal length"])
end
if sensorTbl["resolution"] and sensorTbl["resolution"]["width"] and sensorTbl["resolution"]["height"] then
itm.ResolutionWidth.Text = tostring(sensorTbl["resolution"]["width"])
itm.ResolutionHeight.Text = tostring(sensorTbl["resolution"]["height"])
end
if itm.Unit.CurrentText == "inches" and sensorTbl["inches"] and sensorTbl["inches"]["width"] and sensorTbl["inches"]["height"] and sensorTbl["inches"]["diagonal"] then
itm.SensorDimensionsWidth.Text = tostring(sensorTbl["inches"]["width"])
itm.SensorDimensionsHeight.Text = tostring(sensorTbl["inches"]["height"])
itm.SensorDimensionsDiagonal.Text = tostring(sensorTbl["inches"]["diagonal"])
elseif itm.Unit.CurrentText == "mm" and sensorTbl["mm"] and sensorTbl["mm"]["width"] and sensorTbl["mm"]["height"] and sensorTbl["mm"]["diagonal"] then
itm.SensorDimensionsWidth.Text = tostring(sensorTbl["mm"]["width"])
itm.SensorDimensionsHeight.Text = tostring(sensorTbl["mm"]["height"])
itm.SensorDimensionsDiagonal.Text = tostring(sensorTbl["mm"]["diagonal"])
end
end
end
end
end
end
end
end
-- The "Apply to Selection" button was clicked
function win.On.ApplyButton.Clicked(ev)
print("\n[Apply to Selection]")
-- Undo Stack
comp:StartUndo("Camera Sensor Database")
local vendorName = itm.Vendor.CurrentText
local cameraName = itm.Camera.CurrentText
local sensorName = itm.Sensor.CurrentText
local sensorWidthMM
local sensorWidthInches
local sensorHeightMM
local sensorHeightInches
local focalLengthMM
local width
local height
sItemsTbl = {}
for vendor,vendorTbl in pairs(tbl) do
if vendor == vendorName then
for camera,cameraTbl in pairs(vendorTbl) do
if camera == cameraName then
sensorDimensionsTbl = cameraTbl["sensor dimensions"] or {}
for sensor,sensorTbl in pairs(sensorDimensionsTbl) do
if sensor == sensorName then
if sensorTbl["resolution"] and sensorTbl["focal length"] then
focalLengthMM = tostring(sensorTbl["focal length"])
end
if sensorTbl["resolution"] and sensorTbl["resolution"]["width"] and sensorTbl["resolution"]["height"] then
width = tostring(sensorTbl["resolution"]["width"])
height = tostring(sensorTbl["resolution"]["height"])
end
if sensorTbl["inches"] and sensorTbl["inches"]["width"] and sensorTbl["inches"]["height"] and sensorTbl["inches"]["diagonal"] then
sensorWidthInches = tostring(sensorTbl["inches"]["width"])
sensorHeightInches = tostring(sensorTbl["inches"]["height"])
end
if sensorTbl["mm"] and sensorTbl["mm"]["width"] and sensorTbl["mm"]["height"] and sensorTbl["mm"]["diagonal"] then
sensorWidthMM = tostring(sensorTbl["mm"]["width"])
sensorHeightMM = tostring(sensorTbl["mm"]["height"])
end
end
end
end
end
end
end
Camera3DTools = comp:GetToolList(true, "Camera3D")
for k, tool in pairs(Camera3DTools) do
print(tool.Name)
tool["FilmGate"][fu.TIME_UNDEFINED] = "User"
-- Focal Length is in mm
if focalLengthMM ~= "" then
tool["FLength"][fu.TIME_UNDEFINED] = tonumber(focalLengthMM)
end
-- Aperture is in Inches
print("\t[Sensor Dimensions] ", sensorWidthInches, "x", sensorHeightInches, " inches")
tool["ApertureW"][fu.TIME_UNDEFINED] = tonumber(sensorWidthInches)
tool["ApertureH"][fu.TIME_UNDEFINED] = tonumber(sensorHeightInches)
end
uCameraTools = comp:GetToolList(true, "uCamera")
for k, tool in pairs(uCameraTools) do
print(tool.Name)
-- Focal Length is in mm
if focalLengthMM ~= "" then
tool["FocalLength"][fu.TIME_UNDEFINED] = tonumber(focalLengthMM)
end
-- Aperture is in mm
print("\t[Sensor Dimensions] ", sensorWidthMM, "x", sensorHeightMM, " mm")
tool["HorizontalAperture"][fu.TIME_UNDEFINED] = tonumber(sensorWidthMM)
tool["VerticalAperture"][fu.TIME_UNDEFINED] = tonumber(sensorHeightMM)
end
CameraTrackerTools = comp:GetToolList(true, "Dimension.CameraTracker")
for k, tool in pairs(CameraTrackerTools) do
print(tool.Name)
tool["Camera.FilmGate"][fu.TIME_UNDEFINED] = "User"
-- Focal Length is in mm
if focalLengthMM ~= "" then
tool["Camera.FocalLength"][fu.TIME_UNDEFINED] = tonumber(focalLengthMM)
end
-- Aperture is in Inches
print("\t[Sensor Dimensions] ", sensorWidthInches, "x", sensorHeightInches, " inches")
tool["Camera.ApertureW"][fu.TIME_UNDEFINED] = tonumber(sensorWidthInches)
tool["Camera.ApertureH"][fu.TIME_UNDEFINED] = tonumber(sensorHeightInches)
end
uRendererTools = comp:GetToolList(true, "uRenderer")
for k, tool in pairs(uRendererTools) do
print(tool.Name)
-- Image Size
if (type(width) == "string" and width ~= "") and (type(height) == "string" and height ~= "") then
print("\t[Image Size] ", width, "x", height, " px")
tool["Width"][fu.TIME_UNDEFINED] = tonumber(width)
tool["Height"][fu.TIME_UNDEFINED] = tonumber(height)
end
end
Renderer3DTools = comp:GetToolList(true, "Renderer3D")
for k, tool in pairs(Renderer3DTools) do
print(tool.Name)
-- Image Size
if (type(width) == "string" and width ~= "") and (type(height) == "string" and height ~= "") then
print("\t[Image Size] ", width, "x", height, " px")
tool["Width"][fu.TIME_UNDEFINED] = tonumber(width)
tool["Height"][fu.TIME_UNDEFINED] = tonumber(height)
end
end
-- Undo Stack
comp:EndUndo(true)
end
-- The app:AddConfig() command that will capture the "Control + W" or "Control + F4" hotkeys so they will close the window instead of closing the foreground composite.
app:AddConfig("CameraSensorDatabase", {
Target {
ID = "CameraSensorDatabase",
},
Hotkeys {
Target = "CameraSensorDatabase",
Defaults = true,
CONTROL_W = "Execute{cmd = [[app.UIManager:QueueEvent(obj, 'Close', {})]]}",
CONTROL_F4 = "Execute{cmd = [[app.UIManager:QueueEvent(obj, 'Close', {})]]}",
ESCAPE = "Execute{cmd = [[app.UIManager:QueueEvent(obj, 'Close', {})]]}",
},
})
win:Show()
disp:RunLoop()
win:Hide()
app:RemoveConfig("CameraSensorDatabase")
collectgarbage()
end
function Main()
ProgramInfo()
-- Grab the latest sensor data
local tbl = Download()
-- Print the vendor data to the console
-- VendorInfo(tbl)
-- Show the GUI
if tbl and type(tbl) == "table" then
-- dump(tbl)
GUI(tbl)
else
print("No sensor data received")
end
print("[Done]")
end
-- Where the magic happens
Main()
@AndrewHazelden
Copy link
Author

Screenshots

2024-05-28 Camera Sensor Database R1
2024-05-28 Console Output R1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment