/// <summary> /// Gets the marker identifier. /// </summary> /// <returns>The marker identifier.</returns> /// <param name="markerImage">Marker image.</param> /// <param name="nRotations">N rotations.</param> public static int getMarkerId(Mat markerImage, MatOfInt nRotations, byte[,] markerDesign) { Mat grey = markerImage; // Threshold image Imgproc.threshold(grey, grey, 125, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU); //Markers are divided in 7x7 regions, of which the inner 5x5 belongs to marker info //the external border should be entirely black int size = markerDesign.GetLength(0); int cellSize = markerImage.rows() / (size + 2); for (int y = 0; y < (size + 2); y++) { int inc = size + 1; if (y == 0 || y == (size + 1)) { inc = 1; //for first and last row, check the whole border } for (int x = 0; x < (size + 2); x += inc) { int cellX = x * cellSize; int cellY = y * cellSize; Mat cell = new Mat(grey, new OpenCVForUnity.CoreModule.Rect(cellX, cellY, cellSize, cellSize)); int nZ = Core.countNonZero(cell); cell.Dispose(); if (nZ > (cellSize * cellSize) / 2) { return(-1);//can not be a marker because the border element is not black! } } } Mat bitMatrix = Mat.zeros(size, size, CvType.CV_8UC1); //get information(for each inner square, determine if it is black or white) for (int y = 0; y < size; y++) { for (int x = 0; x < size; x++) { int cellX = (x + 1) * cellSize; int cellY = (y + 1) * cellSize; Mat cell = new Mat(grey, new OpenCVForUnity.CoreModule.Rect(cellX, cellY, cellSize, cellSize)); int nZ = Core.countNonZero(cell); if (nZ > (cellSize * cellSize) / 2) { bitMatrix.put(y, x, new byte[] { 1 }); } cell.Dispose(); } } //check all possible rotations Mat[] rotations = new Mat[4]; for (int i = 0; i < rotations.Length; i++) { rotations[i] = new Mat(); } int[] distances = new int[4]; rotations[0] = bitMatrix; distances[0] = hammDistMarker(rotations[0], markerDesign); int first = distances[0]; int second = 0; for (int i = 1; i < 4; i++) { //get the hamming distance to the nearest possible word rotations[i] = rotate(rotations[i - 1]); distances[i] = hammDistMarker(rotations[i], markerDesign); if (distances[i] < first) { first = distances[i]; second = i; } } nRotations.fromArray(second); if (first == 0) { int id = mat2id(rotations[second]); bitMatrix.Dispose(); for (int i = 0; i < rotations.Length; i++) { rotations[i].Dispose(); } return(id); } return(-1); }
/// <summary> /// Gets the marker identifier. /// </summary> /// <returns>The marker identifier.</returns> /// <param name="markerImage">Marker image.</param> /// <param name="nRotations">N rotations.</param> public static int getMarkerId (Mat markerImage, MatOfInt nRotations, byte[,] markerDesign) { Mat grey = markerImage; // Threshold image Imgproc.threshold (grey, grey, 125, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU); //Markers are divided in 7x7 regions, of which the inner 5x5 belongs to marker info //the external border should be entirely black int size = markerDesign.GetLength(0); int cellSize = markerImage.rows () / (size + 2); for (int y=0; y<(size+2); y++) { int inc = size + 1; if (y == 0 || y == (size + 1)) inc = 1; //for first and last row, check the whole border for (int x=0; x<(size+2); x+=inc) { int cellX = x * cellSize; int cellY = y * cellSize; Mat cell = new Mat (grey, new OpenCVForUnity.Rect (cellX, cellY, cellSize, cellSize)); int nZ = Core.countNonZero (cell); cell.Dispose (); if (nZ > (cellSize * cellSize) / 2) { return -1;//can not be a marker because the border element is not black! } } } Mat bitMatrix = Mat.zeros (size, size, CvType.CV_8UC1); //get information(for each inner square, determine if it is black or white) for (int y=0; y<size; y++) { for (int x=0; x<size; x++) { int cellX = (x + 1) * cellSize; int cellY = (y + 1) * cellSize; Mat cell = new Mat (grey, new OpenCVForUnity.Rect (cellX, cellY, cellSize, cellSize)); int nZ = Core.countNonZero (cell); if (nZ > (cellSize * cellSize) / 2) bitMatrix.put (y, x, new byte[]{1}); //bitMatrix.at<uchar> (y, x) = 1; cell.Dispose (); } } // Debug.Log ("bitMatrix " + bitMatrix.dump()); //check all possible rotations Mat[] rotations = new Mat[4]; for (int i = 0; i < rotations.Length; i++) { rotations [i] = new Mat (); } int[] distances = new int[4]; rotations [0] = bitMatrix; distances [0] = hammDistMarker (rotations [0], markerDesign); int first = distances [0]; int second = 0; for (int i=1; i<4; i++) { //get the hamming distance to the nearest possible word rotations [i] = rotate (rotations [i - 1]); distances [i] = hammDistMarker (rotations [i], markerDesign); if (distances [i] < first) { first = distances [i]; second = i; } } // Debug.Log ("first " + first); nRotations.fromArray (second); if (first == 0) { int id = mat2id (rotations [second]); bitMatrix.Dispose (); for (int i = 0; i < rotations.Length; i++) { rotations [i].Dispose (); } return id; } return -1; }