2016-06-21 2 views
2

Ich versuche gerade, einen ArUco Cube-Detektor für ein Projekt zu entwickeln. Das Ziel ist eine stabilere und genauere Posenschätzung ohne Verwendung einer großen ArUco-Platine. Damit dies funktioniert, muss ich jedoch die Ausrichtung der einzelnen Marker kennen. Mit der draw3dAxis-Methode habe ich festgestellt, dass die X- und Y-Achse nicht immer am selben Ort auftauchen. Hier ist ein Video, das das Problem demonstriert: https://youtu.be/gS7BWKm2nmgArUco Axis Swap beim Zeichnen 3dAxis

Es scheint ein Problem mit der Rvec-Erkennung zu sein. Die ersten beiden Werte des Rvec werden deutlich verschoben, was bis zum Austausch der Achse relativ konstant bleibt. Wenn dieser Achsentausch stattfindet, können sich die Werte um eine Stärke von 2-6 ändern. Die ARuco Bibliothek nicht versuchen, mit Drehungen zu behandeln wie in der Marker.calculateMarkerId() -Methode gezeigt:

/** 
* Return the id read in the code inside a marker. Each marker is divided into 7x7 regions 
* of which the inner 5x5 contain info, the border should always be black. This function 
* assumes that the code has been extracted previously. 
* @return the id of the marker 
*/ 
protected int calculateMarkerId(){ 
    // check all the rotations of code 
    Code[] rotations = new Code[4]; 
    rotations[0] = code; 
    int[] dists = new int[4]; 
    dists[0] = hammDist(rotations[0]); 
    int[] minDist = {dists[0],0}; 
    for(int i=1;i<4;i++){ 
     // rotate 
     rotations[i] = Code.rotate(rotations[i-1]); 
     dists[i] = hammDist(rotations[i]); 
     if(dists[i] < minDist[0]){ 
      minDist[0] = dists[i]; 
      minDist[1] = i; 
     } 
    } 
    this.rotations = minDist[1]; 
    if(minDist[0] != 0){ 
     return -1; // matching id not found 
    } 
    else{ 
     this.id = mat2id(rotations[minDist[1]]); 
    } 
    return id; 
} 

und die MarkerDetector.detect() ruft diese Methode und verwendet die getRotations() Methode:

// identify the markers 
    for(int i=0;i<nCandidates;i++){ 
     if(toRemove.get(i) == 0){ 
      Marker marker = candidateMarkers.get(i); 
      Mat canonicalMarker = new Mat(); 
      warp(in, canonicalMarker, new Size(50,50), marker.toList()); 
      marker.setMat(canonicalMarker); 
      marker.extractCode(); 
      if(marker.checkBorder()){ 
       int id = marker.calculateMarkerId(); 
       if(id != -1){ 
        // rotate the points of the marker so they are always in the same order no matter the camera orientation 
        Collections.rotate(marker.toList(), 4-marker.getRotations()); 

        newMarkers.add(marker); 

       } 
      } 
     } 
    } 

der vollständige Quellcode für die ArUco Bibliothek ist hier: https://github.com/sidberg/aruco-android/blob/master/Aruco/src/es/ava/aruco/MarkerDetector.java

Wenn jemand irgendwelche Ratschläge oder Lösungen hat würde ich mich sehr gnädig. Bitte kontaktieren Sie mich, wenn Sie Fragen haben.

Antwort

2

Ich habe das Problem gefunden. Es stellt sich heraus, dass die Marker-Klasse über eine Rotationsvariable verfügt, mit der die Achse so gedreht werden kann, dass sie mit der Ausrichtung des Markers übereinstimmt. Ich schrieb die folgende Methode in der Utils-Klasse:

protected static void alignToId(Mat rotation, int codeRotation) { 
    //get the matrix corresponding to the rotation vector 
    Mat R = new Mat(3, 3, CvType.CV_64FC1); 
    Calib3d.Rodrigues(rotation, R); 

    codeRotation += 1; 
    //create the matrix to rotate around Z Axis 
    double[] rot = { 
      Math.cos(Math.toRadians(90) * codeRotation), -Math.sin(Math.toRadians(90) * codeRotation), 0, 
      Math.sin(Math.toRadians(90) * codeRotation), Math.cos(Math.toRadians(90) * codeRotation), 0, 
      0, 0, 1 
    }; 

    // multiply both matrix 
    Mat res = new Mat(3, 3, CvType.CV_64FC1); 
    double[] prod = new double[9]; 
    double[] a = new double[9]; 
    R.get(0, 0, a); 
    for (int i = 0; i < 3; i++) 
     for (int j = 0; j < 3; j++) { 
      prod[3 * i + j] = 0; 
      for (int k = 0; k < 3; k++) { 
       prod[3 * i + j] += a[3 * i + k] * rot[3 * k + j]; 
      } 
     } 
    // convert the matrix to a vector with rodrigues back 
    res.put(0, 0, prod); 
    Calib3d.Rodrigues(res, rotation); 
} 

und ich rief es aus der Marker.calculateExtrinsics Methode:

 Utils.alignToId(Rvec, this.getRotations());