### xcode

#### trouble to understand how to make the matrix match the AR Marker

My goal is to know how to create my own marker and use it I'm having trouble to understand how to make the matrix matches the AR Marker PNG. Id really love someone to either explain how this and the PNG are working together, Actually Im a bit embarrassed as on further reading it is not hamming code, but based on hamming code Still possibly someone familiar with hamming code might be able to help this is (the whole tutorial link is at the bottom of the post) The main difference with the hamming code is that the first bit (parity of bits 3 and 5) is inverted. So, ID 0 (which in hamming code is 00000) becomes 10000 in our code. The idea is to prevent a completely black rectangle from being a valid marker ID, with the goal of reducing the likelihood of false positives with objects of the environment. As there are four possible orientations of the marker picture, we have to find the correct marker position. Remember, we introduced three parity bits for each two bits of information. With their help we can find the hamming distance for each possible marker orientation. The correct marker position will have zero hamming distance error, while the other rotations won't. Here is a code snippet that rotates the bit matrix four times and finds the correct marker orientation: //check all possible rotations cv::Mat rotations[4]; int distances[4]; rotations[0] = bitMatrix; distances[0] = hammDistMarker(rotations[0]); std::pair<int,int> minDist(distances[0],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]); if (distances[i] < minDist.first) { minDist.first = distances[i]; minDist.second = i; } } This code finds the orientation of the bit matrix in such a way that it gives minimal error for the hamming distance metric. This error should be zero for correct marker ID; if it's not, it means that we encountered a wrong marker pattern (corrupted image or false-positive marker detection). **this is the code that I think is relating to the Marker png shown can anyone help me to understand the matrix so I can use it. ALL diagrams, thoughts and explanations happily accepted for a non maths person to get an understanding of this quite complex problem ;P ! ![the working AR marker when view from iPad][4] // // Marker.cpp // Example_MarkerBasedAR // // Created by Ievgen Khvedchenia on 3/13/12. // Copyright (c) 2012 Ievgen Khvedchenia. All rights reserved. // #include "Marker.hpp" #include "DebugHelpers.hpp" Marker::Marker() : id(-1) { } bool operator<(const Marker &M1,const Marker&M2) { return M1.id<M2.id; } cv::Mat Marker::rotate(cv::Mat in) { cv::Mat out; in.copyTo(out); for (int i=0;i<in.rows;i++) { for (int j=0;j<in.cols;j++) { out.at<uchar>(i,j)=in.at<uchar>(in.cols-j-1,i); } } return out; } int Marker::hammDistMarker(cv::Mat bits) { int ids[4][5]= { {1,0,0,0,0}, {1,0,1,1,1}, {0,1,0,0,1}, {0,1,1,1,0} }; int dist=0; for (int y=0;y<5;y++) { int minSum=1e5; //hamming distance to each possible word for (int p=0;p<4;p++) { int sum=0; //now, count for (int x=0;x<5;x++) { sum += bits.at<uchar>(y,x) == ids[p][x] ? 0 : 1; } if (minSum>sum) minSum=sum; } //do the and dist += minSum; } return dist; } int Marker::mat2id(const cv::Mat &bits) { int val=0; for (int y=0;y<5;y++) { val<<=1; if ( bits.at<uchar>(y,1)) val|=1; val<<=1; if ( bits.at<uchar>(y,3)) val|=1; } return val; } int Marker::getMarkerId(cv::Mat &markerImage,int &nRotations) { assert(markerImage.rows == markerImage.cols); assert(markerImage.type() == CV_8UC1); cv::Mat grey = markerImage; // Threshold image cv::threshold(grey, grey, 125, 255, cv::THRESH_BINARY | cv::THRESH_OTSU); #ifdef SHOW_DEBUG_IMAGES cv::showAndSave("Binary marker", grey); #endif //Markers are divided in 7x7 regions, of which the inner 5x5 belongs to marker info //the external border should be entirely black int cellSize = markerImage.rows / 7; for (int y=0;y<7;y++) { int inc=6; if (y==0 || y==6) inc=1; //for first and last row, check the whole border for (int x=0;x<7;x+=inc) { int cellX = x * cellSize; int cellY = y * cellSize; cv::Mat cell = grey(cv::Rect(cellX,cellY,cellSize,cellSize)); int nZ = cv::countNonZero(cell); if (nZ > (cellSize*cellSize) / 2) { return -1;//can not be a marker because the border element is not black! } } } cv::Mat bitMatrix = cv::Mat::zeros(5,5,CV_8UC1); //get information(for each inner square, determine if it is black or white) for (int y=0;y<5;y++) { for (int x=0;x<5;x++) { int cellX = (x+1)*cellSize; int cellY = (y+1)*cellSize; cv::Mat cell = grey(cv::Rect(cellX,cellY,cellSize,cellSize)); int nZ = cv::countNonZero(cell); if (nZ> (cellSize*cellSize) /2) bitMatrix.at<uchar>(y,x) = 1; } } //check all possible rotations cv::Mat rotations[4]; int distances[4]; rotations[0] = bitMatrix; distances[0] = hammDistMarker(rotations[0]); std::pair<int,int> minDist(distances[0],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]); if (distances[i] < minDist.first) { minDist.first = distances[i]; minDist.second = i; } } nRotations = minDist.second; if (minDist.first == 0) { return mat2id(rotations[minDist.second]); } return -1; } void Marker::drawContour(cv::Mat& image, cv::Scalar color) const { float thickness = 2; cv::line(image, points[0], points[1], color, thickness, CV_AA); cv::line(image, points[1], points[2], color, thickness, CV_AA); cv::line(image, points[2], points[3], color, thickness, CV_AA); cv::line(image, points[3], points[0], color, thickness, CV_AA); } AR tutorial I'm working from https://www.packtpub.com/books/content/marker-based-augmented-reality-iphone-or-ipad

I don't have an exhaustive answer, but I think I can explain enough to help your confusion since I am familiar with Hamming distance as well as matrix rotations and other transformations. From what I can tell: The matrix you have isn't the bitmap for that marker. It is an array of rotations. In the algorithm as implemented in the article, the hamming distances are computed with 4 rotations of a marker. So the reason you have 4 rows in the matrix is it is 4 rotations. I could be wrong, or have oversimplified, maybe this answer will trigger discussion and someone better will see it. I'll look closer at the algorithm and article to see if I can understand it. I made an A in Matrix Theory, but that was 18 years ago and I've frankly forgotten how to transform matrices.

I just found out a clue, but not very sure. Here is my thought: I found the explanation of "Hamming code" via Wiki http://en.wikipedia.org/wiki/Hamming_code, and how to encode.(have no privilege to insert picture, so please visit the link above) Here is the code from the book《Mastering OpenCV ...》: int Marker::mat2id(const cv::Mat &bits) { int val=0; for (int y=0;y<5;y++) { val<<=1; if ( bits.at<uchar>(y,1)) val|=1; val<<=1; if ( bits.at<uchar>(y,3)) val|=1; } return val; } I think only bits 1 and 3 are data, so I took a look at the matrix: int ids[4][5]= { {1,0,0,0,0},// 0,0 -> 0 {1,0,1,1,1},// 0,1 -> 1 {0,1,0,0,1},// 1,0 -> 2 {0,1,1,1,0} // 1,1 -> 3 }; ^ ^ | | So these 4 cols should be the hamming-code of [0][1][2][3](which 2 bits can encode) The following is my explanation( maybe incorrect~): //(1):'d' represents data, 'p' represents parity bits. Among [d1~d4],only [d1][d2] are useful //(2):then place [d1][d2] into [p1][p2][p4],[p1~p3] is calculated following the circle graph(?) in the Wiki webpage. //(3):next, write the matrix from the high bits //(4):finally, according to what the book explains: The main difference with the hamming code is that the first bit (parity of bits 3 and 5) is inverted. So, ID 0 (which in hamming code is 00000) becomes 10000 in our code. The idea is to prevent a completely black rectangle from being a valid marker ID, with the goal of reducing the likelihood of false positives with objects of the environment. //I invert the [p4] , and I got the matrix above. origin Num d1 d2 d3 d4 p1 p2 p4 p1 d1 p2 d2 p4 p4 d2 p2 d1 p1 p4 d2 p2 d1 p1 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 01 1 0 0 0 1 1 0 => 1 1 1 0 0 => 0 0 1 1 1 => 1 0 1 1 1 10 0 1 0 0 1 0 1 => 1 0 0 1 1 => 1 1 0 0 1 => 0 1 0 0 1 11 1 1 0 0 0 1 1 0 1 1 1 1 1 1 1 1 0 0 1 1 1 0 [ (1) ] [ (2) ] [ (3) ] [ (4) ] I do not sure whether this is right, but I got the same result. If it is true, then we can make our own markers with this matrix. #Natalie and #mrjoltcola . Hope you can see this~ (this is my first time reply on this forum ,if there are something improper, I`d be glad to receiving advices :) ^_^ )

### Related Links

Adding a UINavigationController built with IB

Set Initial Screen Image for Xcode Tab Bar App

How do you add a breakpoint in Xcode?

In Xcode how do I add a breakpoint inside a block?

xcode/iOS: Autoresize to fill a view - explicit frame size is essential?

Is xcode 4.2 is compatible with mac os 10.6.3?

Xcode keeps searching dylib at wrong path

How can I get UDID using liblockdown.dylib?

Insert into different tables in SQlite

In Xcode 4, setting User Header Search path breaks code sense

Tools to document Core Data Models?

iPod won't sleep when connected to debugger

How can I install the OSX 10.4u SDK to support backwards compatible OSX builds?

Building a universal app for iOS 3.1, iOS 3.2 using iOS SDK 4.2

xcode4: Where are the User Scripts?

Do I still need an Entitlements.plist file for an ad-hoc build?