mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-07-28 14:07:47 +02:00
Use bindings for hdr brackets estimation
This commit is contained in:
parent
ebcbf9dace
commit
c78834b6d2
3 changed files with 45 additions and 259 deletions
|
@ -5,6 +5,9 @@ import math
|
||||||
import os
|
import os
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
|
||||||
|
from pyalicevision import sfmData as avsfmdata
|
||||||
|
from pyalicevision import hdr as avhdr
|
||||||
|
|
||||||
from meshroom.core import desc
|
from meshroom.core import desc
|
||||||
from meshroom.core.utils import COLORSPACES, VERBOSE_LEVEL
|
from meshroom.core.utils import COLORSPACES, VERBOSE_LEVEL
|
||||||
|
|
||||||
|
@ -205,7 +208,7 @@ Calibrate LDR to HDR response curve from samples.
|
||||||
node.nbBrackets.value = 0
|
node.nbBrackets.value = 0
|
||||||
return
|
return
|
||||||
|
|
||||||
inputs = []
|
inputs = avhdr.vectorli()
|
||||||
for viewpoint in viewpoints:
|
for viewpoint in viewpoints:
|
||||||
jsonMetadata = viewpoint.metadata.value
|
jsonMetadata = viewpoint.metadata.value
|
||||||
if not jsonMetadata:
|
if not jsonMetadata:
|
||||||
|
@ -232,97 +235,22 @@ Calibrate LDR to HDR response curve from samples.
|
||||||
# We assume that there is no multi-bracketing, so nothing to do.
|
# We assume that there is no multi-bracketing, so nothing to do.
|
||||||
node.nbBrackets.value = 1
|
node.nbBrackets.value = 1
|
||||||
return
|
return
|
||||||
inputs.append((viewpoint.path.value, (float(fnumber), float(shutterSpeed), float(iso))))
|
|
||||||
inputs.sort()
|
|
||||||
|
|
||||||
exposureGroups = []
|
exposure = LdrToHdrCalibration.getExposure((float(fnumber), float(shutterSpeed), float(iso)))
|
||||||
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)
|
obj = avhdr.LuminanceInfo(viewpoint.viewId.value,viewpoint.path.value, exposure)
|
||||||
|
inputs.append(obj)
|
||||||
|
|
||||||
# Create a new group if the current image's exposure level is smaller than the previous image's, or
|
obj = avhdr.estimateGroups(inputs)
|
||||||
# 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)
|
|
||||||
|
|
||||||
prevPath = os.path.dirname(path)
|
if len(obj) == 0:
|
||||||
prevExposure = currentExposure
|
|
||||||
newGroup = False
|
|
||||||
|
|
||||||
exposureGroups.append(exposures)
|
|
||||||
|
|
||||||
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
|
node.nbBrackets.value = 0
|
||||||
else:
|
return
|
||||||
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
|
|
||||||
|
|
||||||
bestBracketSize = bestTuple[0]
|
node.nbBrackets.value = len(obj[0])
|
||||||
node.nbBrackets.value = bestBracketSize
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getExposure(exp, refIso = 100.0, refFnumber = 1.0):
|
def getExposure(exp, refIso = 100.0, refFnumber = 1.0):
|
||||||
fnumber, shutterSpeed, iso = exp
|
fnumber, shutterSpeed, iso = exp
|
||||||
|
obj = avsfmdata.ExposureSetting(shutterSpeed, fnumber, iso)
|
||||||
validShutterSpeed = shutterSpeed > 0.0 and math.isfinite(shutterSpeed)
|
return obj.getExposure()
|
||||||
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
|
|
||||||
|
|
|
@ -5,6 +5,9 @@ import os
|
||||||
import math
|
import math
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
|
||||||
|
from pyalicevision import sfmData as avsfmdata
|
||||||
|
from pyalicevision import hdr as avhdr
|
||||||
|
|
||||||
from meshroom.core import desc
|
from meshroom.core import desc
|
||||||
from meshroom.core.utils import COLORSPACES, EXR_STORAGE_DATA_TYPE, VERBOSE_LEVEL
|
from meshroom.core.utils import COLORSPACES, EXR_STORAGE_DATA_TYPE, VERBOSE_LEVEL
|
||||||
|
|
||||||
|
@ -278,7 +281,7 @@ Merge LDR images into HDR images.
|
||||||
node.nbBrackets.value = 0
|
node.nbBrackets.value = 0
|
||||||
return
|
return
|
||||||
|
|
||||||
inputs = []
|
inputs = avhdr.vectorli()
|
||||||
for viewpoint in viewpoints:
|
for viewpoint in viewpoints:
|
||||||
jsonMetadata = viewpoint.metadata.value
|
jsonMetadata = viewpoint.metadata.value
|
||||||
if not jsonMetadata:
|
if not jsonMetadata:
|
||||||
|
@ -305,100 +308,25 @@ Merge LDR images into HDR images.
|
||||||
# We assume that there is no multi-bracketing, so nothing to do.
|
# We assume that there is no multi-bracketing, so nothing to do.
|
||||||
node.nbBrackets.value = 1
|
node.nbBrackets.value = 1
|
||||||
return
|
return
|
||||||
inputs.append((viewpoint.path.value, (float(fnumber), float(shutterSpeed), float(iso))))
|
|
||||||
inputs.sort()
|
|
||||||
|
|
||||||
exposureGroups = []
|
exposure = LdrToHdrMerge.getExposure((float(fnumber), float(shutterSpeed), float(iso)))
|
||||||
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)
|
obj = avhdr.LuminanceInfo(viewpoint.viewId.value,viewpoint.path.value, exposure)
|
||||||
|
inputs.append(obj)
|
||||||
|
|
||||||
# Create a new group if the current image's exposure level is smaller than the previous image's, or
|
obj = avhdr.estimateGroups(inputs)
|
||||||
# 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)
|
|
||||||
|
|
||||||
prevPath = os.path.dirname(path)
|
if len(obj) == 0:
|
||||||
prevExposure = currentExposure
|
|
||||||
newGroup = False
|
|
||||||
|
|
||||||
exposureGroups.append(exposures)
|
|
||||||
|
|
||||||
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
|
node.nbBrackets.value = 0
|
||||||
else:
|
return
|
||||||
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
|
|
||||||
|
|
||||||
bestBracketSize = bestTuple[0]
|
node.nbBrackets.value = len(obj[0])
|
||||||
node.nbBrackets.value = bestBracketSize
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getExposure(exp, refIso = 100.0, refFnumber = 1.0):
|
def getExposure(exp, refIso = 100.0, refFnumber = 1.0):
|
||||||
fnumber, shutterSpeed, iso = exp
|
fnumber, shutterSpeed, iso = exp
|
||||||
|
obj = avsfmdata.ExposureSetting(shutterSpeed, fnumber, iso)
|
||||||
validShutterSpeed = shutterSpeed > 0.0 and math.isfinite(shutterSpeed)
|
return obj.getExposure()
|
||||||
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
|
|
||||||
|
|
||||||
def processChunk(self, chunk):
|
def processChunk(self, chunk):
|
||||||
# Trick to avoid sending --nbBrackets to the command line when the bracket detection is automatic.
|
# Trick to avoid sending --nbBrackets to the command line when the bracket detection is automatic.
|
||||||
|
|
|
@ -5,6 +5,9 @@ import math
|
||||||
import os
|
import os
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
|
||||||
|
from pyalicevision import sfmData as avsfmdata
|
||||||
|
from pyalicevision import hdr as avhdr
|
||||||
|
|
||||||
from meshroom.core import desc
|
from meshroom.core import desc
|
||||||
from meshroom.core.utils import COLORSPACES, VERBOSE_LEVEL
|
from meshroom.core.utils import COLORSPACES, VERBOSE_LEVEL
|
||||||
|
|
||||||
|
@ -231,7 +234,7 @@ Sample pixels from Low range images for HDR creation.
|
||||||
node.nbBrackets.value = 0
|
node.nbBrackets.value = 0
|
||||||
return
|
return
|
||||||
|
|
||||||
inputs = []
|
inputs = avhdr.vectorli()
|
||||||
for viewpoint in viewpoints:
|
for viewpoint in viewpoints:
|
||||||
jsonMetadata = viewpoint.metadata.value
|
jsonMetadata = viewpoint.metadata.value
|
||||||
if not jsonMetadata:
|
if not jsonMetadata:
|
||||||
|
@ -258,99 +261,26 @@ Sample pixels from Low range images for HDR creation.
|
||||||
# We assume that there is no multi-bracketing, so nothing to do.
|
# We assume that there is no multi-bracketing, so nothing to do.
|
||||||
node.nbBrackets.value = 1
|
node.nbBrackets.value = 1
|
||||||
return
|
return
|
||||||
inputs.append((viewpoint.path.value, (float(fnumber), float(shutterSpeed), float(iso))))
|
|
||||||
inputs.sort()
|
|
||||||
|
|
||||||
exposureGroups = []
|
exposure = LdrToHdrSampling.getExposure((float(fnumber), float(shutterSpeed), float(iso)))
|
||||||
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)
|
obj = avhdr.LuminanceInfo(viewpoint.viewId.value,viewpoint.path.value, exposure)
|
||||||
|
inputs.append(obj)
|
||||||
|
|
||||||
# Create a new group if the current image's exposure level is smaller than the previous image's, or
|
obj = avhdr.estimateGroups(inputs)
|
||||||
# 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)
|
|
||||||
|
|
||||||
prevPath = os.path.dirname(path)
|
if len(obj) == 0:
|
||||||
prevExposure = currentExposure
|
|
||||||
newGroup = False
|
|
||||||
|
|
||||||
exposureGroups.append(exposures)
|
|
||||||
|
|
||||||
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
|
node.nbBrackets.value = 0
|
||||||
else:
|
return
|
||||||
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
|
|
||||||
|
|
||||||
bestBracketSize = bestTuple[0]
|
bracketSize = len(obj[0])
|
||||||
bestCount = bestTuple[1]
|
bracketCount = len(obj)
|
||||||
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
|
@staticmethod
|
||||||
def getExposure(exp, refIso = 100.0, refFnumber = 1.0):
|
def getExposure(exp, refIso = 100.0, refFnumber = 1.0):
|
||||||
fnumber, shutterSpeed, iso = exp
|
fnumber, shutterSpeed, iso = exp
|
||||||
|
obj = avsfmdata.ExposureSetting(shutterSpeed, fnumber, iso)
|
||||||
validShutterSpeed = shutterSpeed > 0.0 and math.isfinite(shutterSpeed)
|
return obj.getExposure()
|
||||||
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
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue