parent
2a63746177
commit
9c1d01e22a
10 changed files with 1297 additions and 5 deletions
@ -1,4 +1,5 @@ |
||||
set(the_description "Contributed/Experimental Algorithms for Salient 2D Features Detection") |
||||
ocv_define_module(xfeatures2d opencv_core opencv_imgproc opencv_features2d opencv_calib3d opencv_shape opencv_highgui opencv_videoio opencv_ml |
||||
OPTIONAL opencv_cudaarithm WRAP python java) |
||||
include(cmake/download_vgg.cmake) |
||||
include(cmake/download_vgg.cmake) |
||||
include(cmake/download_boostdesc.cmake) |
||||
|
@ -0,0 +1,30 @@ |
||||
|
||||
set(OPENCV_3RDPARTY_COMMIT "34e4206aef44d50e6bbcd0ab06354b52e7466d26") |
||||
set(FILE_HASH_BOOSTDESC_BGM "0ea90e7a8f3f7876d450e4149c97c74f") |
||||
set(FILE_HASH_BOOSTDESC_BGM_BI "232c966b13651bd0e46a1497b0852191") |
||||
set(FILE_HASH_BOOSTDESC_BGM_HD "324426a24fa56ad9c5b8e3e0b3e5303e") |
||||
set(FILE_HASH_BOOSTDESC_BINBOOST_064 "202e1b3e9fec871b04da31f7f016679f") |
||||
set(FILE_HASH_BOOSTDESC_BINBOOST_128 "98ea99d399965c03d555cef3ea502a0b") |
||||
set(FILE_HASH_BOOSTDESC_BINBOOST_256 "e6dcfa9f647779eb1ce446a8d759b6ea") |
||||
set(FILE_HASH_BOOSTDESC_LBGM "0ae0675534aa318d9668f2a179c2a052") |
||||
|
||||
|
||||
|
||||
set(BOOSTDESC_DOWNLOAD_URL ${OPENCV_CONTRIB_BOOSTDESC_URL};$ENV{OPENCV_CONTRIB_BOOSTDESC_URL};https://raw.githubusercontent.com/opencv/opencv_3rdparty/${OPENCV_3RDPARTY_COMMIT}/) |
||||
|
||||
function(boostdesc_download file id) |
||||
message(STATUS "Check contents of ${file} ...") |
||||
ocv_download(PACKAGE ${file} |
||||
HASH ${FILE_HASH_${id}} |
||||
URL ${BOOSTDESC_DOWNLOAD_URL} |
||||
DESTINATION_DIR ${CMAKE_CURRENT_LIST_DIR}/../src |
||||
DOWNLOAD_DIR ${CMAKE_CURRENT_LIST_DIR}/.download) |
||||
endfunction() |
||||
|
||||
boostdesc_download(boostdesc_bgm.i BOOSTDESC_BGM) |
||||
boostdesc_download(boostdesc_bgm_bi.i BOOSTDESC_BGM_BI) |
||||
boostdesc_download(boostdesc_bgm_hd.i BOOSTDESC_BGM_HD) |
||||
boostdesc_download(boostdesc_binboost_064.i BOOSTDESC_BINBOOST_064) |
||||
boostdesc_download(boostdesc_binboost_128.i BOOSTDESC_BINBOOST_128) |
||||
boostdesc_download(boostdesc_binboost_256.i BOOSTDESC_BINBOOST_256) |
||||
boostdesc_download(boostdesc_lbgm.i BOOSTDESC_LBGM) |
@ -0,0 +1,293 @@ |
||||
#!/usr/bin/python |
||||
|
||||
""" |
||||
|
||||
/********************************************************************* |
||||
* Software License Agreement (BSD License) |
||||
* |
||||
* Copyright (c) 2016 |
||||
* |
||||
* Balint Cristian <cristian dot balint at gmail dot com> |
||||
* |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following |
||||
* disclaimer in the documentation and/or other materials provided |
||||
* with the distribution. |
||||
* * Neither the name of the copyright holders nor the names of its |
||||
* contributors may be used to endorse or promote products derived |
||||
* from this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||||
* POSSIBILITY OF SUCH DAMAGE. |
||||
*********************************************************************/ |
||||
|
||||
/* export-boostdesc.py */ |
||||
/* Export C headers from binary data */ |
||||
// [http://infoscience.epfl.ch/record/186246/files/boostDesc_1.0.tar.gz] |
||||
|
||||
""" |
||||
|
||||
import sys |
||||
import struct |
||||
|
||||
|
||||
|
||||
def float_to_hex(f): |
||||
return struct.unpack( '<I', struct.pack('<f', f) )[0] |
||||
|
||||
def main(): |
||||
|
||||
# usage |
||||
if ( len(sys.argv) < 3 ): |
||||
print( "Usage: %s <binary-type (BGM, LBGM, BINBOOST)> <boostdesc-binary-filename>" % sys.argv[0] ) |
||||
sys.exit(0) |
||||
|
||||
|
||||
if ( ( sys.argv[1] != "BGM" ) and |
||||
( sys.argv[1] != "LBGM" ) and |
||||
( sys.argv[1] != "BINBOOST" ) ): |
||||
print( "Invalid type [%s]" % sys.argv[1] ) |
||||
sys.exit(0) |
||||
|
||||
# enum literals |
||||
Assign = [ "ASSIGN_HARD", |
||||
"ASSIGN_BILINEAR", |
||||
"ASSIGN_SOFT", |
||||
"ASSIGN_HARD_MAGN", |
||||
"ASSIGN_SOFT_MAGN" ] |
||||
|
||||
# open binary data file |
||||
f = open( sys.argv[2], 'rb' ) |
||||
|
||||
# header |
||||
print "/*" |
||||
print " *" |
||||
print " * Header exported from binary." |
||||
print " * [%s %s %s]" % ( sys.argv[0], sys.argv[1], sys.argv[2] ) |
||||
print " *" |
||||
print " */" |
||||
|
||||
# ini |
||||
nDim = 1; |
||||
nWLs = 0; |
||||
|
||||
# dimensionality (where is the case) |
||||
if ( ( sys.argv[1] == "LBGM" ) or |
||||
( sys.argv[1] == "BINBOOST" ) ): |
||||
nDim = struct.unpack( '<i', f.read(4) )[0] |
||||
|
||||
print |
||||
print "// dimensionality of learner" |
||||
print "static const int nDim = %i;" % nDim |
||||
|
||||
# week learners (where is the case) |
||||
if ( sys.argv[1] != "BINBOOST" ): |
||||
nWLs = struct.unpack( '<i', f.read(4) )[0] |
||||
|
||||
# common header |
||||
orientQuant = struct.unpack( '<i', f.read(4) )[0] |
||||
patchSize = struct.unpack( '<i', f.read(4) )[0] |
||||
iGradAssignType = struct.unpack( '<i', f.read(4) )[0] |
||||
|
||||
print |
||||
print "// orientations" |
||||
print "static const int orientQuant = %i;" % orientQuant |
||||
|
||||
print |
||||
print "// patch size" |
||||
print "static const int patchSize = %i;" % patchSize |
||||
|
||||
print |
||||
print "// gradient assignment type" |
||||
print "static const int iGradAssignType = %s;" % Assign[iGradAssignType] |
||||
|
||||
arr_thresh = "" |
||||
arr_orient = "" |
||||
|
||||
arr__y_min = "" |
||||
arr__y_max = "" |
||||
arr__x_min = "" |
||||
arr__x_max = "" |
||||
|
||||
arr__alpha = "" |
||||
arr___beta = "" |
||||
|
||||
|
||||
dims = nDim |
||||
if ( sys.argv[1] == "LBGM" ): |
||||
dims = 1 |
||||
|
||||
# iterate each dimension |
||||
for d in range( 0, dims ): |
||||
|
||||
if ( sys.argv[1] == "BINBOOST" ): |
||||
nWLs = struct.unpack( '<i', f.read(4) )[0] |
||||
|
||||
if ( d == 0 ): |
||||
print |
||||
print "// number of weak learners" |
||||
print "static const int nWLs = %i;" % nWLs |
||||
|
||||
# iterate each members |
||||
for i in range( 0, nWLs ): |
||||
|
||||
# unpack structure array |
||||
thresh = struct.unpack( '<f', f.read(4) )[0] |
||||
orient = struct.unpack( '<i', f.read(4) )[0] |
||||
|
||||
y_min = struct.unpack( '<i', f.read(4) )[0] |
||||
y_max = struct.unpack( '<i', f.read(4) )[0] |
||||
x_min = struct.unpack( '<i', f.read(4) )[0] |
||||
x_max = struct.unpack( '<i', f.read(4) )[0] |
||||
|
||||
alpha = struct.unpack( '<f', f.read(4) )[0] |
||||
|
||||
beta = 0 |
||||
if ( sys.argv[1] == "BINBOOST" ): |
||||
beta = struct.unpack( '<f', f.read(4) )[0] |
||||
|
||||
# first entry |
||||
if ( d*dims + i == 0 ): |
||||
|
||||
arr_thresh += "\n" |
||||
arr_thresh += "// threshold array (%s x %s)\n" % (dims,nWLs) |
||||
arr_thresh += "static const unsigned int thresh[] =\n{\n" |
||||
|
||||
arr_orient += "\n" |
||||
arr_orient += "// orientation array (%s x %s)\n" % (dims,nWLs) |
||||
arr_orient += "static const int orient[] =\n{\n" |
||||
|
||||
arr__y_min += "\n" |
||||
arr__y_min += "// Y min array (%s x %s)\n" % (dims,nWLs) |
||||
arr__y_min += "static const int y_min[] =\n{\n" |
||||
|
||||
arr__y_max += "\n" |
||||
arr__y_max += "// Y max array (%s x %s)\n" % (dims,nWLs) |
||||
arr__y_max += "static const int y_max[] =\n{\n" |
||||
|
||||
arr__x_min += "\n" |
||||
arr__x_min += "// X min array (%s x %s)\n" % (dims,nWLs) |
||||
arr__x_min += "static const int x_min[] =\n{\n" |
||||
|
||||
arr__x_max += "\n" |
||||
arr__x_max += "// X max array (%s x %s)\n" % (dims,nWLs) |
||||
arr__x_max += "static const int x_max[] =\n{\n" |
||||
|
||||
arr__alpha += "\n" |
||||
arr__alpha += "// alpha array (%s x %s)\n" % (dims,nWLs) |
||||
arr__alpha += "static const unsigned int alpha[] =\n{\n" |
||||
|
||||
if ( sys.argv[1] == "BINBOOST" ): |
||||
arr___beta += "\n" |
||||
arr___beta += "// beta array (%s x %s)\n" % (dims,nWLs) |
||||
arr___beta += "static const unsigned int beta[] =\n{\n" |
||||
|
||||
# last entry |
||||
if ( i == nWLs - 1 ) and ( d == dims - 1): |
||||
|
||||
arr_thresh += " 0x%08x\n};" % float_to_hex(thresh) |
||||
arr_orient += " 0x%02x\n};" % orient |
||||
|
||||
arr__y_min += " 0x%02x\n};" % y_min |
||||
arr__y_max += " 0x%02x\n};" % y_max |
||||
arr__x_min += " 0x%02x\n};" % x_min |
||||
arr__x_max += " 0x%02x\n};" % x_max |
||||
|
||||
arr__alpha += " 0x%08x\n};" % float_to_hex(alpha) |
||||
|
||||
if ( sys.argv[1] == "BINBOOST" ): |
||||
arr___beta += " 0x%08x\n};" % float_to_hex(beta) |
||||
|
||||
break |
||||
|
||||
# align entries |
||||
if ( (d*dims + i + 1) % 8 ): |
||||
|
||||
arr_thresh += " 0x%08x," % float_to_hex(thresh) |
||||
arr_orient += " 0x%02x," % orient |
||||
|
||||
arr__y_min += " 0x%02x," % y_min |
||||
arr__y_max += " 0x%02x," % y_max |
||||
arr__x_min += " 0x%02x," % x_min |
||||
arr__x_max += " 0x%02x," % x_max |
||||
|
||||
arr__alpha += " 0x%08x," % float_to_hex(alpha) |
||||
|
||||
if ( sys.argv[1] == "BINBOOST" ): |
||||
arr___beta += " 0x%08x," % float_to_hex(beta) |
||||
|
||||
else: |
||||
|
||||
arr_thresh += " 0x%08x,\n" % float_to_hex(thresh) |
||||
arr_orient += " 0x%02x,\n" % orient |
||||
|
||||
arr__y_min += " 0x%02x,\n" % y_min |
||||
arr__y_max += " 0x%02x,\n" % y_max |
||||
arr__x_min += " 0x%02x,\n" % x_min |
||||
arr__x_max += " 0x%02x,\n" % x_max |
||||
|
||||
arr__alpha += " 0x%08x,\n" % float_to_hex(alpha) |
||||
|
||||
if ( sys.argv[1] == "BINBOOST" ): |
||||
arr___beta += " 0x%08x,\n" % float_to_hex(beta) |
||||
|
||||
# extra array (when LBGM) |
||||
if ( sys.argv[1] == "LBGM" ): |
||||
|
||||
arr___beta += "\n" |
||||
arr___beta += "// beta array (%s x %s)\n" % (nWLs,nDim) |
||||
arr___beta += "static const unsigned int beta[] =\n{\n" |
||||
|
||||
for i in range( 0, nWLs ): |
||||
for d in range( 0, nDim ): |
||||
beta = struct.unpack( '<f', f.read(4) )[0] |
||||
|
||||
# last entry |
||||
if ( i == nWLs-1 ) and ( d == nDim-1 ): |
||||
arr___beta += " 0x%08x\n};" % float_to_hex(beta) |
||||
break |
||||
|
||||
# align entries |
||||
if ( (i*nDim + d + 1) % 8 ): |
||||
arr___beta += " 0x%08x," % float_to_hex(beta) |
||||
else: |
||||
arr___beta += " 0x%08x,\n" % float_to_hex(beta) |
||||
|
||||
# release |
||||
f.close() |
||||
|
||||
# dump on screen |
||||
print arr_thresh |
||||
print arr_orient |
||||
|
||||
print arr__y_min |
||||
print arr__y_max |
||||
print arr__x_min |
||||
print arr__x_max |
||||
|
||||
print arr__alpha |
||||
|
||||
if ( ( sys.argv[1] == "LBGM" ) or |
||||
( sys.argv[1] == "BINBOOST" ) ): |
||||
print arr___beta |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
main() |
@ -0,0 +1,731 @@ |
||||
/*********************************************************************
|
||||
* Software License Agreement (BSD License) |
||||
* |
||||
* Copyright (c) 2013, 2016 |
||||
* |
||||
* Tomasz Trzcinski <t dot trzcinski at ii dot pw dot edu dot pl> |
||||
* Mario Christoudias <mariochristoudias at gmail dot com> |
||||
* Vincent Lepetit <lepetit at icg dot tugraz dot at> |
||||
* |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following |
||||
* disclaimer in the documentation and/or other materials provided |
||||
* with the distribution. |
||||
* * Neither the name of the copyright holders nor the names of its |
||||
* contributors may be used to endorse or promote products derived |
||||
* from this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||||
* POSSIBILITY OF SUCH DAMAGE. |
||||
*********************************************************************/ |
||||
|
||||
/*
|
||||
|
||||
"Learning Image Descriptors with Boosting" |
||||
T. Trzcinski, M. Christoudias and V. Lepetit |
||||
IEEE Transactions on Pattern Analysis and Machine Intelligence, 2013 |
||||
|
||||
"Boosting Binary Keypoint Descriptors" |
||||
T. Trzcinski, M. Christoudias, V. Lepetit and P. Fua |
||||
Computer Vision and Pattern Recognition (CVPR), 2013 |
||||
|
||||
Original code: Tomasz Trzcinski <t dot trzcinski at ii dot pw dot edu dot pl> |
||||
OpenCV port by: Cristian Balint <cristian dot balint at gmail dot com> |
||||
|
||||
*/ |
||||
|
||||
#include <bitset> |
||||
#include "precomp.hpp" |
||||
|
||||
|
||||
|
||||
using namespace cv; |
||||
using namespace std; |
||||
|
||||
|
||||
namespace cv |
||||
{ |
||||
namespace xfeatures2d |
||||
{ |
||||
|
||||
/*
|
||||
!BoostDesc implementation |
||||
*/ |
||||
class BoostDesc_Impl : public BoostDesc |
||||
{ |
||||
|
||||
public: |
||||
|
||||
// constructor
|
||||
explicit BoostDesc_Impl( int desc = BINBOOST_256, |
||||
bool use_scale_orientation = true, |
||||
float scale_factor = 6.25f ); |
||||
|
||||
// destructor
|
||||
virtual ~BoostDesc_Impl(); |
||||
|
||||
// returns the descriptor length in bytes
|
||||
virtual int descriptorSize() const { return m_descriptor_size; } |
||||
|
||||
// returns the descriptor type
|
||||
virtual int descriptorType() const { return m_descriptor_type; } |
||||
|
||||
// returns the default norm type
|
||||
virtual int defaultNorm() const { return m_descriptor_norm; } |
||||
|
||||
// compute descriptors given keypoints
|
||||
virtual void compute( InputArray image, vector<KeyPoint>& keypoints, OutputArray descriptors ); |
||||
|
||||
protected: |
||||
|
||||
/*
|
||||
* BoostDesc parameters |
||||
*/ |
||||
|
||||
// size, type, norm
|
||||
int m_descriptor_size; |
||||
int m_descriptor_type; |
||||
int m_descriptor_norm; |
||||
|
||||
// desc type
|
||||
int m_desc_type; |
||||
|
||||
// gradient
|
||||
// assignment types
|
||||
enum Assign |
||||
{ |
||||
ASSIGN_HARD = 0, |
||||
ASSIGN_BILINEAR = 1, |
||||
ASSIGN_SOFT = 2, |
||||
ASSIGN_HARD_MAGN = 3, |
||||
ASSIGN_SOFT_MAGN = 4 |
||||
}; |
||||
|
||||
// dims
|
||||
int m_Dims; |
||||
|
||||
// no. weak
|
||||
// learners
|
||||
int m_nWLs; |
||||
|
||||
// gradient type
|
||||
int m_grad_atype; |
||||
|
||||
// patch size
|
||||
int m_patch_size; |
||||
|
||||
// orient quantitiy
|
||||
int m_orient_q; |
||||
|
||||
// patch scale factor
|
||||
float m_scale_factor; |
||||
|
||||
/*
|
||||
* BoostDesc switches |
||||
*/ |
||||
|
||||
// switch to enable sample by keypoints orientation
|
||||
bool m_use_scale_orientation; |
||||
|
||||
|
||||
/*
|
||||
* BoostDesc arrays |
||||
*/ |
||||
|
||||
// image
|
||||
Mat m_image; |
||||
|
||||
// parameters
|
||||
// weak learner
|
||||
Mat m_wl_thresh; |
||||
Mat m_wl_orient; |
||||
Mat m_wl_x_min, m_wl_x_max; |
||||
Mat m_wl_y_min, m_wl_y_max; |
||||
Mat m_wl_alpha, m_wl_beta; |
||||
|
||||
private: |
||||
|
||||
/*
|
||||
* BoostDesc functions |
||||
*/ |
||||
|
||||
// initialize parameters
|
||||
inline void ini_params( const int orientQuant, const int patchSize, |
||||
const int iGradAssignType, |
||||
const int nDim, const int nWLs, |
||||
const unsigned int thresh[], const int orient[], |
||||
const int x_min[], const int x_max[], |
||||
const int y_min[], const int y_max[], |
||||
const unsigned int alpha[], const unsigned int beta[] ); |
||||
|
||||
}; // END BoostDesc_Impl CLASS
|
||||
|
||||
// -------------------------------------------------
|
||||
/* BoostDesc internal routines */ |
||||
|
||||
static void computeGradientMaps( const Mat& im, |
||||
const int gradAssignType, |
||||
const int orientQuant, |
||||
vector<Mat>& gradMap ) |
||||
{ |
||||
enum Assign |
||||
{ |
||||
ASSIGN_HARD = 0, |
||||
ASSIGN_BILINEAR = 1, |
||||
ASSIGN_SOFT = 2, |
||||
ASSIGN_HARD_MAGN = 3, |
||||
ASSIGN_SOFT_MAGN = 4 |
||||
}; |
||||
|
||||
Mat derivx( im.size(), CV_32FC1 ); |
||||
Mat derivy( im.size(), CV_32FC1 ); |
||||
|
||||
Sobel( im, derivx, derivx.depth(), 1, 0 ); |
||||
Sobel( im, derivy, derivy.depth(), 0, 1 ); |
||||
|
||||
for ( int i = 0; i < orientQuant; i++ ) |
||||
gradMap.push_back( Mat::zeros( im.size(), CV_8UC1 ) ); |
||||
|
||||
int index, index2; |
||||
double binCenter, weight; |
||||
double binSize = (2 * CV_PI) / orientQuant; |
||||
|
||||
// fill in temp matrices with
|
||||
// respones to edge detection
|
||||
const float* pDerivx = derivx.ptr<float>(); |
||||
const float* pDerivy = derivy.ptr<float>(); |
||||
|
||||
for ( int i = 0; i < im.rows; i++ ) |
||||
{ |
||||
for ( int j = 0; j < im.cols; j++ ) |
||||
{ |
||||
float gradMagnitude = sqrt( (*pDerivx) * (*pDerivx) |
||||
+ (*pDerivy) * (*pDerivy) ); |
||||
if ( gradMagnitude > 20 ) |
||||
{ |
||||
double theta = atan2( *pDerivy, *pDerivx ); |
||||
theta = ( theta < 0 ) ? theta + 2*CV_PI : theta; |
||||
index = int( theta / binSize ); |
||||
index = ( index == orientQuant ) ? 0 : index; |
||||
|
||||
switch ( gradAssignType ) |
||||
{ |
||||
case ASSIGN_HARD: |
||||
gradMap[index].at<uchar>(i,j) = 1; |
||||
break; |
||||
|
||||
case ASSIGN_HARD_MAGN: |
||||
gradMap[index].at<uchar>(i,j) = (uchar) round( gradMagnitude ); |
||||
break; |
||||
|
||||
case ASSIGN_BILINEAR: |
||||
index2 = (int) ceil( theta / binSize ); |
||||
index2 = ( index2 == orientQuant ) ? 0 : index2; |
||||
binCenter = ( index + 0.5f ) * binSize; |
||||
weight = 1 - abs( theta - binCenter ) / binSize; |
||||
gradMap[index ].at<uchar>(i,j) = (uchar) round( 255 * weight ); |
||||
gradMap[index2].at<uchar>(i,j) = (uchar) round( 255 * ( 1 - weight ) ); |
||||
break; |
||||
|
||||
case ASSIGN_SOFT: |
||||
for ( int binNum = 0; binNum < orientQuant/2 + 1; binNum++ ) |
||||
{ |
||||
index2 = ( binNum + index + orientQuant - orientQuant/4 ) % orientQuant; |
||||
binCenter = ( index2 + 0.5f ) * binSize; |
||||
weight = cos( theta - binCenter ); |
||||
weight = ( weight < 0 ) ? 0 : weight; |
||||
gradMap[index2].at<uchar>(i,j) = (uchar) round( 255 * weight ); |
||||
} |
||||
break; |
||||
|
||||
case ASSIGN_SOFT_MAGN: |
||||
for ( int binNum = 0; binNum < orientQuant/2 + 1; binNum++ ) |
||||
{ |
||||
index2 = ( binNum + index + orientQuant - orientQuant/4 ) % orientQuant; |
||||
binCenter = ( index2 + 0.5f ) * binSize; |
||||
weight = cos( theta - binCenter ); |
||||
weight = ( weight < 0 ) ? 0 : weight; |
||||
gradMap[index2].at<uchar>(i,j) = (uchar) round( gradMagnitude * weight ); |
||||
} |
||||
break; |
||||
} // end switch
|
||||
} |
||||
++pDerivy; |
||||
++pDerivx; |
||||
} |
||||
} |
||||
} |
||||
|
||||
static void computeIntegrals( const vector<Mat>& gradMap, |
||||
const int orientQuant, |
||||
vector<Mat>& integralMap ) |
||||
{ |
||||
// init integral images
|
||||
int rows = gradMap[0].rows; |
||||
int cols = gradMap[0].cols; |
||||
|
||||
for ( int i = 0; i < orientQuant+1; i++ ) |
||||
integralMap.push_back( Mat::zeros( rows+1, cols+1, CV_8UC1 ) ); |
||||
|
||||
// generate corresponding integral images
|
||||
for( int i = 0; i < orientQuant; i++ ) |
||||
integral( gradMap[i], integralMap[i] ); |
||||
|
||||
// copy the values from the first quantization bin
|
||||
integralMap[0].copyTo( integralMap[orientQuant] ); |
||||
|
||||
int* ptrSum, *ptr; |
||||
for ( int k = 1; k < orientQuant; k++ ) |
||||
{ |
||||
ptr = (int*) integralMap[k].ptr<int>(); |
||||
ptrSum = (int*) integralMap[orientQuant].ptr<int>(); |
||||
for (int i=0; i<(rows+1)*(cols+1); ++i) |
||||
{ |
||||
*ptrSum += *ptr; |
||||
++ptrSum; |
||||
++ptr; |
||||
} |
||||
} |
||||
} |
||||
|
||||
static float computeWLResponse( const int x_min, const int x_max, |
||||
const int y_min, const int y_max, |
||||
const int orient, const float thresh, |
||||
const int orientQuant, |
||||
const vector<Mat>& integralMap ) |
||||
{ |
||||
const int width = integralMap[0].cols; |
||||
|
||||
const int idx1 = (y_min ) * width + x_min; |
||||
const int idx2 = (y_min ) * width + x_max + 1; |
||||
const int idx3 = (y_max + 1) * width + x_min; |
||||
const int idx4 = (y_max + 1) * width + x_max + 1; |
||||
|
||||
const int* ptr = integralMap[orient].ptr<int>(); |
||||
|
||||
int A, B ,C, D; |
||||
A = ptr[idx1]; B = ptr[idx2]; |
||||
C = ptr[idx3]; D = ptr[idx4]; |
||||
|
||||
const float current = float(D + A - B - C); |
||||
|
||||
ptr = integralMap[orientQuant].ptr<int>(); |
||||
|
||||
A = ptr[idx1]; B = ptr[idx2]; |
||||
C = ptr[idx3]; D = ptr[idx4]; |
||||
|
||||
const float total = float(D + A - B - C); |
||||
|
||||
return total ? ( (current / total) - thresh ) : 0.f; |
||||
} |
||||
|
||||
static void rectifyPatch( const Mat& image, const KeyPoint& kp, |
||||
const int& patchSize, Mat& patch, |
||||
const bool use_scale_orientation, |
||||
const float scale_factor ) |
||||
{ |
||||
Mat M; |
||||
if ( use_scale_orientation ) |
||||
{ |
||||
const float s = scale_factor * (float) kp.size / (float) patchSize; |
||||
|
||||
const float cosine = (kp.angle>=0) ? cos(kp.angle*(float)CV_PI/180.0f) : 1.f; |
||||
const float sine = (kp.angle>=0) ? sin(kp.angle*(float)CV_PI/180.0f) : 0.f; |
||||
|
||||
float M_[] = { |
||||
s*cosine, -s*sine, (-s*cosine + s*sine ) * patchSize/2.0f + kp.pt.x, |
||||
s*sine, s*cosine, (-s*sine - s*cosine) * patchSize/2.0f + kp.pt.y |
||||
}; |
||||
M = Mat( 2, 3, CV_32FC1, M_ ).clone(); |
||||
} |
||||
else |
||||
{ |
||||
float M_[] = { |
||||
1.f, 0.f, -1.f * patchSize/2.0f + kp.pt.x, |
||||
0.f, 1.f, -1.f * patchSize/2.0f + kp.pt.y |
||||
}; |
||||
M = Mat( 2, 3, CV_32FC1, M_ ).clone(); |
||||
} |
||||
|
||||
warpAffine( image, patch, M, Size( patchSize, patchSize ), |
||||
WARP_INVERSE_MAP + INTER_CUBIC + WARP_FILL_OUTLIERS ); |
||||
} |
||||
|
||||
// -------------------------------------------------
|
||||
/* BoostDesc interface implementation */ |
||||
|
||||
struct ComputeBoostDescInvoker : ParallelLoopBody |
||||
{ |
||||
ComputeBoostDescInvoker( const Mat& _image, Mat* _descriptors, |
||||
const vector<KeyPoint>& _keypoints, |
||||
const int _desc_type, const int _grad_atype, |
||||
const int _orient_q, const int _patch_size, |
||||
const int _nWLs, const int _Dims, |
||||
const Mat& _wl_x_min, const Mat& _wl_x_max, |
||||
const Mat& _wl_y_min, const Mat& _wl_y_max, |
||||
const Mat& _wl_thresh, const Mat& _wl_orient, |
||||
const Mat& _wl_alpha, const Mat& _wl_beta, |
||||
const bool _use_scale_orientation, |
||||
const float _scale_factor ) |
||||
{ |
||||
nWLs = _nWLs; |
||||
Dims = _Dims; |
||||
image = _image; |
||||
orient_q = _orient_q; |
||||
desc_type = _desc_type; |
||||
keypoints = _keypoints; |
||||
grad_atype = _grad_atype; |
||||
patch_size = _patch_size; |
||||
descriptors = _descriptors; |
||||
|
||||
wl_beta = _wl_beta; |
||||
wl_alpha = _wl_alpha; |
||||
wl_x_min = _wl_x_min; |
||||
wl_x_max = _wl_x_max; |
||||
wl_y_min = _wl_y_min; |
||||
wl_y_max = _wl_y_max; |
||||
wl_thresh = _wl_thresh; |
||||
wl_orient = _wl_orient; |
||||
|
||||
scale_factor = _scale_factor; |
||||
use_scale_orientation = _use_scale_orientation; |
||||
} |
||||
|
||||
void operator ()( const cv::Range& range ) const |
||||
{ |
||||
// maps
|
||||
vector<Mat> gradMap, integralMap; |
||||
|
||||
// small binary map
|
||||
uchar binLookUp[8]; |
||||
for ( unsigned int i = 0; i < 8; i++ ) |
||||
binLookUp[i] = (uchar) 1 << i; |
||||
|
||||
for ( int i = range.start; i < range.end; i++ ) |
||||
{ |
||||
|
||||
Mat patch; |
||||
// rectify the patch around a given keypoint
|
||||
rectifyPatch( image, keypoints[i], patch_size, |
||||
patch, use_scale_orientation, scale_factor ); |
||||
|
||||
// compute gradient maps (and integral gradient maps)
|
||||
computeGradientMaps( patch, grad_atype, orient_q, gradMap ); |
||||
computeIntegrals( gradMap, orient_q, integralMap ); |
||||
|
||||
float WLR; |
||||
|
||||
/*
|
||||
* BGM |
||||
*/ |
||||
if ( ( desc_type == BGM ) || |
||||
( desc_type == BGM_HARD ) || |
||||
( desc_type == BGM_BILINEAR ) |
||||
) |
||||
{ |
||||
uchar* desc = descriptors->ptr<uchar>(i); |
||||
for ( int j = 0; j < nWLs; j++ ) |
||||
{ |
||||
WLR = computeWLResponse( wl_x_min.at<int>(0,j), wl_x_max.at<int>(0,j), |
||||
wl_y_min.at<int>(0,j), wl_y_max.at<int>(0,j), |
||||
wl_orient.at<int>(0,j), wl_thresh.at<float>(0,j), |
||||
orient_q, integralMap ); |
||||
desc[j/8] |= ( WLR >= 0 ) ? binLookUp[ j % 8 ] : 0; |
||||
} |
||||
} // end BGM
|
||||
|
||||
/*
|
||||
* LBGM |
||||
*/ |
||||
if ( desc_type == LBGM ) |
||||
{ |
||||
std::bitset<512> wlResponses; |
||||
|
||||
for ( int j = 0; j < nWLs; j++ ) |
||||
{ |
||||
WLR = computeWLResponse( wl_x_min.at<int>(0,j), wl_x_max.at<int>(0,j), |
||||
wl_y_min.at<int>(0,j), wl_y_max.at<int>(0,j), |
||||
wl_orient.at<int>(0,j), wl_thresh.at<float>(0,j), |
||||
orient_q, integralMap ); |
||||
wlResponses[j] = ( WLR >= 0 ) ? 1 : 0; |
||||
} |
||||
|
||||
float* desc = descriptors->ptr<float>(i); |
||||
for ( int d = 0; d < Dims; d++ ) |
||||
{ |
||||
for ( int wl = 0; wl < nWLs; wl++ ) |
||||
{ |
||||
desc[d] += ( wlResponses[wl] ) ? wl_beta.at<float>(wl,d) : -wl_beta.at<float>(wl,d); |
||||
} |
||||
} |
||||
} // end LBGM
|
||||
|
||||
/*
|
||||
* BINBOOST |
||||
*/ |
||||
if ( ( desc_type == BINBOOST_64 ) || |
||||
( desc_type == BINBOOST_128 ) || |
||||
( desc_type == BINBOOST_256 ) |
||||
) |
||||
{ |
||||
float resp; |
||||
for ( int d = 0; d < Dims; d++ ) |
||||
{ |
||||
resp = 0; |
||||
uchar* desc = descriptors->ptr<uchar>(i); |
||||
for ( int wl = 0; wl < nWLs; wl++ ) |
||||
{ |
||||
WLR = computeWLResponse( wl_x_min.at<int>(d,wl), wl_x_max.at<int>(d,wl), |
||||
wl_y_min.at<int>(d,wl), wl_y_max.at<int>(d,wl), |
||||
wl_orient.at<int>(d,wl), wl_thresh.at<float>(d,wl), |
||||
orient_q, integralMap ); |
||||
resp += ( WLR >= 0 ) ? wl_beta.at<float>(d,wl) : -wl_beta.at<float>(d,wl); |
||||
} |
||||
desc[d/8] |= ( resp >= 0 ) ? binLookUp[d%8] : 0; |
||||
} |
||||
} // end BINBOOST
|
||||
|
||||
// clean-up
|
||||
patch.release(); |
||||
gradMap.clear(); |
||||
integralMap.clear(); |
||||
|
||||
} // end for loop
|
||||
} // end operator
|
||||
|
||||
int nWLs; |
||||
int Dims; |
||||
int orient_q; |
||||
int desc_type; |
||||
int patch_size; |
||||
int grad_atype; |
||||
int patch_szie; |
||||
|
||||
Mat image; |
||||
Mat *descriptors; |
||||
vector<KeyPoint> keypoints; |
||||
|
||||
Mat wl_x_min, wl_x_max, wl_y_min, wl_y_max; |
||||
Mat wl_thresh, wl_orient, wl_alpha, wl_beta; |
||||
|
||||
float scale_factor; |
||||
bool use_scale_orientation; |
||||
|
||||
enum
|
||||
{ |
||||
BGM = 100, BGM_HARD = 101, BGM_BILINEAR = 102, LBGM = 200, |
||||
BINBOOST_64 = 300, BINBOOST_128 = 301, BINBOOST_256 = 302 |
||||
}; |
||||
}; |
||||
|
||||
// descriptor computation using keypoints
|
||||
void BoostDesc_Impl::compute( InputArray _image, vector<KeyPoint>& keypoints, OutputArray _descriptors ) |
||||
{ |
||||
// do nothing if no image
|
||||
if( _image.getMat().empty() ) |
||||
return; |
||||
|
||||
if( keypoints.empty() ) |
||||
return; |
||||
|
||||
m_image = _image.getMat().clone(); |
||||
|
||||
// Only 8bit images
|
||||
CV_Assert( m_image.depth() == CV_8U ); |
||||
|
||||
// convert to gray inplace
|
||||
if( m_image.channels() > 1 ) |
||||
cvtColor( m_image, m_image, COLOR_BGR2GRAY ); |
||||
|
||||
// initialize the variables
|
||||
_descriptors.create( (int)keypoints.size(), descriptorSize(), descriptorType() ); |
||||
_descriptors.setTo( Scalar::all(0) ); |
||||
|
||||
// descriptor storage
|
||||
Mat descriptors = _descriptors.getMat(); |
||||
|
||||
parallel_for_( Range( 0, (int) keypoints.size() ), |
||||
ComputeBoostDescInvoker( m_image, &descriptors, keypoints, |
||||
m_desc_type, m_grad_atype, m_orient_q, |
||||
m_patch_size, m_nWLs, m_Dims, |
||||
m_wl_x_min, m_wl_x_max, m_wl_y_min, m_wl_y_max, |
||||
m_wl_thresh, m_wl_orient, m_wl_alpha, m_wl_beta, |
||||
m_use_scale_orientation, m_scale_factor ) |
||||
); |
||||
} |
||||
|
||||
void BoostDesc_Impl::ini_params( const int orientQuant, const int patchSize, |
||||
const int iGradAssignType, |
||||
const int nDim, const int nWLs, |
||||
const unsigned int thresh[], const int orient[], |
||||
const int x_min[], const int x_max[], |
||||
const int y_min[], const int y_max[], |
||||
const unsigned int alpha[], const unsigned int beta[] ) |
||||
{ |
||||
// desc type, norm, size
|
||||
if ( m_desc_type == LBGM ) |
||||
{ |
||||
m_descriptor_size = nDim; |
||||
m_descriptor_norm = NORM_L2; |
||||
m_descriptor_type = CV_32FC1; |
||||
} |
||||
else |
||||
{ |
||||
if ( ( m_desc_type == BGM ) || |
||||
( m_desc_type == BGM_HARD ) || |
||||
( m_desc_type == BGM_BILINEAR ) |
||||
) |
||||
m_descriptor_size = nWLs / 8; |
||||
else |
||||
m_descriptor_size = nDim / 8; |
||||
|
||||
m_descriptor_type = CV_8UC1; |
||||
m_descriptor_norm = NORM_HAMMING; |
||||
} |
||||
|
||||
// 2d array dim
|
||||
int dim0 = nDim; |
||||
int dim1 = nWLs; |
||||
|
||||
// override beta dim0 on LBGM
|
||||
if ( m_desc_type == LBGM ) dim0 = 1; |
||||
|
||||
m_Dims = nDim; |
||||
m_nWLs = nWLs; |
||||
m_orient_q = orientQuant; |
||||
m_patch_size = patchSize; |
||||
m_grad_atype = iGradAssignType; |
||||
|
||||
// cast into opencv Mat type as float
|
||||
m_wl_thresh = Mat( dim0, dim1, CV_32F, reinterpret_cast<float *>(const_cast<unsigned int *>(thresh)) ); |
||||
m_wl_alpha = Mat( dim0, dim1, CV_32F, reinterpret_cast<float *>(const_cast<unsigned int *>(alpha )) ); |
||||
|
||||
// cast into opencv Mat type as integer
|
||||
m_wl_orient = Mat( dim0, dim1, CV_32S, const_cast<int *>(orient) ); |
||||
m_wl_x_min = Mat( dim0, dim1, CV_32S, const_cast<int *>(x_min ) ); |
||||
m_wl_x_max = Mat( dim0, dim1, CV_32S, const_cast<int *>(x_max ) ); |
||||
m_wl_y_min = Mat( dim0, dim1, CV_32S, const_cast<int *>(y_min ) ); |
||||
m_wl_y_max = Mat( dim0, dim1, CV_32S, const_cast<int *>(y_max ) ); |
||||
|
||||
// no beta
|
||||
if ( beta == NULL ) return; |
||||
|
||||
if ( m_desc_type == LBGM ) |
||||
m_wl_beta = Mat( dim1, nDim, CV_32F, reinterpret_cast<float *>(const_cast<unsigned int *>(beta)) ); |
||||
else |
||||
m_wl_beta = Mat( dim0, dim1, CV_32F, reinterpret_cast<float *>(const_cast<unsigned int *>(beta)) ); |
||||
} |
||||
|
||||
// constructor
|
||||
BoostDesc_Impl::BoostDesc_Impl( int _desc, bool _use_scale_orientation, float _scale_factor ) |
||||
: m_desc_type( _desc ), m_scale_factor( _scale_factor ), |
||||
m_use_scale_orientation( _use_scale_orientation ) |
||||
{ |
||||
// desc type
|
||||
switch ( m_desc_type ) |
||||
{ |
||||
case BGM: |
||||
{ |
||||
#include "boostdesc_bgm.i" |
||||
ini_params( orientQuant, patchSize, |
||||
iGradAssignType, |
||||
nDim, nWLs, thresh, orient, |
||||
x_min, x_max, y_min, y_max, |
||||
alpha, NULL ); |
||||
} |
||||
break; |
||||
case BGM_HARD: |
||||
{ |
||||
#include "boostdesc_bgm_hd.i" |
||||
ini_params( orientQuant, patchSize, |
||||
iGradAssignType, |
||||
nDim, nWLs, thresh, orient, |
||||
x_min, x_max, y_min, y_max, |
||||
alpha, NULL ); |
||||
} |
||||
break; |
||||
case BGM_BILINEAR: |
||||
{ |
||||
#include "boostdesc_bgm_bi.i" |
||||
ini_params( orientQuant, patchSize, |
||||
iGradAssignType, |
||||
nDim, nWLs, thresh, orient, |
||||
x_min, x_max, y_min, y_max, |
||||
alpha, NULL ); |
||||
} |
||||
break; |
||||
case LBGM: |
||||
{ |
||||
#include "boostdesc_lbgm.i" |
||||
ini_params( orientQuant, patchSize, |
||||
iGradAssignType, |
||||
nDim, nWLs, thresh, orient, |
||||
x_min, x_max, y_min, y_max, |
||||
alpha, beta ); |
||||
} |
||||
break; |
||||
case BINBOOST_64: |
||||
{ |
||||
#include "boostdesc_binboost_064.i" |
||||
ini_params( orientQuant, patchSize, |
||||
iGradAssignType, |
||||
nDim, nWLs, thresh, orient, |
||||
x_min, x_max, y_min, y_max, |
||||
alpha, beta ); |
||||
} |
||||
break; |
||||
case BINBOOST_128: |
||||
{ |
||||
#include "boostdesc_binboost_128.i" |
||||
ini_params( orientQuant, patchSize, |
||||
iGradAssignType, |
||||
nDim, nWLs, thresh, orient, |
||||
x_min, x_max, y_min, y_max, |
||||
alpha, beta ); |
||||
} |
||||
break; |
||||
case BINBOOST_256: |
||||
{ |
||||
#include "boostdesc_binboost_256.i" |
||||
ini_params( orientQuant, patchSize, |
||||
iGradAssignType, |
||||
nDim, nWLs, thresh, orient, |
||||
x_min, x_max, y_min, y_max, |
||||
alpha, beta ); |
||||
} |
||||
break; |
||||
default: |
||||
CV_Error( Error::StsInternal, "Unknown Descriptor Type." ); |
||||
} |
||||
} |
||||
|
||||
// destructor
|
||||
BoostDesc_Impl::~BoostDesc_Impl() |
||||
{ |
||||
} |
||||
|
||||
Ptr<BoostDesc> BoostDesc::create( int desc, bool use_scale_orientation, float scale_factor ) |
||||
{ |
||||
return makePtr<BoostDesc_Impl>( desc, use_scale_orientation, scale_factor ); |
||||
} |
||||
|
||||
|
||||
} // END NAMESPACE XFEATURES2D
|
||||
} // END NAMESPACE CV
|
Loading…
Reference in new issue