[ui] Add visualisation for automatically detected fisheye circle

This commit is contained in:
Fabien Castan 2020-03-23 19:25:57 +01:00
parent b7b1f49bc5
commit bb60c9b78d
4 changed files with 72 additions and 12 deletions

View file

@ -45,6 +45,13 @@ class PanoramaInit(desc.CommandLineNode):
value=False,
uid=[0],
),
desc.BoolParam(
name='estimateFisheyeCircle',
label='Estimate Fisheye Circle',
description='Automatically estimate the Fisheye Circle center and radius instead of using user values.',
value=True,
uid=[0],
),
desc.GroupAttribute(
name="fisheyeCenterOffset",
label="Fisheye Center",

View file

@ -3,6 +3,8 @@ import QtQuick 2.11
Rectangle {
id: root
property bool readOnly: false
signal moved()
signal incrementRadius(real radiusOffset)
@ -10,7 +12,20 @@ Rectangle {
height: width
color: "transparent"
border.width: 5
border.color: "yellow"
border.color: readOnly ? "green" : "yellow"
Rectangle {
color: parent.color
anchors.centerIn: parent
width: 20
height: 2
}
Rectangle {
color: parent.color
anchors.centerIn: parent
width: 2
height: 20
}
Behavior on x {
NumberAnimation {
@ -32,11 +47,15 @@ Rectangle {
MouseArea {
id: mArea
enabled: !root.readOnly
anchors.fill: parent
cursorShape: controlModifierEnabled ? Qt.SizeBDiagCursor : (pressed ? Qt.ClosedHandCursor : Qt.OpenHandCursor)
cursorShape: root.readOnly ? Qt.ArrowCursor : (controlModifierEnabled ? Qt.SizeBDiagCursor : (pressed ? Qt.ClosedHandCursor : Qt.OpenHandCursor))
propagateComposedEvents: true
property bool controlModifierEnabled: false
onPositionChanged: {
mArea.controlModifierEnabled = (mouse.modifiers & Qt.ControlModifier)
mouse.accepted = false;
}
acceptedButtons: Qt.LeftButton
hoverEnabled: true

View file

@ -249,20 +249,31 @@ FocusScope {
// note: use a Loader to evaluate if a PanoramaInit node exist and displayFisheyeCircle checked at runtime
Loader {
anchors.centerIn: parent
active: (_reconstruction.panoramaInit && displayFisheyeCircleLoader.checked)
active: (displayFisheyeCircleLoader.checked && _reconstruction.panoramaInit)
sourceComponent: CircleGizmo {
x: _reconstruction.panoramaInit.attribute("fisheyeCenterOffset.fisheyeCenterOffset_x").value
y: _reconstruction.panoramaInit.attribute("fisheyeCenterOffset.fisheyeCenterOffset_y").value
property real fisheyeRadius: _reconstruction.panoramaInit.attribute("fisheyeRadius").value
radius: (imgContainer.image ? Math.min(imgContainer.image.width, imgContainer.image.height) : 1.0) * 0.5 * (fisheyeRadius * 0.01)
border.width: Math.max(1, (3.0 / imgContainer.scale))
property bool useAuto: _reconstruction.panoramaInit.attribute("estimateFisheyeCircle").value
readOnly: useAuto
visible: (!useAuto) || _reconstruction.panoramaInit.isComputed
property real userFisheyeRadius: _reconstruction.panoramaInit.attribute("fisheyeRadius").value
property variant fisheyeAutoParams: _reconstruction.getAutoFisheyeCircle(_reconstruction.panoramaInit)
x: useAuto ? (fisheyeAutoParams.x - imgContainer.image.width * 0.5) : _reconstruction.panoramaInit.attribute("fisheyeCenterOffset.fisheyeCenterOffset_x").value
y: useAuto ? (fisheyeAutoParams.y - imgContainer.image.height * 0.5) : _reconstruction.panoramaInit.attribute("fisheyeCenterOffset.fisheyeCenterOffset_y").value
radius: useAuto ? fisheyeAutoParams.z : ((imgContainer.image ? Math.min(imgContainer.image.width, imgContainer.image.height) : 1.0) * 0.5 * (userFisheyeRadius * 0.01))
border.width: Math.max(1, (3.0 / imgContainer.scale))
onMoved: {
_reconstruction.setAttribute(_reconstruction.panoramaInit.attribute("fisheyeCenterOffset.fisheyeCenterOffset_x"), x)
_reconstruction.setAttribute(_reconstruction.panoramaInit.attribute("fisheyeCenterOffset.fisheyeCenterOffset_y"), y)
if(!useAuto)
{
_reconstruction.setAttribute(_reconstruction.panoramaInit.attribute("fisheyeCenterOffset.fisheyeCenterOffset_x"), x)
_reconstruction.setAttribute(_reconstruction.panoramaInit.attribute("fisheyeCenterOffset.fisheyeCenterOffset_y"), y)
}
}
onIncrementRadius: {
_reconstruction.setAttribute(_reconstruction.panoramaInit.attribute("fisheyeRadius"), _reconstruction.panoramaInit.attribute("fisheyeRadius").value + radiusOffset)
if(!useAuto)
{
_reconstruction.setAttribute(_reconstruction.panoramaInit.attribute("fisheyeRadius"), _reconstruction.panoramaInit.attribute("fisheyeRadius").value + radiusOffset)
}
}
}
}
@ -406,7 +417,7 @@ FocusScope {
}
MaterialToolButton {
id: displayFisheyeCircleLoader
ToolTip.text: "Display Fisheye Circle"
ToolTip.text: "Display Fisheye Circle: " + (_reconstruction.panoramaInit ? _reconstruction.panoramaInit.label : "No Node")
text: MaterialIcons.panorama_fish_eye
font.pointSize: 11
Layout.minimumWidth: 0

View file

@ -559,6 +559,29 @@ class Reconstruction(UIGraph):
tmpCameraInit = Node("CameraInit", viewpoints=views, intrinsics=intrinsics)
self.hdrCameraInit = tmpCameraInit
@Slot(QObject, result=QVector3D)
def getAutoFisheyeCircle(self, panoramaInit):
if not panoramaInit or not panoramaInit.isComputed:
return QVector3D(0.0, 0.0, 0.0)
if not panoramaInit.attribute("estimateFisheyeCircle").value:
return QVector3D(0.0, 0.0, 0.0)
sfmFile = panoramaInit.attribute('outSfMDataFilename').value
if not os.path.exists(sfmFile):
return QVector3D(0.0, 0.0, 0.0)
import io # use io.open for Python2/3 compatibility (allow to specify encoding + errors handling)
# skip decoding errors to avoid potential exceptions due to non utf-8 characters in images metadata
with io.open(sfmFile, 'r', encoding='utf-8', errors='ignore') as f:
data = json.load(f)
intrinsics = data.get('intrinsics', [])
if len(intrinsics) == 0:
return QVector3D(0.0, 0.0, 0.0)
intrinsic = intrinsics[0]
res = QVector3D(float(intrinsic.get("fisheyeCenterX", 0.0)), float(intrinsic.get("fisheyeCenterY", 0.0)), float(intrinsic.get("fisheyeRadius", 0.0)))
return res
def updatePanoramaInitNode(self):
""" Set the current FeatureExtraction node based on the current CameraInit node. """
self.panoramaInit = self.lastNodeOfType('PanoramaInit', self.cameraInit) if self.cameraInit else None