<!--
    This tutorial shows a basic sample of augmented reality.
    This exhibits:
      - how to detect an ArUco marker,
      - how to compute the pose of a marker,
      - how to make a basic augmented-reality render (we superimpose a cube onto the ArUco marker)
      - how to undistort a video according to the camera intrinsic parameters
      - how to distort a 3D render according to the camera intrinsic parameters
      - how to synchronize efficiently a video process pipeline with the video playback using SSignalGate

    To use this application, you must open a calibration and a video. Samples are provided in the module folder
    of the application, `share/sight/Tuto17SimpleAR` on Linux and `share\Tuto17SimpleAR` on Windows:
      - calibration.xml
      - aruco_tag.m4v
-->
<plugin id="Tuto17SimpleAR" >

    <requirement id="sight::module::ui::base" />
    <requirement id="sight::module::viz::scene3d" />
    <requirement id="sight::module::ui::qt" />
    <requirement id="sight::module::service" />
    <requirement id="sight::module::ui::base" />

    <extension implements="sight::service::extension::AppConfig" >
        <id>Tuto17SimpleAR_AppCfg</id>
        <config>

            <!-- ******************************* Objects declaration ****************************** -->

            <!-- Series of camera calibration -->
            <object uid="cameraSeries" type="sight::data::CameraSeries" />
            <!-- Camera calibration, deferred because it is extracted from the series -->
            <object uid="camera" type="sight::data::Camera" src="deferred" />
            <!-- Frame timeline used to buffer the output of the video grabber -->
            <object uid="frameTL" type="sight::data::FrameTL" />
            <!-- Video frame that is used for the current iteration -->
            <object uid="sourceFrame" type="sight::data::Image" />
            <!-- Map containing all detected markers in the current frame -->
            <object uid="markerMap" type="sight::data::MarkerMap" />
            <!-- Marker matrix in the camera world -->
            <object uid="markerToCamera" type="sight::data::Matrix4" />
            <!-- Camera matrix in the marker world -->
            <object uid="cameraToMarker" type="sight::data::Matrix4" />
            <!-- Cube superimposed on the video at the marker location -->
            <object uid="cubeMesh" type="sight::data::Mesh" />
            <object uid="undistortMap" type="sight::data::Image" />
            <object uid="distortMap" type="sight::data::Image" />
            <object uid="cubeMaterial" type="sight::data::Material"/>

            <!-- ******************************* UI declaration *********************************** -->

            <!-- declaration of the views, menu and toolbar -->
            <service uid="mainFrame" type="sight::module::ui::base::SFrame" >
                <gui>
                    <frame>
                        <name>Tuto17SimpleAR</name>
                        <icon>Tuto17SimpleAR/app.ico</icon>
                    </frame>
                    <toolBar/>
                </gui>
                <registry>
                    <toolBar sid="toolbarView" start="true" />
                    <view sid="cameraView" start="true" />
                </registry>
            </service>

            <service uid="toolbarView" type="sight::module::ui::base::SToolBar" >
                <gui>
                    <layout>
                        <menuItem name="Load Calibration" icon="sight::module::ui::flaticons/YellowCamera.svg" />
                        <editor/>
                        <separator/>
                        <menuItem name="Start" icon="sight::module::ui::flaticons/GreenStart.svg" shortcut="Space" />
                        <menuItem name="Pause" icon="sight::module::ui::flaticons/OrangePause.svg" shortcut="Space" />
                        <menuItem name="Play" icon="sight::module::ui::flaticons/GreenStart.svg" shortcut="Space" />
                        <menuItem name="Stop" icon="sight::module::ui::flaticons/RedStop.svg" />
                        <menuItem name="Loop" icon="sight::module::ui::flaticons/OrangeLoop.svg" style="check" />
                        <separator />
                        <menuItem name="Enable video image undistortion" icon="sight::module::ui::flaticons/YellowUndistortion.svg" />
                        <menuItem name="Disable video image undistortion" icon="sight::module::ui::flaticons/YellowDistortion.svg" />
                        <menuItem name="Enable 3D rendering distortion" icon="sight::module::ui::flaticons/YellowDistortion.svg" />
                        <menuItem name="Disable 3D rendering distortion" icon="sight::module::ui::flaticons/YellowUndistortion.svg" />
                        <separator/>
                        <menuItem name="Show Mesh on tag" icon="sight::module::ui::flaticons/Mask.svg" style="check" />
                        <separator/>
                        <menuItem name="Settings" icon="sight::module::ui::flaticons/BlueParameters.svg" style="check" />
                    </layout>
                </gui>
                <registry>
                    <menuItem sid="loadCalibAct" start="true" />
                    <editor sid="videoSelectorSrv" />
                    <menuItem sid="startVideoAct" start="true" />
                    <menuItem sid="pauseVideoAct" start="true" />
                    <menuItem sid="resumeVideoAct" start="true" />
                    <menuItem sid="stopVideoAct" start="true" />
                    <menuItem sid="loopVideoAct" start="true" />
                    <menuItem sid="startUndistortAct" start="true" />
                    <menuItem sid="stopUndistortAct" start="true" />
                    <menuItem sid="startDistortAct" start="true" />
                    <menuItem sid="stopDistortAct" start="true" />
                    <menuItem sid="showMeshAct" start="true" />
                    <menuItem sid="showParametersAct" start="true" />
                </registry>
            </service>

            <service uid="cameraView" type="sight::module::ui::base::SView" >
                <gui>
                    <layout type="sight::ui::base::LineLayoutManager" >
                        <orientation value="horizontal" />
                        <view proportion="1" />
                        <view proportion="0" backgroundColor="#36393E" />
                    </layout>
                </gui>
                <registry>
                    <view sid="videoView" start="true" />
                    <view sid="parametersView" start="true" />
                </registry>
            </service>

            <service uid="videoView" type="sight::module::ui::base::SView" >
                <gui>
                    <layout type="sight::ui::base::LineLayoutManager" >
                        <orientation value="vertical" />
                        <view proportion="3" />
                        <view proportion="0" backgroundColor="#36393E" />
                    </layout>
                </gui>
                <registry>
                    <view sid="genericSceneSrv" />
                    <view sid="errorLabelSrv" start="true" />
                </registry>
            </service>

            <service uid="parametersView" type="sight::module::ui::base::SView" >
                <gui>
                    <layout type="sight::ui::base::LineLayoutManager" >
                        <orientation value="vertical" />
                        <view proportion="3" />
                        <view proportion="2" />
                        <view proportion="1" />
                        <spacer/>
                    </layout>
                </gui>
                <registry>
                    <view sid="arucoParamametersSrv" start="true" />
                    <view sid="reprojectionParamametersSrv" start="true" />
                    <view sid="materialOpacityEditor" start="true" />
                </registry>
            </service>

            <!-- ************************************* Action ************************************ -->

            <!-- declaration of actions/slot callers -->
            <service uid="showParametersAct" type="sight::module::ui::base::SModifyLayout" >
                <config>
                    <show_or_hide sid="parametersView" />
                </config>
            </service>

            <service uid="loadCalibAct" type="sight::module::ui::base::com::SSlotCaller" >
                <slots>
                    <slot>calibrationReaderSrv/update</slot>
                </slots>
            </service>

            <!-- Start the frame grabber -->
            <service uid="startVideoAct" type="sight::module::ui::base::com::SSlotCaller" >
                <slots>
                    <slot>videoGrabberSrv/startCamera</slot>
                </slots>
                <state executable="false" />
            </service>

            <!-- Pause the frame grabber -->
            <service uid="pauseVideoAct" type="sight::module::ui::base::com::SSlotCaller" >
                <slots>
                    <slot>videoGrabberSrv/pauseCamera</slot>
                    <slot>resumeVideoAct/show</slot>
                    <slot>pauseVideoAct/hide</slot>
                </slots>
                <state visible="false" />
            </service>

            <!-- Resume the frame grabber -->
            <service uid="resumeVideoAct" type="sight::module::ui::base::com::SSlotCaller" >
                <slots>
                    <slot>videoGrabberSrv/pauseCamera</slot>
                    <slot>resumeVideoAct/hide</slot>
                    <slot>pauseVideoAct/show</slot>
                </slots>
                <state visible="false" />
            </service>

            <!-- Stop the frame grabber -->
            <service uid="stopVideoAct" type="sight::module::ui::base::com::SSlotCaller" >
                <slots>
                    <slot>videoGrabberSrv/stopCamera</slot>
                    <slot>startVideoAct/show</slot>
                    <slot>resumeVideoAct/hide</slot>
                    <slot>pauseVideoAct/hide</slot>
                    <slot>stopVideoAct/setInexecutable</slot>
                    <slot>loopVideoAct/setInexecutable</slot>
                    <slot>loopVideoAct/deactivate</slot>
                </slots>
                <state executable="false" />
            </service>

            <!-- Loop the frame grabber -->
            <service uid="loopVideoAct" type="sight::module::ui::base::com::SSlotCaller" >
                <slots>
                    <slot>videoGrabberSrv/loopVideo</slot>
                </slots>
                <state executable="false" />
            </service>

            <service uid="startUndistortAct" type="sight::module::ui::base::com::SSlotCaller" >
                <slots>
                    <slot>undistortAdp/show</slot>
                    <slot>startDistortAct/setInexecutable</slot>
                    <slot>startUndistortAct/hide</slot>
                    <slot>stopUndistortAct/show</slot>
                </slots>
            </service>

            <service uid="stopUndistortAct" type="sight::module::ui::base::com::SSlotCaller" >
                <state visible="false" />
                <slots>
                    <slot>undistortAdp/hide</slot>
                    <slot>startDistortAct/setExecutable</slot>
                    <slot>startUndistortAct/show</slot>
                    <slot>stopUndistortAct/hide</slot>
                </slots>
            </service>

            <service uid="startDistortAct" type="sight::module::ui::base::com::SSlotCaller" >
                <slots>
                    <slot>distortAdp/show</slot>
                    <slot>startUndistortAct/setInexecutable</slot>
                    <slot>startDistortAct/hide</slot>
                    <slot>stopDistortAct/show</slot>
                </slots>
            </service>

            <service uid="stopDistortAct" type="sight::module::ui::base::com::SSlotCaller" >
                <state visible="false" />
                <slots>
                    <slot>distortAdp/hide</slot>
                    <slot>startUndistortAct/setExecutable</slot>
                    <slot>startDistortAct/show</slot>
                    <slot>stopDistortAct/hide</slot>
                </slots>
            </service>

            <service uid="showMeshAct" type="sight::module::ui::base::com::SBooleanSlotCaller" >
                <slots>
                    <slot>cubeAdp/updateVisibility</slot>
                </slots>
                <state active="true" />
            </service>

            <!-- ******************************* Begin Generic Scene ******************************* -->

            <!-- Scene in which the video and the 3D will be rendered -->
            <!-- In this tutorial, we move the camera and the marker mesh is fixed -->
            <service uid="genericSceneSrv" type="sight::viz::scene3d::SRender" >
                <!-- It is essential to use the 'sync' mode when doing AR -->
                <!-- In this mode, the renderer will wait for a signal to trigger the rendering -->
                <scene renderMode="sync" >
                    <background topColor="#36393E" bottomColor="#36393E" />

                    <layer id="video" order="1" compositors="Remap" transparency=""/>
                    <adaptor uid="videoAdp" />
                    <adaptor uid="undistortAdp" />

                    <layer id="default" order="3" compositors="Remap" transparency=""/>
                    <adaptor uid="axisAdp" />
                    <adaptor uid="cameraAdp" />
                    <adaptor uid="materialAdp" />
                    <adaptor uid="cubeAdp" />
                    <adaptor uid="distortAdp" />
                </scene>
            </service>

            <service uid="videoAdp" type="sight::module::viz::scene3d::adaptor::SVideo" autoConnect="true" >
                <in key="image" uid="sourceFrame" />
                <config layer="video" />
            </service>

            <service uid="undistortAdp" type="sight::module::viz::scene3d::adaptor::SCompositorParameter" autoConnect="true" >
                <inout key="parameter" uid="undistortMap" />
                <config layer="video" compositorName="Remap" parameter="u_map" shaderType="fragment" visible="false" />
            </service>

            <service uid="axisAdp" type="sight::module::viz::scene3d::adaptor::SAxis" >
                <config layer="default" length="30" origin="true" label="false" />
            </service>

            <!-- Camera for the 3D layer -->
            <service uid="cameraAdp" type="sight::module::viz::scene3d::adaptor::SCamera" autoConnect="true" >
                <inout key="transform" uid="cameraToMarker" />
                <in key="calibration" uid="camera" />
                <config layer="default" />
            </service>

            <service uid="materialAdp" type="sight::module::viz::scene3d::adaptor::SMaterial" autoConnect="true">
                <inout key="material" uid="cubeMaterial" />
                <config layer="default" materialName="cube" />
            </service>

            <!-- Cube displayed on top of the marker plane -->
            <service uid="cubeAdp" type="sight::module::viz::scene3d::adaptor::SMesh" autoConnect="true" >
                <in key="mesh" uid="cubeMesh" />
                <config layer="default" autoresetcamera="false" materialName="cube" />
            </service>

            <service uid="distortAdp" type="sight::module::viz::scene3d::adaptor::SCompositorParameter" autoConnect="true" >
                <inout key="parameter" uid="distortMap" />
                <config layer="default" compositorName="Remap" parameter="u_map" shaderType="fragment" visible="false" />
            </service>

            <!-- ************************************* Services ************************************ -->

            <service uid="loadMeshSrv" type="sight::module::io::vtk::SMeshReader" >
                <inout key="data" uid="cubeMesh" />
                <resource>Tuto17SimpleAR/cube_60.vtk</resource>
            </service>

            <!-- hide axis adaptor until a marker is found -->
            <service uid="hideAxisSrv" type="sight::module::ui::base::com::SBooleanSlotCaller" >
                <slots>
                    <slot>axisAdp/updateVisibility</slot>
                </slots>
            </service>

            <!-- Calibration reader (here OpenCV's XML/YAML) -->
            <service uid="calibrationReaderSrv" type="sight::module::io::vision::SOpenCVReader" >
                <inout key="data" uid="cameraSeries" />
            </service>

            <!-- extract the first sight::data::Camera from the sight::data::CameraSeries -->
            <service uid="extractCameraSrv" type="sight::module::data::SGetCamera" >
                <inout key="source" uid="cameraSeries" />
                <out group="camera" >
                    <key index="0" uid="camera" />
                </out>
            </service>

            <!-- GUI to handle aruco tracking parameters -->
            <service uid="arucoParamametersSrv" type="sight::module::ui::qt::SParameters" >
                <parameters>
                    <!-- show marker or not -->
                    <param type="bool" name="Show Marker" key="debugMode" defaultValue="true" />
                    <!--  do corner refinement or not. -->
                    <param type="bool" name="Corner refinement." key="corner" defaultValue="true" />
                    <!-- minimum window size for adaptive thresholding before finding contours -->
                    <param type="int" name="adpt. Threshold win size min" key="adaptiveThreshWinSizeMin" defaultValue="3" min="3" max="100" />
                    <!-- maximum window size for adaptive thresholding before finding contours -->
                    <param type="int" name="adpt. Threshold win size max" key="adaptiveThreshWinSizeMax" defaultValue="23" min="4" max="100" />
                    <!-- increments from adaptiveThreshWinSizeMin to adaptiveThreshWinSizeMax during the thresholding -->
                    <param type="int" name="adpt. Threshold win size step" key="adaptiveThreshWinSizeStep" defaultValue="10" min="1" max="100" />
                    <!-- constant for adaptive thresholding before finding contours -->
                    <param type="double" name="adpt. threshold constant" key="adaptiveThreshConstant" defaultValue="7." min="0." max="30." />
                    <!-- determine minimum perimeter for marker contour to be detected.
                        This is defined as a rate respect to the maximum dimension of the input image -->
                    <param type="double" name="Min. Marker Perimeter Rate" key="minMarkerPerimeterRate" defaultValue="0.03" min="0.01" max="1.0" />
                    <!-- determine maximum perimeter for marker contour to be detected.
                        This is defined as a rate respect to the maximum dimension of the input image -->
                    <param type="double" name="Max. Marker Perimeter Rate" key="maxMarkerPerimeterRate" defaultValue="4.0" min="1." max="10." />
                    <!-- minimum accuracy during the polygonal approximation process to determine which contours are squares -->
                    <param type="double" name="Polygonal Approx. Accuracy Rate" key="polygonalApproxAccuracyRate" defaultValue="0.03" min="0.01" max="1." />
                    <!-- minimum distance between corners for detected markers relative to its perimeter -->
                    <param type="double" name="Min. Corner Distance Rate" key="minCornerDistanceRate" defaultValue="0.01" min="0." max="1." />
                    <!-- minimum distance of any corner to the image border for detected markers (in pixels) -->
                    <param type="int" name="Min. Distance to Border" key="minDistanceToBorder" defaultValue="1" min="0" max="10" />
                    <!-- minimum mean distance beetween two marker corners to be considered similar,
                    so that the smaller one is removed. The rate is relative to the smaller perimeter of the two markers -->
                    <param type="double" name="Min. Marker Distance Rate" key="minMarkerDistanceRate" defaultValue="0.01" min="0." max="1." />
                    <!-- window size for the corner refinement process (in pixels) -->
                    <param type="int" name="Corner Refinement Win. Size" key="cornerRefinementWinSize" defaultValue="5" min="1" max="100" />
                    <!-- maximum number of iterations for stop criteria of the corner refinement process -->
                    <param type="int" name="Corner Refinement Max Iterations" key="cornerRefinementMaxIterations" defaultValue="30" min="1" max="10" />
                    <!-- minimum error for the stop cristeria of the corner refinement process -->
                    <param type="double" name="Corner Refinement Min. Accuracy" key="cornerRefinementMinAccuracy" defaultValue="0.1" min="0.01" max="10." />
                    <!-- number of bits of the marker border, i.e. marker border width -->
                    <param type="int" name="Marker Border Bits" key="markerBorderBits" defaultValue="1" min="1" max="100" />
                    <!-- number of bits (per dimension) for each cell of the marker when removing the perspective -->
                    <param type="int" name="Perspective Remove Pixel per Cell" key="perspectiveRemovePixelPerCell" defaultValue="8" min="1" max="32" />
                    <!-- width of the margin of pixels on each cell not considered for the determination of the cell bit.
                        Represents the rate respect to the total size of the cell,
                        i.e. perpectiveRemovePixelPerCel -->
                    <param type="double" name="Perspective Remove Ignored Margin Per Cell" key="perspectiveRemoveIgnoredMarginPerCell" defaultValue="0.13" min="0." max="1." />
                    <!-- maximum number of accepted erroneous bits in the border (i.e. number of allowed white bits in the border).
                        Represented as a rate respect to the total number of bits per marker -->
                    <param type="double" name="Max. Erroneous Bits In Border Rate" key="maxErroneousBitsInBorderRate" defaultValue="0.35" min="0." max="1." />
                    <!-- minimun standard deviation in pixels values during the decodification step to apply Otsu thresholding
                        (otherwise, all the bits are set to 0 or 1 depending on mean higher than 128 or not) -->
                    <param type="double" name="Min. Otsu Std. Dev." key="minOtsuStdDev" defaultValue="5.0" min="0." max="100." />
                    <!-- error correction rate respect to the maximun error correction capability for each dictionary -->
                    <param type="double" name="Error Correction Rate" key="errorCorrectionRate" defaultValue="0.6" min="0." max="1." />
                </parameters>
            </service>

            <service uid="reprojectionParamametersSrv" type="sight::module::ui::qt::SParameters" >
                <parameters>
                    <param type="bool" name="Show reprojection" key="display" defaultValue="true" />
                    <param type="color" name="Circle color" key="color" defaultValue="#ffffff" />
                </parameters>
            </service>

            <!-- Gui Service to display a value in a QLabel -->
            <service uid="errorLabelSrv" type="sight::module::ui::qt::STextStatus" >
                <label>Reprojection error (RMSE)</label>
                <color>#D25252</color>
            </service>

            <!-- GUI to select camera (device, file, or stream) -->
            <service uid="videoSelectorSrv" type="sight::module::ui::qt::video::SCamera" >
                <inout key="camera" uid="camera" />
                <videoSupport>true</videoSupport>
            </service>

            <!-- Grab image from camera device and fill a frame timeline -->
            <service uid="videoGrabberSrv" type="sight::module::io::video::SFrameGrabber" >
                <in key="camera" uid="camera" />
                <inout key="frameTL" uid="frameTL" />
            </service>

            <!-- Consumes a frame in the timeline, picks the latest one to be processed -->
            <!-- It is overkill in this sample, but mandatory when we use multiple grabbers to synchronize them. -->
            <service uid="frameUpdaterSrv" type="sight::module::sync::SFrameMatrixSynchronizer" >
                <in group="frameTL" >
                    <key uid="frameTL" autoConnect="true" />
                </in>
                <inout group="image" >
                    <key uid="sourceFrame" />
                </inout>
                <tolerance>100</tolerance>
                <framerate>0</framerate>
            </service>

            <!-- Aruco tracker service -->
            <service uid="trackerSrv" type="sight::module::navigation::optics::SArucoTracker" worker="tracking" >
                <in key="camera" uid="camera" />
                <inout key="frame" uid="sourceFrame" autoConnect="true" />
                <inout group="markerMap" >
                    <key uid="markerMap" /> <!-- timeline of detected tag(s) -->
                </inout>
                <track>
                    <!-- list of tag's id -->
                    <marker id="101" />
                </track>
                <debugMarkers>true</debugMarkers>
            </service>

            <!-- Computes the pose of the camera with tag(s) detected by aruco -->
            <service uid="registrationSrv" type="sight::module::geometry::vision::SPoseFrom2d" worker="tracking" >
                <in group="markerMap" autoConnect="true" >
                    <key uid="markerMap" />
                </in>
                <in group="camera" >
                    <key uid="camera" />
                </in>
                <inout group="matrix" >
                    <key uid="markerToCamera" id="101" />
                </inout>
                <patternWidth>60</patternWidth>
            </service>

            <!-- Computes the reprojection error -->
            <service uid="errorSrv" type="sight::module::geometry::vision::SReprojectionError" worker="error" >
                <in group="matrix" autoConnect="true" >
                    <key uid="markerToCamera" id="101" />
                </in>
                <in key="markerMap" uid="markerMap" />
                <in key="camera" uid="camera" />
                <inout key="frame" uid="sourceFrame" />
                <patternWidth>60</patternWidth>
            </service>

            <!-- Multiply matrices (here only used to inverse "markerToCamera") -->
            <service uid="matrixReverserSrv" type="sight::module::geometry::base::SConcatenateMatrices" >
                <in group="matrix" >
                    <key uid="markerToCamera" autoConnect="true" inverse="true" />
                </in>
                <inout key="output" uid="cameraToMarker" />
            </service>

            <service uid="undistorterSrv" type="sight::module::geometry::vision::SDistortion" >
                <in key="camera" uid="camera" autoConnect="true" />
                <inout key="map" uid="undistortMap" />
                <mode>undistort</mode>
            </service>

            <service uid="distorterSrv" type="sight::module::geometry::vision::SDistortion" >
                <in key="camera" uid="camera" autoConnect="true" />
                <inout key="map" uid="distortMap" />
                <mode>distort</mode>
            </service>

            <!-- Wait for the undistortion and the matrix inversion to be finished -->
            <service uid="syncGenericSceneSrv" type="sight::module::sync::SSignalGate" >
                <signal>sourceFrame/bufferModified</signal>
                <signal>cameraToMarker/modified</signal>
            </service>

            <service uid="materialOpacityEditor" type="sight::module::ui::qt::SMaterialOpacityEditor">
                <inout key="material" uid="cubeMaterial"/>
                <label>Cube opacity</label>
            </service>

            <!-- ******************************* Connections ***************************************** -->

            <connect>
                <signal>videoSelectorSrv/configuredFile</signal>
                <signal>videoSelectorSrv/configuredStream</signal>
                <signal>videoSelectorSrv/configuredDevice</signal>
                <slot>startVideoAct/update</slot>
            </connect>

            <connect>
                <signal>videoGrabberSrv/cameraStarted</signal>
                <slot>pauseVideoAct/show</slot>
                <slot>startVideoAct/hide</slot>
                <slot>stopVideoAct/setExecutable</slot>
                <slot>loopVideoAct/setExecutable</slot>
            </connect>

            <connect>
                <signal>camera/idModified</signal>
                <slot>videoGrabberSrv/stopCamera</slot>
            </connect>

            <connect>
                <signal>camera/modified</signal>
                <slot>startVideoAct/setExecutable</slot>
                <slot>stopVideoAct/update</slot>
            </connect>

            <!-- signal/slot connection -->
            <connect>
                <signal>reprojectionParamametersSrv/colorChanged</signal>
                <slot>errorSrv/setColorParameter</slot>
            </connect>

            <connect>
                <signal>reprojectionParamametersSrv/boolChanged</signal>
                <slot>errorSrv/setBoolParameter</slot>
            </connect>

            <connect>
                <signal>errorSrv/errorComputed</signal>
                <slot>errorLabelSrv/setDoubleParameter</slot>
            </connect>

            <connect>
                <signal>arucoParamametersSrv/boolChanged</signal>
                <slot>trackerSrv/setBoolParameter</slot>
            </connect>

            <connect>
                <signal>arucoParamametersSrv/intChanged</signal>
                <slot>trackerSrv/setIntParameter</slot>
            </connect>

            <connect>
                <signal>arucoParamametersSrv/doubleChanged</signal>
                <slot>trackerSrv/setDoubleParameter</slot>
            </connect>

            <connect>
                <signal>cameraSeries/modified</signal>
                <slot>extractCameraSrv/update</slot>
                <slot>errorSrv/update</slot>
            </connect>

            <connect>
                <signal>trackerSrv/markerDetected</signal>
                <slot>axisAdp/updateVisibility</slot>
            </connect>

            <!-- When the undistortion and the matrix inversion are done, trigger the rendering -->
            <!-- then process a new frame -->
            <connect>
                <signal>syncGenericSceneSrv/allReceived</signal>
                <slot>genericSceneSrv/requestRender</slot>
                <slot>frameUpdaterSrv/synchronize</slot>
            </connect>

            <!-- ******************************* Start services ***************************************** -->

            <start uid="mainFrame" />
            <start uid="videoGrabberSrv" />
            <start uid="frameUpdaterSrv" />
            <start uid="registrationSrv" />
            <start uid="trackerSrv" />
            <start uid="calibrationReaderSrv" />
            <start uid="videoSelectorSrv" />
            <start uid="extractCameraSrv" />
            <start uid="matrixReverserSrv" />
            <start uid="errorSrv" />
            <start uid="hideAxisSrv" />
            <start uid="undistorterSrv" />
            <start uid="distorterSrv" />
            <start uid="syncGenericSceneSrv" />
            <start uid="loadMeshSrv" />
            <start uid="genericSceneSrv" />
            <start uid="materialAdp" />
            <start uid="videoAdp" />
            <start uid="undistortAdp" />
            <start uid="axisAdp" />
            <start uid="cameraAdp" />
            <start uid="cubeAdp" />
            <start uid="distortAdp" />

            <!-- ******************************* Update services ***************************************** -->

            <!-- At launch, enable the synchronization with the non-offscreen rendering -->
            <update uid="showParametersAct" />
            <update uid="hideAxisSrv" />
            <update uid="loadMeshSrv" />
            <update uid="arucoParamametersSrv" />
            <update uid="reprojectionParamametersSrv" />

        </config>
    </extension>
</plugin>
