Skip to content

Commit d783cbe

Browse files
committed
Merge pull request #384 from paroj:markercoding
2 parents dc4e52c + 35b935c commit d783cbe

File tree

1 file changed

+30
-63
lines changed

1 file changed

+30
-63
lines changed

modules/aruco/src/dictionary.cpp

Lines changed: 30 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -48,24 +48,6 @@ namespace aruco {
4848

4949
using namespace std;
5050

51-
52-
53-
/**
54-
* Hamming weight look up table from 0 to 255
55-
*/
56-
const unsigned char hammingWeightLUT[] = {
57-
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
58-
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
59-
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
60-
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
61-
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
62-
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
63-
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
64-
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
65-
};
66-
67-
68-
6951
/**
7052
*/
7153
Dictionary::Dictionary(const unsigned char *bytes, int _markerSize, int dictsize, int _maxcorr) {
@@ -75,14 +57,9 @@ Dictionary::Dictionary(const unsigned char *bytes, int _markerSize, int dictsize
7557
if((markerSize * markerSize) % 8 != 0) nbytes++;
7658

7759
// save bytes in internal format
78-
// bytesList.at<Vec4b>(i, j)[k] is j-th byte of i-th marker, in its k-th rotation
60+
// bytesList.ptr(i)[k*nbytes + j] is j-th byte of i-th marker, in its k-th rotation
7961
bytesList = Mat(dictsize, nbytes, CV_8UC4);
80-
for(int i = 0; i < dictsize; i++) {
81-
for(int j = 0; j < nbytes; j++) {
82-
for(int k = 0; k < 4; k++)
83-
bytesList.at< Vec4b >(i, j)[k] = bytes[i * (4 * nbytes) + k * nbytes + j];
84-
}
85-
}
62+
memcpy(bytesList.data, bytes, dictsize*nbytes*4);
8663
}
8764

8865

@@ -106,13 +83,10 @@ bool Dictionary::identify(const Mat &onlyBits, int &idx, int &rotation,
10683
int currentMinDistance = markerSize * markerSize + 1;
10784
int currentRotation = -1;
10885
for(unsigned int r = 0; r < 4; r++) {
109-
int currentHamming = 0;
110-
// for each byte, calculate XOR result and then sum the Hamming weight from the LUT
111-
for(unsigned int b = 0; b < candidateBytes.total(); b++) {
112-
unsigned char xorRes =
113-
bytesList.ptr< Vec4b >(m)[b][r] ^ candidateBytes.ptr< Vec4b >(0)[b][0];
114-
currentHamming += hammingWeightLUT[xorRes];
115-
}
86+
int currentHamming = hal::normHamming(
87+
bytesList.ptr(m)+r*candidateBytes.cols,
88+
candidateBytes.ptr(),
89+
candidateBytes.cols);
11690

11791
if(currentHamming < currentMinDistance) {
11892
currentMinDistance = currentHamming;
@@ -147,12 +121,10 @@ int Dictionary::getDistanceToId(InputArray bits, int id, bool allRotations) cons
147121
Mat candidateBytes = getByteListFromBits(bits.getMat());
148122
int currentMinDistance = int(bits.total() * bits.total());
149123
for(unsigned int r = 0; r < nRotations; r++) {
150-
int currentHamming = 0;
151-
for(unsigned int b = 0; b < candidateBytes.total(); b++) {
152-
unsigned char xorRes =
153-
bytesList.ptr< Vec4b >(id)[b][r] ^ candidateBytes.ptr< Vec4b >(0)[b][0];
154-
currentHamming += hammingWeightLUT[xorRes];
155-
}
124+
int currentHamming = hal::normHamming(
125+
bytesList.ptr(id) + r*candidateBytes.cols,
126+
candidateBytes.ptr(),
127+
candidateBytes.cols);
156128

157129
if(currentHamming < currentMinDistance) {
158130
currentMinDistance = currentHamming;
@@ -202,26 +174,25 @@ Mat Dictionary::getByteListFromBits(const Mat &bits) {
202174
Mat candidateByteList(1, nbytes, CV_8UC4, Scalar::all(0));
203175
unsigned char currentBit = 0;
204176
int currentByte = 0;
177+
178+
// the 4 rotations
179+
uchar* rot0 = candidateByteList.ptr();
180+
uchar* rot1 = candidateByteList.ptr() + 1*nbytes;
181+
uchar* rot2 = candidateByteList.ptr() + 2*nbytes;
182+
uchar* rot3 = candidateByteList.ptr() + 3*nbytes;
183+
205184
for(int row = 0; row < bits.rows; row++) {
206185
for(int col = 0; col < bits.cols; col++) {
207186
// circular shift
208-
candidateByteList.ptr< Vec4b >(0)[currentByte][0] =
209-
candidateByteList.ptr< Vec4b >(0)[currentByte][0] << 1;
210-
candidateByteList.ptr< Vec4b >(0)[currentByte][1] =
211-
candidateByteList.ptr< Vec4b >(0)[currentByte][1] << 1;
212-
candidateByteList.ptr< Vec4b >(0)[currentByte][2] =
213-
candidateByteList.ptr< Vec4b >(0)[currentByte][2] << 1;
214-
candidateByteList.ptr< Vec4b >(0)[currentByte][3] =
215-
candidateByteList.ptr< Vec4b >(0)[currentByte][3] << 1;
216-
// increment if bit is 1
217-
if(bits.at< unsigned char >(row, col))
218-
candidateByteList.ptr< Vec4b >(0)[currentByte][0]++;
219-
if(bits.at< unsigned char >(col, bits.cols - 1 - row))
220-
candidateByteList.ptr< Vec4b >(0)[currentByte][1]++;
221-
if(bits.at< unsigned char >(bits.rows - 1 - row, bits.cols - 1 - col))
222-
candidateByteList.ptr< Vec4b >(0)[currentByte][2]++;
223-
if(bits.at< unsigned char >(bits.rows - 1 - col, row))
224-
candidateByteList.ptr< Vec4b >(0)[currentByte][3]++;
187+
rot0[currentByte] <<= 1;
188+
rot1[currentByte] <<= 1;
189+
rot2[currentByte] <<= 1;
190+
rot3[currentByte] <<= 1;
191+
// set bit
192+
rot0[currentByte] |= bits.at<uchar>(row, col);
193+
rot1[currentByte] |= bits.at<uchar>(col, bits.cols - 1 - row);
194+
rot2[currentByte] |= bits.at<uchar>(bits.rows - 1 - row, bits.cols - 1 - col);
195+
rot3[currentByte] |= bits.at<uchar>(bits.rows - 1 - col, row);
225196
currentBit++;
226197
if(currentBit == 8) {
227198
// next byte
@@ -247,7 +218,7 @@ Mat Dictionary::getBitsFromByteList(const Mat &byteList, int markerSize) {
247218
unsigned char base2List[] = { 128, 64, 32, 16, 8, 4, 2, 1 };
248219
int currentByteIdx = 0;
249220
// we only need the bytes in normal rotation
250-
unsigned char currentByte = byteList.ptr< Vec4b >(0)[0][0];
221+
unsigned char currentByte = byteList.ptr()[0];
251222
int currentBit = 0;
252223
for(int row = 0; row < bits.rows; row++) {
253224
for(int col = 0; col < bits.cols; col++) {
@@ -258,7 +229,7 @@ Mat Dictionary::getBitsFromByteList(const Mat &byteList, int markerSize) {
258229
currentBit++;
259230
if(currentBit == 8) {
260231
currentByteIdx++;
261-
currentByte = byteList.ptr< Vec4b >(0)[currentByteIdx][0];
232+
currentByte = byteList.ptr()[currentByteIdx];
262233
// if not enough bits for one more byte, we are in the end
263234
// update bit position accordingly
264235
if(8 * (currentByteIdx + 1) > (int)bits.total())
@@ -369,12 +340,8 @@ static Mat _generateRandomMarker(int markerSize) {
369340
static int _getSelfDistance(const Mat &marker) {
370341
Mat bytes = Dictionary::getByteListFromBits(marker);
371342
int minHamming = (int)marker.total() + 1;
372-
for(int i = 1; i < 4; i++) {
373-
int currentHamming = 0;
374-
for(int j = 0; j < bytes.cols; j++) {
375-
unsigned char xorRes = bytes.ptr< Vec4b >()[j][0] ^ bytes.ptr< Vec4b >()[j][i];
376-
currentHamming += hammingWeightLUT[xorRes];
377-
}
343+
for(int r = 1; r < 4; r++) {
344+
int currentHamming = hal::normHamming(bytes.ptr(), bytes.ptr() + bytes.cols*r, bytes.cols);
378345
if(currentHamming < minHamming) minHamming = currentHamming;
379346
}
380347
return minHamming;

0 commit comments

Comments
 (0)