((FREAK*)this)->buildPattern();
- computeDescriptors<uchar, int>(grayImage, keypoints, descriptors);
+ // Convert to gray if not already
+ Mat grayImage = image;
+// if( image.channels() > 1 )
+// cvtColor( image, grayImage, COLOR_BGR2GRAY );
+
+ // Use 32-bit integers if we won't overflow in the integral image
+ if ((image.depth() == CV_8U || image.depth() == CV_8S) &&
+ (image.rows * image.cols) < 8388608 ) // 8388608 = 2 ^ (32 - 8(bit depth) - 1(sign bit))
+ {
+ // Create the integral image appropriate for our type & usage
+ if (image.depth() == CV_8U)
- computeDescriptors<char, int>(grayImage, keypoints, descriptors);
++ computeDescriptors<uchar, int>(grayImage, keypoints, _descriptors);
+ else if (image.depth() == CV_8S)
- computeDescriptors<uchar, double>(grayImage, keypoints, descriptors);
++ computeDescriptors<char, int>(grayImage, keypoints, _descriptors);
+ else
+ CV_Error( Error::StsUnsupportedFormat, "" );
+ } else {
+ // Create the integral image appropriate for our type & usage
+ if ( image.depth() == CV_8U )
- computeDescriptors<char, double>(grayImage, keypoints, descriptors);
++ computeDescriptors<uchar, double>(grayImage, keypoints, _descriptors);
+ else if ( image.depth() == CV_8S )
- computeDescriptors<ushort, double>(grayImage, keypoints, descriptors);
++ computeDescriptors<char, double>(grayImage, keypoints, _descriptors);
+ else if ( image.depth() == CV_16U )
- computeDescriptors<short, double>(grayImage, keypoints, descriptors);
++ computeDescriptors<ushort, double>(grayImage, keypoints, _descriptors);
+ else if ( image.depth() == CV_16S )
- void FREAK::computeDescriptors( const Mat& image, std::vector<KeyPoint>& keypoints, Mat& descriptors ) const {
++ computeDescriptors<short, double>(grayImage, keypoints, _descriptors);
+ else
+ CV_Error( Error::StsUnsupportedFormat, "" );
+ }
+}
+
+template <typename srcMatType>
+void FREAK::extractDescriptor(srcMatType *pointsValue, void ** ptr) const
+{
+ std::bitset<FREAK_NB_PAIRS>** ptrScalar = (std::bitset<FREAK_NB_PAIRS>**) ptr;
+
+ // extracting descriptor preserving the order of SSE version
+ int cnt = 0;
+ for( int n = 7; n < FREAK_NB_PAIRS; n += 128)
+ {
+ for( int m = 8; m--; )
+ {
+ int nm = n-m;
+ for(int kk = nm+15*8; kk >= nm; kk-=8, ++cnt)
+ {
+ (*ptrScalar)->set(kk, pointsValue[descriptionPairs[cnt].i] >= pointsValue[descriptionPairs[cnt].j]);
+ }
+ }
+ }
+ --(*ptrScalar);
+}
+
+#if CV_SSE2
+template <>
+void FREAK::extractDescriptor(uchar *pointsValue, void ** ptr) const
+{
+ __m128i** ptrSSE = (__m128i**) ptr;
+
+ // note that comparisons order is modified in each block (but first 128 comparisons remain globally the same-->does not affect the 128,384 bits segmanted matching strategy)
+ int cnt = 0;
+ for( int n = FREAK_NB_PAIRS/128; n-- ; )
+ {
+ __m128i result128 = _mm_setzero_si128();
+ for( int m = 128/16; m--; cnt += 16 )
+ {
+ __m128i operand1 = _mm_set_epi8(pointsValue[descriptionPairs[cnt+0].i],
+ pointsValue[descriptionPairs[cnt+1].i],
+ pointsValue[descriptionPairs[cnt+2].i],
+ pointsValue[descriptionPairs[cnt+3].i],
+ pointsValue[descriptionPairs[cnt+4].i],
+ pointsValue[descriptionPairs[cnt+5].i],
+ pointsValue[descriptionPairs[cnt+6].i],
+ pointsValue[descriptionPairs[cnt+7].i],
+ pointsValue[descriptionPairs[cnt+8].i],
+ pointsValue[descriptionPairs[cnt+9].i],
+ pointsValue[descriptionPairs[cnt+10].i],
+ pointsValue[descriptionPairs[cnt+11].i],
+ pointsValue[descriptionPairs[cnt+12].i],
+ pointsValue[descriptionPairs[cnt+13].i],
+ pointsValue[descriptionPairs[cnt+14].i],
+ pointsValue[descriptionPairs[cnt+15].i]);
+
+ __m128i operand2 = _mm_set_epi8(pointsValue[descriptionPairs[cnt+0].j],
+ pointsValue[descriptionPairs[cnt+1].j],
+ pointsValue[descriptionPairs[cnt+2].j],
+ pointsValue[descriptionPairs[cnt+3].j],
+ pointsValue[descriptionPairs[cnt+4].j],
+ pointsValue[descriptionPairs[cnt+5].j],
+ pointsValue[descriptionPairs[cnt+6].j],
+ pointsValue[descriptionPairs[cnt+7].j],
+ pointsValue[descriptionPairs[cnt+8].j],
+ pointsValue[descriptionPairs[cnt+9].j],
+ pointsValue[descriptionPairs[cnt+10].j],
+ pointsValue[descriptionPairs[cnt+11].j],
+ pointsValue[descriptionPairs[cnt+12].j],
+ pointsValue[descriptionPairs[cnt+13].j],
+ pointsValue[descriptionPairs[cnt+14].j],
+ pointsValue[descriptionPairs[cnt+15].j]);
+
+ __m128i workReg = _mm_min_epu8(operand1, operand2); // emulated "not less than" for 8-bit UNSIGNED integers
+ workReg = _mm_cmpeq_epi8(workReg, operand2); // emulated "not less than" for 8-bit UNSIGNED integers
+
+ workReg = _mm_and_si128(_mm_set1_epi16(short(0x8080 >> m)), workReg); // merge the last 16 bits with the 128bits std::vector until full
+ result128 = _mm_or_si128(result128, workReg);
+ }
+ (**ptrSSE) = result128;
+ ++(*ptrSSE);
+ }
+ (*ptrSSE) -= 8;
+}
+#endif
+
+template <typename srcMatType, typename iiMatType>
++void FREAK::computeDescriptors( InputArray _image, std::vector<KeyPoint>& keypoints, OutputArray _descriptors ) const {
+
++ Mat image = _image.getMat();
Mat imgIntegral;
- integral(image, imgIntegral);
+ integral(image, imgIntegral, DataType<iiMatType>::type);
std::vector<int> kpScaleIdx(keypoints.size()); // used to save pattern scale index corresponding to each keypoints
const std::vector<int>::iterator ScaleIdxBegin = kpScaleIdx.begin(); // used in std::vector erase function
const std::vector<cv::KeyPoint>::iterator kpBegin = keypoints.begin(); // used in std::vector erase function
}
// allocate descriptor memory, estimate orientations, extract descriptors
- if( !extAll ) {
+ if( !extAll )
+ {
// extract the best comparisons only
- descriptors = cv::Mat::zeros((int)keypoints.size(), FREAK_NB_PAIRS/8, CV_8U);
+ _descriptors.create((int)keypoints.size(), FREAK_NB_PAIRS/8, CV_8U);
+ _descriptors.setTo(Scalar::all(0));
+ Mat descriptors = _descriptors.getMat();
-#if CV_SSE2
- __m128i* ptr= (__m128i*) (descriptors.data+(keypoints.size()-1)*descriptors.step[0]);
-#else
- std::bitset<FREAK_NB_PAIRS>* ptr = (std::bitset<FREAK_NB_PAIRS>*) (descriptors.data+(keypoints.size()-1)*descriptors.step[0]);
-#endif
- for( size_t k = keypoints.size(); k--; )
- {
++
+ void *ptr = descriptors.data+(keypoints.size()-1)*descriptors.step[0];
+
+ for( size_t k = keypoints.size(); k--; ) {
// estimate orientation (gradient)
- if( !orientationNormalized ) {
+ if( !orientationNormalized )
+ {
thetaIdx = 0; // assign 0° to all keypoints
keypoints[k].angle = 0.0;
}
- else {
+ else
+ {
// get the points intensity value in the un-rotated pattern
- for( int i = FREAK_NB_POINTS; i--; )
- {
- pointsValue[i] = meanIntensity(image, imgIntegral, keypoints[k].pt.x,keypoints[k].pt.y, kpScaleIdx[k], 0, i);
+ for( int i = FREAK_NB_POINTS; i--; ) {
+ pointsValue[i] = meanIntensity<srcMatType, iiMatType>(image, imgIntegral,
+ keypoints[k].pt.x, keypoints[k].pt.y,
+ kpScaleIdx[k], 0, i);
}
direction0 = 0;
direction1 = 0;
thetaIdx -= FREAK_NB_ORIENTATION;
}
// extract descriptor at the computed orientation
- for( int i = FREAK_NB_POINTS; i--; )
- {
- pointsValue[i] = meanIntensity(image, imgIntegral, keypoints[k].pt.x,keypoints[k].pt.y, kpScaleIdx[k], thetaIdx, i);
+ for( int i = FREAK_NB_POINTS; i--; ) {
+ pointsValue[i] = meanIntensity<srcMatType, iiMatType>(image, imgIntegral,
+ keypoints[k].pt.x, keypoints[k].pt.y,
+ kpScaleIdx[k], thetaIdx, i);
}
-#if CV_SSE2
- // note that comparisons order is modified in each block (but first 128 comparisons remain globally the same-->does not affect the 128,384 bits segmanted matching strategy)
- int cnt = 0;
- for( int n = FREAK_NB_PAIRS/128; n-- ; )
- {
- __m128i result128 = _mm_setzero_si128();
- for( int m = 128/16; m--; cnt += 16 )
- {
- __m128i operand1 = _mm_set_epi8(
- pointsValue[descriptionPairs[cnt+0].i],
- pointsValue[descriptionPairs[cnt+1].i],
- pointsValue[descriptionPairs[cnt+2].i],
- pointsValue[descriptionPairs[cnt+3].i],
- pointsValue[descriptionPairs[cnt+4].i],
- pointsValue[descriptionPairs[cnt+5].i],
- pointsValue[descriptionPairs[cnt+6].i],
- pointsValue[descriptionPairs[cnt+7].i],
- pointsValue[descriptionPairs[cnt+8].i],
- pointsValue[descriptionPairs[cnt+9].i],
- pointsValue[descriptionPairs[cnt+10].i],
- pointsValue[descriptionPairs[cnt+11].i],
- pointsValue[descriptionPairs[cnt+12].i],
- pointsValue[descriptionPairs[cnt+13].i],
- pointsValue[descriptionPairs[cnt+14].i],
- pointsValue[descriptionPairs[cnt+15].i]);
-
- __m128i operand2 = _mm_set_epi8(
- pointsValue[descriptionPairs[cnt+0].j],
- pointsValue[descriptionPairs[cnt+1].j],
- pointsValue[descriptionPairs[cnt+2].j],
- pointsValue[descriptionPairs[cnt+3].j],
- pointsValue[descriptionPairs[cnt+4].j],
- pointsValue[descriptionPairs[cnt+5].j],
- pointsValue[descriptionPairs[cnt+6].j],
- pointsValue[descriptionPairs[cnt+7].j],
- pointsValue[descriptionPairs[cnt+8].j],
- pointsValue[descriptionPairs[cnt+9].j],
- pointsValue[descriptionPairs[cnt+10].j],
- pointsValue[descriptionPairs[cnt+11].j],
- pointsValue[descriptionPairs[cnt+12].j],
- pointsValue[descriptionPairs[cnt+13].j],
- pointsValue[descriptionPairs[cnt+14].j],
- pointsValue[descriptionPairs[cnt+15].j]);
-
- __m128i workReg = _mm_min_epu8(operand1, operand2); // emulated "not less than" for 8-bit UNSIGNED integers
- workReg = _mm_cmpeq_epi8(workReg, operand2); // emulated "not less than" for 8-bit UNSIGNED integers
-
- workReg = _mm_and_si128(_mm_set1_epi16(short(0x8080 >> m)), workReg); // merge the last 16 bits with the 128bits std::vector until full
- result128 = _mm_or_si128(result128, workReg);
- }
- (*ptr) = result128;
- ++ptr;
- }
- ptr -= 8;
-#else
- // extracting descriptor preserving the order of SSE version
- int cnt = 0;
- for( int n = 7; n < FREAK_NB_PAIRS; n += 128)
- {
- for( int m = 8; m--; )
- {
- int nm = n-m;
- for(int kk = nm+15*8; kk >= nm; kk-=8, ++cnt)
- {
- ptr->set(kk, pointsValue[descriptionPairs[cnt].i] >= pointsValue[descriptionPairs[cnt].j]);
- }
- }
- }
- --ptr;
-#endif
+
+ // Extract descriptor
+ extractDescriptor<srcMatType>(pointsValue, &ptr);
}
}
- else { // extract all possible comparisons for selection
- descriptors = cv::Mat::zeros((int)keypoints.size(), 128, CV_8U);
+ else // extract all possible comparisons for selection
+ {
+ _descriptors.create((int)keypoints.size(), 128, CV_8U);
+ _descriptors.setTo(Scalar::all(0));
+ Mat descriptors = _descriptors.getMat();
std::bitset<1024>* ptr = (std::bitset<1024>*) (descriptors.data+(keypoints.size()-1)*descriptors.step[0]);
- for( size_t k = keypoints.size(); k--; ) {
+ for( size_t k = keypoints.size(); k--; )
+ {
//estimate orientation (gradient)
- if( !orientationNormalized ) {
+ if( !orientationNormalized )
+ {
thetaIdx = 0;//assign 0° to all keypoints
keypoints[k].angle = 0.0;
}
- else {
+ else
+ {
//get the points intensity value in the un-rotated pattern
for( int i = FREAK_NB_POINTS;i--; )
- pointsValue[i] = meanIntensity(image, imgIntegral, keypoints[k].pt.x,keypoints[k].pt.y, kpScaleIdx[k], 0, i);
+ pointsValue[i] = meanIntensity<srcMatType, iiMatType>(image, imgIntegral,
+ keypoints[k].pt.x,keypoints[k].pt.y,
+ kpScaleIdx[k], 0, i);
direction0 = 0;
direction1 = 0;
}
// simply take average on a square patch, not even gaussian approx
-uchar FREAK::meanIntensity( InputArray _image, InputArray _integral,
- const float kp_x,
- const float kp_y,
- const unsigned int scale,
- const unsigned int rot,
- const unsigned int point) const
-{
+template <typename imgType, typename iiType>
- imgType FREAK::meanIntensity( const cv::Mat& image, const cv::Mat& integral,
++imgType FREAK::meanIntensity( InputArray _image, InputArray _integral,
+ const float kp_x,
+ const float kp_y,
+ const unsigned int scale,
+ const unsigned int rot,
+ const unsigned int point) const {
+ Mat image = _image.getMat(), integral = _integral.getMat();
// get point position in image
const PatternPoint& FreakPoint = patternLookup[scale*FREAK_NB_ORIENTATION*FREAK_NB_POINTS + rot*FREAK_NB_POINTS + point];
const float xf = FreakPoint.x+kp_x;