00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00024
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <iostream>
00028
00029 #ifndef QVBRIEFDETECTOR_H
00030 #define QVBRIEFDETECTOR_H
00031
00032 #include <QVImage>
00033 #include <QVKeypoint>
00034
00035 #include <math.h>
00036
00086 class QVBRIEFDetector
00087 {
00088 private:
00089 const unsigned int descriptorInts, numTests;
00090 const int windowRadius;
00091
00092 public:
00093 QVector<char> coordinates;
00094
00095 public:
00096 inline unsigned int getWindowRadius() const { return windowRadius; }
00097 inline unsigned int getNumTests() const { return numTests; }
00098
00099 inline unsigned int getDescriptorInts() const { return descriptorInts; }
00100
00111 inline unsigned int distance(const QVector<unsigned int> &descriptorsA, const QVector<unsigned int> &descriptorsB, const int indexA = 0, const int indexB = 0) const
00112 {
00113 Q_ASSERT(descriptorsA.count() > descriptorInts * indexA);
00114 Q_ASSERT(descriptorsB.count() > descriptorInts * indexB);
00115
00116 const unsigned int *dA = &(descriptorsA[descriptorInts*indexA]),
00117 *dB = &(descriptorsB[descriptorInts*indexB]);
00118
00119 unsigned int count = 0;
00120 for(int i = 0; i < descriptorInts; i++)
00121 count += qvNiftyParallelBitCount(dA[i] xor dB[i]);
00122
00123 return count;
00124 }
00125
00129 QVBRIEFDetector(const unsigned int descriptorInts = 4, const unsigned int windowRadius = 16):
00130 descriptorInts(descriptorInts), numTests(descriptorInts*32), windowRadius(windowRadius), coordinates(numTests * 4)
00131 {
00132 if (windowRadius > 127)
00133 std::cout << "[QVBRIEFDetector0::QVBRIEFDetector0()] Error: Test distance must be less than 127." << std::endl;
00134
00135
00136
00137
00138 for(unsigned int i = 0; i < numTests*4; i+=2)
00139 {
00140 const double random1 = double(random()%1000) / 1000.0,
00141 random2 = double(random()%500) / 1000.0 + 0.5;
00142
00143 Q_ASSERT(random1 >= 0);
00144 Q_ASSERT(random2 >= 0);
00145 Q_ASSERT(random1 <= 1.0);
00146 Q_ASSERT(random2 <= 1.0);
00147
00148 const double angle = 2.0 * PI * random1,
00149 dist = random2;
00150
00151 const int x = qvSymmetricFloor(dist * cos(angle) * int(windowRadius)),
00152 y = qvSymmetricFloor(dist * sin(angle) * int(windowRadius));
00153
00154 Q_ASSERT(x >= -int(windowRadius));
00155 Q_ASSERT(y >= -int(windowRadius));
00156 Q_ASSERT(x <= +int(windowRadius));
00157 Q_ASSERT(y <= +int(windowRadius));
00158
00159 coordinates[i+0] = x;
00160 coordinates[i+1] = y;
00161 }
00162 }
00163
00166 QVector<unsigned int> getDescriptors( const QVImage<uChar, 1> &image,
00167 const QVector<QPointF> &keypoints,
00168 const unsigned int octave = 1) const
00169 {
00170 QVector<unsigned int> result(keypoints.count()*descriptorInts);
00171
00172 const uChar *imgData = image.getReadData();
00173
00174 const int imgStep = image.getStep(),
00175 imgCols = image.getCols(),
00176 imgRows = image.getRows();
00177
00178 #ifdef DEBUG
00179 const uChar *imageDataLimit = imgData + imgStep * imgCols + imgRows;
00180 #endif // DEBUG
00181
00182
00183 for(int index = 0; index < keypoints.count(); index++)
00184 {
00185 const QPointF &kp = keypoints[index];
00186
00187
00188
00189
00190 const int xCoor = kp.x() / double(octave),
00191 yCoor = kp.y() / double(octave);
00192
00193
00194
00195
00196
00197 const QVector<char> coors = coordinates;
00198
00199
00200 Q_ASSERT(xCoor - windowRadius >= 0);
00201 Q_ASSERT(yCoor - windowRadius >= 0);
00202 Q_ASSERT(xCoor + windowRadius < imgCols);
00203 Q_ASSERT(yCoor + windowRadius < imgRows);
00204
00205
00206 const uChar *pixelPtr = imgData + imgStep * yCoor + xCoor;
00207 for(int b = 0; b < descriptorInts; b++)
00208 {
00209 Q_ASSERT(result.count() > descriptorInts*index+b);
00210
00211 int ac = 0;
00212 unsigned int binaryDescriptor = 0;
00213 for(int i = 32*4*b; i < 32*4*(b+1); i+=4)
00214 {
00215 Q_ASSERT(i+3 < coors.count());
00216
00217
00218 Q_ASSERT(xCoor + coors[i+0] >= 0);
00219 Q_ASSERT(yCoor + coors[i+1] >= 0);
00220 Q_ASSERT(xCoor + coors[i+0] < imgCols);
00221 Q_ASSERT(yCoor + coors[i+1] < imgRows);
00222
00223 Q_ASSERT(xCoor + coors[i+2] >= 0);
00224 Q_ASSERT(yCoor + coors[i+3] >= 0);
00225 Q_ASSERT(xCoor + coors[i+2] < imgCols);
00226 Q_ASSERT(yCoor + coors[i+3] < imgRows);
00227
00228 Q_ASSERT(*(pixelPtr + imgStep * coors[i+1] + coors[i+0]) == pixelPtr[ imgStep * coors[i+1] + coors[i+0] ]);
00229 Q_ASSERT(*(pixelPtr + imgStep * coors[i+3] + coors[i+2]) == pixelPtr[ imgStep * coors[i+3] + coors[i+2] ]);
00230
00231
00232 binaryDescriptor <<=1;
00233
00234
00235 binaryDescriptor |= pixelPtr[ imgStep * coors[i+1] + coors[i+0] ]
00236 >
00237 pixelPtr[ imgStep * coors[i+3] + coors[i+2] ];
00238
00239 }
00240 result[descriptorInts*index+b] = binaryDescriptor;
00241 }
00242 }
00243
00244 return result;
00245 }
00246 };
00247
00278 bool saveBRIEFDescriptorsInLoweSIFTFileFormat(const QString fileName, const QVector<QPointF> features, const QVector<unsigned int> descriptors);
00279
00280 #endif // QVBRIEFDETECTOR_H