Skip to content

Commit

Permalink
Use bindings for hdr brackets estimation
Browse files Browse the repository at this point in the history
  • Loading branch information
servantftechnicolor committed Sep 30, 2024
1 parent dc8b724 commit 1571ee0
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 259 deletions.
100 changes: 14 additions & 86 deletions meshroom/nodes/aliceVision/LdrToHdrCalibration.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import os
from collections import Counter

from pyalicevision import sfmData as avsfmdata
from pyalicevision import hdr as avhdr

from meshroom.core import desc
from meshroom.core.utils import COLORSPACES, VERBOSE_LEVEL

Expand Down Expand Up @@ -205,7 +208,7 @@ def update(cls, node):
node.nbBrackets.value = 0
return

inputs = []
inputs = avhdr.vectorli()
for viewpoint in viewpoints:
jsonMetadata = viewpoint.metadata.value
if not jsonMetadata:
Expand All @@ -232,97 +235,22 @@ def update(cls, node):
# We assume that there is no multi-bracketing, so nothing to do.
node.nbBrackets.value = 1
return
inputs.append((viewpoint.path.value, (float(fnumber), float(shutterSpeed), float(iso))))
inputs.sort()

exposureGroups = []
exposures = []
prevFnumber = 0.0
prevShutterSpeed = 0.0
prevIso = 0.0
prevPath = None # Stores the dirname of the previous parsed image
prevExposure = None
newGroup = False # True if a new exposure group needs to be created (useful when there are several datasets)
for path, exp in inputs:
# If the dirname of the previous image and the dirname of the current image do not match, this means that the
# dataset that is being parsed has changed. A new group needs to be created but will fail to be detected in the
# next "if" statement if the new dataset's exposure levels are different. Setting "newGroup" to True prevents this
# from happening.
if prevPath is not None and prevPath != os.path.dirname(path):
newGroup = True

currentExposure = LdrToHdrCalibration.getExposure(exp)

# Create a new group if the current image's exposure level is smaller than the previous image's, or
# if a new dataset has been detected (with a change in the path of the images).
if prevExposure and currentExposure < prevExposure or newGroup:
exposureGroups.append(exposures)
exposures = [exp]
else:
exposures.append(exp)
exposure = LdrToHdrCalibration.getExposure((float(fnumber), float(shutterSpeed), float(iso)))

prevPath = os.path.dirname(path)
prevExposure = currentExposure
newGroup = False
obj = avhdr.LuminanceInfo(viewpoint.viewId.value,viewpoint.path.value, exposure)
inputs.append(obj)

exposureGroups.append(exposures)
obj = avhdr.estimateGroups(inputs)

exposures = None
bracketSizes = Counter()
if len(exposureGroups) == 1:
if len(set(exposureGroups[0])) == 1:
# Single exposure and multiple views
node.nbBrackets.value = 1
else:
# Single view and multiple exposures
node.nbBrackets.value = len(exposureGroups[0])
else:
for expGroup in exposureGroups:
bracketSizes[len(expGroup)] += 1

if len(bracketSizes) == 0:
node.nbBrackets.value = 0
else:
bestTuple = None
for tuple in bracketSizes.most_common():
if bestTuple is None or tuple[1] > bestTuple[1]:
bestTuple = tuple
elif tuple[1] == bestTuple[1]:
bestTuple = tuple if tuple[0] > bestTuple[0] else bestTuple
if len(obj) == 0:
node.nbBrackets.value = 0
return

bestBracketSize = bestTuple[0]
node.nbBrackets.value = bestBracketSize
node.nbBrackets.value = len(obj[0])

@staticmethod
def getExposure(exp, refIso = 100.0, refFnumber = 1.0):
fnumber, shutterSpeed, iso = exp

validShutterSpeed = shutterSpeed > 0.0 and math.isfinite(shutterSpeed)
validFnumber = fnumber > 0.0 and math.isfinite(fnumber)

if not validShutterSpeed and not validFnumber:
return -1.0

validRefFnumber = refFnumber > 0.0 and math.isfinite(refFnumber)

if not validShutterSpeed:
shutterSpeed = 1.0 / 200.0

if not validFnumber:
if validRefFnumber:
fnumber = refFnumber
else:
fnumber = 2.0

lRefFnumber = refFnumber
if not validRefFnumber:
lRefFnumber = fnumber

isoToAperture = 1.0
if iso > 1e-6 and refIso > 1e-6:
isoToAperture = math.sqrt(iso / refIso)

newFnumber = fnumber * isoToAperture
expIncrease = (lRefFnumber / newFnumber) * (lRefFnumber / newFnumber)

return shutterSpeed * expIncrease
obj = avsfmdata.ExposureSetting(shutterSpeed, fnumber, iso)
return obj.getExposure()
100 changes: 14 additions & 86 deletions meshroom/nodes/aliceVision/LdrToHdrMerge.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import math
from collections import Counter

from pyalicevision import sfmData as avsfmdata
from pyalicevision import hdr as avhdr

from meshroom.core import desc
from meshroom.core.utils import COLORSPACES, EXR_STORAGE_DATA_TYPE, VERBOSE_LEVEL

Expand Down Expand Up @@ -278,7 +281,7 @@ def update(cls, node):
node.nbBrackets.value = 0
return

inputs = []
inputs = avhdr.vectorli()
for viewpoint in viewpoints:
jsonMetadata = viewpoint.metadata.value
if not jsonMetadata:
Expand All @@ -305,100 +308,25 @@ def update(cls, node):
# We assume that there is no multi-bracketing, so nothing to do.
node.nbBrackets.value = 1
return
inputs.append((viewpoint.path.value, (float(fnumber), float(shutterSpeed), float(iso))))
inputs.sort()

exposureGroups = []
exposures = []
prevFnumber = 0.0
prevShutterSpeed = 0.0
prevIso = 0.0
prevPath = None # Stores the dirname of the previous parsed image
prevExposure = None
newGroup = False # True if a new exposure group needs to be created (useful when there are several datasets)
for path, exp in inputs:
# If the dirname of the previous image and the dirname of the current image do not match, this means that the
# dataset that is being parsed has changed. A new group needs to be created but will fail to be detected in the
# next "if" statement if the new dataset's exposure levels are different. Setting "newGroup" to True prevents this
# from happening.
if prevPath is not None and prevPath != os.path.dirname(path):
newGroup = True

currentExposure = LdrToHdrMerge.getExposure(exp)

# Create a new group if the current image's exposure level is smaller than the previous image's, or
# if a new dataset has been detected (with a change in the path of the images).
if prevExposure and currentExposure < prevExposure or newGroup:
exposureGroups.append(exposures)
exposures = [exp]
else:
exposures.append(exp)
exposure = LdrToHdrMerge.getExposure((float(fnumber), float(shutterSpeed), float(iso)))

prevPath = os.path.dirname(path)
prevExposure = currentExposure
newGroup = False
obj = avhdr.LuminanceInfo(viewpoint.viewId.value,viewpoint.path.value, exposure)
inputs.append(obj)

exposureGroups.append(exposures)
obj = avhdr.estimateGroups(inputs)

exposures = None
bracketSizes = Counter()
if len(exposureGroups) == 1:
if len(set(exposureGroups[0])) == 1:
# Single exposure and multiple views
node.nbBrackets.value = 1
else:
# Single view and multiple exposures
node.nbBrackets.value = len(exposureGroups[0])
else:
for expGroup in exposureGroups:
bracketSizes[len(expGroup)] += 1

if len(bracketSizes) == 0:
node.nbBrackets.value = 0
else:
bestTuple = None
for tuple in bracketSizes.most_common():
if bestTuple is None or tuple[1] > bestTuple[1]:
bestTuple = tuple
elif tuple[1] == bestTuple[1]:
bestTuple = tuple if tuple[0] > bestTuple[0] else bestTuple
if len(obj) == 0:
node.nbBrackets.value = 0
return

bestBracketSize = bestTuple[0]
node.nbBrackets.value = bestBracketSize
node.nbBrackets.value = len(obj[0])

@staticmethod
def getExposure(exp, refIso = 100.0, refFnumber = 1.0):
fnumber, shutterSpeed, iso = exp

validShutterSpeed = shutterSpeed > 0.0 and math.isfinite(shutterSpeed)
validFnumber = fnumber > 0.0 and math.isfinite(fnumber)

if not validShutterSpeed and not validFnumber:
return -1.0

validRefFnumber = refFnumber > 0.0 and math.isfinite(refFnumber)

if not validShutterSpeed:
shutterSpeed = 1.0 / 200.0

if not validFnumber:
if validRefFnumber:
fnumber = refFnumber
else:
fnumber = 2.0

lRefFnumber = refFnumber
if not validRefFnumber:
lRefFnumber = fnumber

isoToAperture = 1.0
if iso > 1e-6 and refIso > 1e-6:
isoToAperture = math.sqrt(iso / refIso)

newFnumber = fnumber * isoToAperture
expIncrease = (lRefFnumber / newFnumber) * (lRefFnumber / newFnumber)

return shutterSpeed * expIncrease
obj = avsfmdata.ExposureSetting(shutterSpeed, fnumber, iso)
return obj.getExposure()

def processChunk(self, chunk):
# Trick to avoid sending --nbBrackets to the command line when the bracket detection is automatic.
Expand Down
104 changes: 17 additions & 87 deletions meshroom/nodes/aliceVision/LdrToHdrSampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import os
from collections import Counter

from pyalicevision import sfmData as avsfmdata
from pyalicevision import hdr as avhdr

from meshroom.core import desc
from meshroom.core.utils import COLORSPACES, VERBOSE_LEVEL

Expand Down Expand Up @@ -231,7 +234,7 @@ def update(cls, node):
node.nbBrackets.value = 0
return

inputs = []
inputs = avhdr.vectorli()
for viewpoint in viewpoints:
jsonMetadata = viewpoint.metadata.value
if not jsonMetadata:
Expand All @@ -258,99 +261,26 @@ def update(cls, node):
# We assume that there is no multi-bracketing, so nothing to do.
node.nbBrackets.value = 1
return
inputs.append((viewpoint.path.value, (float(fnumber), float(shutterSpeed), float(iso))))
inputs.sort()

exposureGroups = []
exposures = []
prevFnumber = 0.0
prevShutterSpeed = 0.0
prevIso = 0.0
prevPath = None # Stores the dirname of the previous parsed image
prevExposure = None
newGroup = False # True if a new exposure group needs to be created (useful when there are several datasets)
for path, exp in inputs:
# If the dirname of the previous image and the dirname of the current image do not match, this means that the
# dataset that is being parsed has changed. A new group needs to be created but will fail to be detected in the
# next "if" statement if the new dataset's exposure levels are different. Setting "newGroup" to True prevents this
# from happening.
if prevPath is not None and prevPath != os.path.dirname(path):
newGroup = True

currentExposure = LdrToHdrSampling.getExposure(exp)

# Create a new group if the current image's exposure level is smaller than the previous image's, or
# if a new dataset has been detected (with a change in the path of the images).
if prevExposure and currentExposure < prevExposure or newGroup:
exposureGroups.append(exposures)
exposures = [exp]
else:
exposures.append(exp)
exposure = LdrToHdrSampling.getExposure((float(fnumber), float(shutterSpeed), float(iso)))

prevPath = os.path.dirname(path)
prevExposure = currentExposure
newGroup = False
obj = avhdr.LuminanceInfo(viewpoint.viewId.value,viewpoint.path.value, exposure)
inputs.append(obj)

exposureGroups.append(exposures)
obj = avhdr.estimateGroups(inputs)

exposures = None
bracketSizes = Counter()
if len(exposureGroups) == 1:
if len(set(exposureGroups[0])) == 1:
# Single exposure and multiple views
node.nbBrackets.value = 1
else:
# Single view and multiple exposures
node.nbBrackets.value = len(exposureGroups[0])
else:
for expGroup in exposureGroups:
bracketSizes[len(expGroup)] += 1
if len(obj) == 0:
node.nbBrackets.value = 0
return

if len(bracketSizes) == 0:
node.nbBrackets.value = 0
else:
bestTuple = None
for tuple in bracketSizes.most_common():
if bestTuple is None or tuple[1] > bestTuple[1]:
bestTuple = tuple
elif tuple[1] == bestTuple[1]:
bestTuple = tuple if tuple[0] > bestTuple[0] else bestTuple
bracketSize = len(obj[0])
bracketCount = len(obj)

bestBracketSize = bestTuple[0]
bestCount = bestTuple[1]
node.outliersNb = len(inputs) - (bestBracketSize * bestCount) # Compute number of outliers
node.nbBrackets.value = bestBracketSize
node.nbBrackets.value = bracketSize
node.outliersNb = len(inputs) - (bracketSize * bracketCount)

@staticmethod
def getExposure(exp, refIso = 100.0, refFnumber = 1.0):
fnumber, shutterSpeed, iso = exp

validShutterSpeed = shutterSpeed > 0.0 and math.isfinite(shutterSpeed)
validFnumber = fnumber > 0.0 and math.isfinite(fnumber)

if not validShutterSpeed and not validFnumber:
return -1.0

validRefFnumber = refFnumber > 0.0 and math.isfinite(refFnumber)

if not validShutterSpeed:
shutterSpeed = 1.0 / 200.0

if not validFnumber:
if validRefFnumber:
fnumber = refFnumber
else:
fnumber = 2.0

lRefFnumber = refFnumber
if not validRefFnumber:
lRefFnumber = fnumber

isoToAperture = 1.0
if iso > 1e-6 and refIso > 1e-6:
isoToAperture = math.sqrt(iso / refIso)

newFnumber = fnumber * isoToAperture
expIncrease = (lRefFnumber / newFnumber) * (lRefFnumber / newFnumber)

return shutterSpeed * expIncrease
obj = avsfmdata.ExposureSetting(shutterSpeed, fnumber, iso)
return obj.getExposure()

0 comments on commit 1571ee0

Please sign in to comment.