2010-05-11 19:44:00 +02:00
|
|
|
/*M///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
|
|
|
//
|
|
|
|
// By downloading, copying, installing or using the software you agree to this license.
|
|
|
|
// If you do not agree to this license, do not download, install,
|
|
|
|
// copy or use the software.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// Intel License Agreement
|
|
|
|
// For Open Source Computer Vision Library
|
|
|
|
//
|
|
|
|
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
|
|
|
// Third party copyrights are property of their respective owners.
|
|
|
|
//
|
|
|
|
// Redistribution and use in source and binary forms, with or without modification,
|
|
|
|
// are permitted provided that the following conditions are met:
|
|
|
|
//
|
|
|
|
// * Redistribution's of source code must retain the above copyright notice,
|
|
|
|
// this list of conditions and the following disclaimer.
|
|
|
|
//
|
|
|
|
// * Redistribution's 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.
|
|
|
|
//
|
|
|
|
// * The name of Intel Corporation may not 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 Intel Corporation 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.
|
|
|
|
//
|
|
|
|
//M*/
|
|
|
|
|
|
|
|
#include "precomp.hpp"
|
|
|
|
|
|
|
|
using namespace std;
|
2010-08-03 18:28:52 +02:00
|
|
|
|
2010-06-11 20:44:22 +02:00
|
|
|
namespace cv
|
|
|
|
{
|
2010-05-11 19:44:00 +02:00
|
|
|
|
|
|
|
/****************************************************************************************\
|
|
|
|
* DescriptorExtractor *
|
|
|
|
\****************************************************************************************/
|
|
|
|
/*
|
|
|
|
* DescriptorExtractor
|
|
|
|
*/
|
|
|
|
struct RoiPredicate
|
|
|
|
{
|
|
|
|
RoiPredicate(float _minX, float _minY, float _maxX, float _maxY)
|
|
|
|
: minX(_minX), minY(_minY), maxX(_maxX), maxY(_maxY)
|
|
|
|
{}
|
|
|
|
|
|
|
|
bool operator()( const KeyPoint& keyPt) const
|
|
|
|
{
|
|
|
|
Point2f pt = keyPt.pt;
|
|
|
|
return (pt.x < minX) || (pt.x >= maxX) || (pt.y < minY) || (pt.y >= maxY);
|
|
|
|
}
|
|
|
|
|
|
|
|
float minX, minY, maxX, maxY;
|
|
|
|
};
|
|
|
|
|
|
|
|
void DescriptorExtractor::removeBorderKeypoints( vector<KeyPoint>& keypoints,
|
|
|
|
Size imageSize, int borderPixels )
|
|
|
|
{
|
|
|
|
keypoints.erase( remove_if(keypoints.begin(), keypoints.end(),
|
|
|
|
RoiPredicate((float)borderPixels, (float)borderPixels,
|
|
|
|
(float)(imageSize.width - borderPixels),
|
|
|
|
(float)(imageSize.height - borderPixels))),
|
|
|
|
keypoints.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************************\
|
2010-07-26 10:58:46 +02:00
|
|
|
* SiftDescriptorExtractor *
|
2010-05-11 19:44:00 +02:00
|
|
|
\****************************************************************************************/
|
2010-05-19 18:02:30 +02:00
|
|
|
SiftDescriptorExtractor::SiftDescriptorExtractor( double magnification, bool isNormalize, bool recalculateAngles,
|
|
|
|
int nOctaves, int nOctaveLayers, int firstOctave, int angleMode )
|
|
|
|
: sift( magnification, isNormalize, recalculateAngles, nOctaves, nOctaveLayers, firstOctave, angleMode )
|
2010-05-11 19:44:00 +02:00
|
|
|
{}
|
|
|
|
|
|
|
|
void SiftDescriptorExtractor::compute( const Mat& image,
|
|
|
|
vector<KeyPoint>& keypoints,
|
|
|
|
Mat& descriptors) const
|
|
|
|
{
|
|
|
|
bool useProvidedKeypoints = true;
|
2010-09-23 12:53:36 +02:00
|
|
|
Mat grayImage = image;
|
|
|
|
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
|
|
|
|
|
|
|
sift(grayImage, Mat(), keypoints, descriptors, useProvidedKeypoints);
|
2010-05-11 19:44:00 +02:00
|
|
|
}
|
|
|
|
|
2010-06-04 07:30:09 +02:00
|
|
|
void SiftDescriptorExtractor::read (const FileNode &fn)
|
|
|
|
{
|
|
|
|
double magnification = fn["magnification"];
|
|
|
|
bool isNormalize = (int)fn["isNormalize"] != 0;
|
|
|
|
bool recalculateAngles = (int)fn["recalculateAngles"] != 0;
|
|
|
|
int nOctaves = fn["nOctaves"];
|
|
|
|
int nOctaveLayers = fn["nOctaveLayers"];
|
|
|
|
int firstOctave = fn["firstOctave"];
|
|
|
|
int angleMode = fn["angleMode"];
|
|
|
|
|
|
|
|
sift = SIFT( magnification, isNormalize, recalculateAngles, nOctaves, nOctaveLayers, firstOctave, angleMode );
|
|
|
|
}
|
|
|
|
|
|
|
|
void SiftDescriptorExtractor::write (FileStorage &fs) const
|
|
|
|
{
|
|
|
|
// fs << "algorithm" << getAlgorithmName ();
|
|
|
|
|
|
|
|
SIFT::CommonParams commParams = sift.getCommonParams ();
|
|
|
|
SIFT::DescriptorParams descriptorParams = sift.getDescriptorParams ();
|
|
|
|
fs << "magnification" << descriptorParams.magnification;
|
|
|
|
fs << "isNormalize" << descriptorParams.isNormalize;
|
|
|
|
fs << "recalculateAngles" << descriptorParams.recalculateAngles;
|
|
|
|
fs << "nOctaves" << commParams.nOctaves;
|
|
|
|
fs << "nOctaveLayers" << commParams.nOctaveLayers;
|
|
|
|
fs << "firstOctave" << commParams.firstOctave;
|
|
|
|
fs << "angleMode" << commParams.angleMode;
|
|
|
|
}
|
|
|
|
|
2010-05-11 19:44:00 +02:00
|
|
|
/****************************************************************************************\
|
2010-07-26 10:58:46 +02:00
|
|
|
* SurfDescriptorExtractor *
|
2010-05-11 19:44:00 +02:00
|
|
|
\****************************************************************************************/
|
|
|
|
SurfDescriptorExtractor::SurfDescriptorExtractor( int nOctaves,
|
|
|
|
int nOctaveLayers, bool extended )
|
|
|
|
: surf( 0.0, nOctaves, nOctaveLayers, extended )
|
|
|
|
{}
|
|
|
|
|
|
|
|
void SurfDescriptorExtractor::compute( const Mat& image,
|
|
|
|
vector<KeyPoint>& keypoints,
|
|
|
|
Mat& descriptors) const
|
|
|
|
{
|
|
|
|
// Compute descriptors for given keypoints
|
|
|
|
vector<float> _descriptors;
|
|
|
|
Mat mask;
|
|
|
|
bool useProvidedKeypoints = true;
|
2010-09-23 12:53:36 +02:00
|
|
|
Mat grayImage = image;
|
|
|
|
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
|
|
|
|
|
|
|
surf(grayImage, mask, keypoints, _descriptors, useProvidedKeypoints);
|
2010-05-11 19:44:00 +02:00
|
|
|
|
2010-07-16 14:54:53 +02:00
|
|
|
descriptors.create((int)keypoints.size(), (int)surf.descriptorSize(), CV_32FC1);
|
2010-05-11 19:44:00 +02:00
|
|
|
assert( (int)_descriptors.size() == descriptors.rows * descriptors.cols );
|
|
|
|
std::copy(_descriptors.begin(), _descriptors.end(), descriptors.begin<float>());
|
|
|
|
}
|
|
|
|
|
2010-06-04 07:30:09 +02:00
|
|
|
void SurfDescriptorExtractor::read( const FileNode &fn )
|
|
|
|
{
|
|
|
|
int nOctaves = fn["nOctaves"];
|
|
|
|
int nOctaveLayers = fn["nOctaveLayers"];
|
|
|
|
bool extended = (int)fn["extended"] != 0;
|
|
|
|
|
|
|
|
surf = SURF( 0.0, nOctaves, nOctaveLayers, extended );
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfDescriptorExtractor::write( FileStorage &fs ) const
|
|
|
|
{
|
|
|
|
// fs << "algorithm" << getAlgorithmName ();
|
|
|
|
|
|
|
|
fs << "nOctaves" << surf.nOctaves;
|
|
|
|
fs << "nOctaveLayers" << surf.nOctaveLayers;
|
|
|
|
fs << "extended" << surf.extended;
|
|
|
|
}
|
|
|
|
|
2010-09-23 12:53:36 +02:00
|
|
|
/****************************************************************************************\
|
|
|
|
* OpponentColorDescriptorExtractor *
|
|
|
|
\****************************************************************************************/
|
|
|
|
OpponentColorDescriptorExtractor::OpponentColorDescriptorExtractor( const Ptr<DescriptorExtractor>& _dextractor ) :
|
|
|
|
dextractor(_dextractor)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void convertBGRImageToOpponentColorSpace( const Mat& bgrImage, vector<Mat>& opponentChannels )
|
|
|
|
{
|
|
|
|
if( bgrImage.type() != CV_8UC3 )
|
|
|
|
CV_Error( CV_StsBadArg, "input image must be an BGR image of type CV_8UC3" );
|
|
|
|
|
|
|
|
// Split image into RGB to allow conversion to Opponent Color Space.
|
|
|
|
vector<Mat> bgrChannels(3);
|
|
|
|
split( bgrImage, bgrChannels );
|
|
|
|
|
|
|
|
// Prepare opponent color space storage matrices.
|
|
|
|
opponentChannels.resize( 3 );
|
|
|
|
opponentChannels[0] = cv::Mat(bgrImage.size(), CV_8UC1); // R-G RED-GREEN
|
|
|
|
opponentChannels[1] = cv::Mat(bgrImage.size(), CV_8UC1); // R+G-2B YELLOW-BLUE
|
|
|
|
opponentChannels[2] = cv::Mat(bgrImage.size(), CV_8UC1); // R+G+B
|
|
|
|
|
|
|
|
// Calculate the channels of the opponent color space
|
|
|
|
{
|
|
|
|
// (R - G) / sqrt(2)
|
|
|
|
MatConstIterator_<char> rIt = bgrChannels[2].begin<char>();
|
|
|
|
MatConstIterator_<char> gIt = bgrChannels[1].begin<char>();
|
|
|
|
MatIterator_<char> dstIt = opponentChannels[0].begin<char>();
|
|
|
|
float factor = 1.f / sqrt(2.0);
|
|
|
|
for( ; dstIt != opponentChannels[0].end<char>(); ++rIt, ++gIt, ++dstIt )
|
|
|
|
{
|
|
|
|
int value = static_cast<int>( static_cast<float>(static_cast<int>(*gIt)-static_cast<int>(*rIt)) * factor );
|
|
|
|
if( value < 0 ) value = 0;
|
|
|
|
if( value > 255 ) value = 255;
|
|
|
|
(*dstIt) = static_cast<unsigned char>(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
// (R + G - 2B)/sqrt(6)
|
|
|
|
MatConstIterator_<char> rIt = bgrChannels[2].begin<char>();
|
|
|
|
MatConstIterator_<char> gIt = bgrChannels[1].begin<char>();
|
|
|
|
MatConstIterator_<char> bIt = bgrChannels[0].begin<char>();
|
|
|
|
MatIterator_<char> dstIt = opponentChannels[1].begin<char>();
|
|
|
|
float factor = 1.f / sqrt(6.0);
|
|
|
|
for( ; dstIt != opponentChannels[1].end<char>(); ++rIt, ++gIt, ++bIt, ++dstIt )
|
|
|
|
{
|
|
|
|
int value = static_cast<int>( static_cast<float>(static_cast<int>(*rIt) + static_cast<int>(*gIt) - 2*static_cast<int>(*bIt)) *
|
|
|
|
factor );
|
|
|
|
if( value < 0 ) value = 0;
|
|
|
|
if( value > 255 ) value = 255;
|
|
|
|
(*dstIt) = static_cast<unsigned char>(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
// (R + G + B)/sqrt(3)
|
|
|
|
MatConstIterator_<char> rIt = bgrChannels[2].begin<char>();
|
|
|
|
MatConstIterator_<char> gIt = bgrChannels[1].begin<char>();
|
|
|
|
MatConstIterator_<char> bIt = bgrChannels[0].begin<char>();
|
|
|
|
MatIterator_<char> dstIt = opponentChannels[2].begin<char>();
|
|
|
|
float factor = 1.f / sqrt(3.0);
|
|
|
|
for( ; dstIt != opponentChannels[2].end<char>(); ++rIt, ++gIt, ++bIt, ++dstIt )
|
|
|
|
{
|
|
|
|
int value = static_cast<int>( static_cast<float>(static_cast<int>(*rIt) + static_cast<int>(*gIt) + static_cast<int>(*bIt)) *
|
|
|
|
factor );
|
|
|
|
if( value < 0 ) value = 0;
|
|
|
|
if( value > 255 ) value = 255;
|
|
|
|
(*dstIt) = static_cast<unsigned char>(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpponentColorDescriptorExtractor::compute( const Mat& bgrImage, vector<KeyPoint>& keypoints, Mat& descriptors ) const
|
|
|
|
{
|
|
|
|
vector<Mat> opponentChannels;
|
|
|
|
convertBGRImageToOpponentColorSpace( bgrImage, opponentChannels );
|
|
|
|
|
|
|
|
// Compute descriptors three times, once for each Opponent channel
|
|
|
|
// and concatenate into a single color surf descriptor
|
|
|
|
int descriptorSize = dextractor->descriptorSize();
|
|
|
|
descriptors.create( static_cast<int>(keypoints.size()), 3*descriptorSize, CV_32FC1 );
|
|
|
|
for( int i = 0; i < 3/*channel count*/; i++ )
|
|
|
|
{
|
|
|
|
CV_Assert( opponentChannels[i].type() == CV_8UC1 );
|
|
|
|
Mat opponentDescriptors = descriptors.colRange( i*descriptorSize, (i+1)*descriptorSize );
|
|
|
|
dextractor->compute( opponentChannels[i], keypoints, opponentDescriptors );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpponentColorDescriptorExtractor::read( const FileNode& fn )
|
|
|
|
{
|
|
|
|
dextractor->read( fn );
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpponentColorDescriptorExtractor::write( FileStorage& fs ) const
|
|
|
|
{
|
|
|
|
dextractor->write( fs );
|
|
|
|
}
|
|
|
|
|
2010-07-26 10:58:46 +02:00
|
|
|
/****************************************************************************************\
|
2010-09-23 15:44:23 +02:00
|
|
|
* Factory function for descriptor extractor creating *
|
2010-07-26 10:58:46 +02:00
|
|
|
\****************************************************************************************/
|
|
|
|
|
2010-07-12 13:56:11 +02:00
|
|
|
Ptr<DescriptorExtractor> createDescriptorExtractor( const string& descriptorExtractorType )
|
2010-06-11 20:44:22 +02:00
|
|
|
{
|
|
|
|
DescriptorExtractor* de = 0;
|
|
|
|
if( !descriptorExtractorType.compare( "SIFT" ) )
|
|
|
|
{
|
2010-09-23 12:53:36 +02:00
|
|
|
de = new SiftDescriptorExtractor();
|
2010-06-11 20:44:22 +02:00
|
|
|
}
|
|
|
|
else if( !descriptorExtractorType.compare( "SURF" ) )
|
|
|
|
{
|
2010-09-23 12:53:36 +02:00
|
|
|
de = new SurfDescriptorExtractor();
|
2010-06-11 20:44:22 +02:00
|
|
|
}
|
2010-09-23 12:53:36 +02:00
|
|
|
else if( !descriptorExtractorType.compare( "OpponentSIFT" ) )
|
2010-06-11 20:44:22 +02:00
|
|
|
{
|
2010-09-23 12:53:36 +02:00
|
|
|
de = new OpponentColorDescriptorExtractor( new SiftDescriptorExtractor );
|
|
|
|
}
|
|
|
|
else if( !descriptorExtractorType.compare( "OpponentSURF" ) )
|
|
|
|
{
|
|
|
|
de = new OpponentColorDescriptorExtractor( new SurfDescriptorExtractor );
|
2010-06-11 20:44:22 +02:00
|
|
|
}
|
|
|
|
return de;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|