CogniPilot

MODELICA LIBRARY · ENGINEERING REFERENCE

SLAM/LoopClosure/RGBDCatalogLoopVerification.mo

Download original .moGitHub source

Documentation: SLAM.LoopClosure.RGBDCatalogLoopVerification · SLAM.LoopClosure.RGBDCatalogLoopVerification.PoseConsistent · SLAM.LoopClosure.RGBDCatalogLoopVerification.VerifyCandidate · SLAM.LoopClosure.RGBDCatalogLoopVerification.Batch · SLAM.LoopClosure.RGBDCatalogLoopVerification.ProposeCapture

within SLAM.LoopClosure;
// Geometric proposals use the same immutable catalog snapshot as retrieval.
// Graph admission and shared-image correlation remain separate owners.
package RGBDCatalogLoopVerification
  import RegistrationWhitenedResidual3 = Vision.Registration.RegistrationWhitenedResidual3;
  import RGBDUncertaintySkew = SLAM.Localization.RGBDUncertaintySkew;

  function PoseConsistent
    input Real referencePosition[3]; input Real currentPosition[3];
    input Real referenceRotation[3,3];
    input Real referenceCovariance[6,6]; input Real currentCovariance[6,6];
    input Real measuredTranslation[3]; input Real measuredCovariance[3,3];
    input Real maximumSquared = 9.0; input Real minimumPivot = 1e-10;
    input Real maximumTranslationInnovation = 2.0 "Motion disagreement limit; explicit relocalization policy may enlarge it";
    output Boolean accepted; output Real squared;
  protected
    Real residual[3]; Real arm[3,3]; Real covariance[3,3]; Boolean valid;
  algorithm
    residual := currentPosition-referencePosition-referenceRotation*measuredTranslation;
    arm := referenceRotation*RGBDUncertaintySkew(measuredTranslation);
    // A conservative screening bound, not an independent measurement update.
    // Four times the marginal sum bounds arbitrary correlations among the
    // two positions, retained-reference angle and measured translation.
    covariance := 4.0*(referenceCovariance[1:3,1:3]+currentCovariance[1:3,1:3]
      +referenceRotation*measuredCovariance*transpose(referenceRotation)
      +arm*referenceCovariance[4:6,4:6]*transpose(arm));
    (valid,squared) := RegistrationWhitenedResidual3(residual,covariance,minimumPivot);
    accepted := valid and maximumSquared > 0.0 and squared <= maximumSquared
      and maximumTranslationInnovation > 0.0
      and residual*residual <= maximumTranslationInnovation*maximumTranslationInnovation;
  end PoseConsistent;
  import RGBDKeyframeRetrieval = SLAM.LoopClosure.RGBDKeyframeRetrieval;
  import RGBDKeyframes = SLAM.LoopClosure.RGBDKeyframes;
  import RGBDLoopVerification = SLAM.LoopClosure.RGBDLoopVerification;

  function VerifyCandidate
    input RGBDKeyframes.Catalog catalog;
    input RGBDKeyframes.Frame current;
    input Integer candidateId; input Integer candidateSlot;
    input Real appearanceScore; input Boolean requested;
    input Integer seed = 7; input Integer trials = 96; input Integer refinements = 4;
    input Integer minimumInliers = 12; input Real minimumFraction = 0.5;
    input Real inlierDistance = 0.08; input Real maximumRms = 0.03;
    input Real minimumAge = 5.0; input Real minimumSimilarity = 0.35;
    input Real descriptorRatio = 0.8; input Real maximumDescriptorDistance = 0.8;
    input Real coordinateLimit = 100.0; input Real rankTolerance = 1e-8;
    input Real localizationSigma = 0.5; input Real depthInflation = 1.0; input Real minimumPivot = 1e-10;
    output RGBDLoopVerification.Proposal proposal;
    input Boolean calibratedResiduals = true;
    input Real maximumNormalizedSquared = 9.0;
    input Boolean poseConsistentLoops = false;
    input Real maximumPoseInnovation = 2.0;
    input Real poseConsistencySquared = 9.0;
  protected
    RGBDKeyframes.Frame reference;
    Boolean bound; Boolean poseConsistent; Real poseSquared;
  algorithm
    proposal := RGBDLoopVerification.EmptyProposal(seed);
    if requested then
      // Check domains before reading a slot. Capture will replace nextSlot,
      // so that identity cannot supply a retained loop endpoint.
      bound := RGBDKeyframes.ValidHeader(catalog)
        and candidateSlot >= 1 and candidateSlot <= RGBDKeyframes.keyframeCapacity
        and candidateSlot <> catalog.nextSlot and candidateId >= 1 and candidateId < catalog.nextId
        and current.generation == catalog.generation
        and current.vocabularyVersion == catalog.vocabularyVersion
        and current.id == catalog.nextId and current.epoch > catalog.lastEpoch
        and (catalog.nextId == 1 or current.imageTime > catalog.lastTime)
        and minimumSimilarity >= 0 and minimumSimilarity <= 1
        and appearanceScore >= minimumSimilarity and appearanceScore <= 1;
      proposal.rejectionReason := 10 "Catalog/appearance identity binding refused";
      if bound then
        bound := catalog.occupied[candidateSlot] and catalog.ids[candidateSlot] == candidateId
          and catalog.generations[candidateSlot] == current.generation
          and catalog.vocabularyVersions[candidateSlot] == current.vocabularyVersion;
        if bound then
          reference := RGBDKeyframes.ReadSlot(catalog,candidateSlot);
          proposal := RGBDLoopVerification.Verify(reference,current,true,seed,trials,refinements,
            minimumInliers,minimumFraction,inlierDistance,maximumRms,minimumAge,descriptorRatio,
            maximumDescriptorDistance,coordinateLimit,rankTolerance,localizationSigma,depthInflation,minimumPivot,
            calibratedResiduals=calibratedResiduals,maximumNormalizedSquared=maximumNormalizedSquared);
          if proposal.verified and poseConsistentLoops then
            (poseConsistent,poseSquared) := PoseConsistent(reference.bodyPosition,current.bodyPosition,
              reference.bodyRotation,reference.poseCovariance,current.poseCovariance,
              proposal.bodyTranslation,proposal.covariance[1:3,1:3],minimumPivot=minimumPivot,
              maximumSquared=poseConsistencySquared,maximumTranslationInnovation=maximumPoseInnovation);
            if not poseConsistent then
              proposal.verified := false; proposal.rejectionReason := 11;
            end if;
          end if;
        end if;
      end if;
    end if;
  end VerifyCandidate;

  record Batch
    RGBDKeyframes.Frame prepared;
    Boolean retrievalAccepted; Integer retrievalRejectionReason;
    Real wordIndex[RGBDKeyframes.featureCapacity];
    Integer candidateId[RGBDKeyframeRetrieval.proposalCapacity];
    Integer candidateSlot[RGBDKeyframeRetrieval.proposalCapacity];
    Real candidateScore[RGBDKeyframeRetrieval.proposalCapacity];
    Integer candidateCount; Real assignmentCount;
    RGBDLoopVerification.Proposal proposals[RGBDKeyframeRetrieval.proposalCapacity];
    Integer verifiedCount;
    Integer nextSeeds[RGBDKeyframeRetrieval.proposalCapacity];
  end Batch;

  function ProposeCapture
    input RGBDKeyframes.Catalog catalog;
    input RGBDKeyframes.Frame measurement;
    input Real vocabulary[RGBDKeyframes.wordCapacity,RGBDKeyframes.descriptorSize];
    input Real vocabularyEnabled[RGBDKeyframes.wordCapacity];
    input Boolean requested;
    input Integer seeds[RGBDKeyframeRetrieval.proposalCapacity];
    input Real maximumWordDistanceSquared = 0.8; input Integer minimumAssignments = 8;
    input Real minimumSimilarity = 0.35; input Real minimumAge = 5.0;
    input Integer trials = 96; input Integer refinements = 4;
    input Integer minimumInliers = 12; input Real minimumFraction = 0.5;
    input Real inlierDistance = 0.08; input Real maximumRms = 0.03;
    input Real descriptorRatio = 0.8; input Real maximumDescriptorDistance = 0.8;
    input Real coordinateLimit = 100.0; input Real rankTolerance = 1e-8;
    input Real localizationSigma = 0.5; input Real depthInflation = 1.0; input Real minimumPivot = 1e-10;
    output Batch result;
    input Boolean calibratedResiduals = true;
    input Real maximumNormalizedSquared = 9.0;
    input Boolean poseConsistentLoops = false;
    input Real maximumPoseInnovation = 2.0;
    input Real poseConsistencySquared = 9.0;
  algorithm
    (result.prepared,result.retrievalAccepted,result.retrievalRejectionReason,result.wordIndex,result.candidateId,result.candidateSlot,result.candidateScore,
      result.candidateCount,result.assignmentCount) := RGBDKeyframeRetrieval.PrepareCapture(catalog,measurement,
        vocabulary,vocabularyEnabled,requested,maximumWordDistanceSquared,minimumAssignments,minimumSimilarity,minimumAge);
    result.verifiedCount := 0;
    for rank in 1:RGBDKeyframeRetrieval.proposalCapacity loop
      result.proposals[rank] := VerifyCandidate(catalog,result.prepared,result.candidateId[rank],result.candidateSlot[rank],result.candidateScore[rank],
        result.retrievalAccepted and rank <= result.candidateCount,seeds[rank],trials,refinements,minimumInliers,
        minimumFraction,inlierDistance,maximumRms,minimumAge,minimumSimilarity,descriptorRatio,
        maximumDescriptorDistance,coordinateLimit,rankTolerance,localizationSigma,depthInflation,minimumPivot,
        calibratedResiduals=calibratedResiduals,maximumNormalizedSquared=maximumNormalizedSquared,
        poseConsistentLoops=poseConsistentLoops,maximumPoseInnovation=maximumPoseInnovation,poseConsistencySquared=poseConsistencySquared);
      result.nextSeeds[rank] := result.proposals[rank].nextSeed;
      result.verifiedCount := result.verifiedCount+(if result.proposals[rank].verified then 1 else 0);
    end for;
  end ProposeCapture;
end RGBDCatalogLoopVerification;