/*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; namespace cv { /****************************************************************************************\ * 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& 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()); } /****************************************************************************************\ * SiftDescriptorExtractor * \****************************************************************************************/ SiftDescriptorExtractor::SiftDescriptorExtractor( double magnification, bool isNormalize, bool recalculateAngles, int nOctaves, int nOctaveLayers, int firstOctave, int angleMode ) : sift( magnification, isNormalize, recalculateAngles, nOctaves, nOctaveLayers, firstOctave, angleMode ) {} void SiftDescriptorExtractor::compute( const Mat& image, vector& keypoints, Mat& descriptors) const { bool useProvidedKeypoints = true; Mat grayImage = image; if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY ); sift(grayImage, Mat(), keypoints, descriptors, useProvidedKeypoints); } 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; } /****************************************************************************************\ * SurfDescriptorExtractor * \****************************************************************************************/ SurfDescriptorExtractor::SurfDescriptorExtractor( int nOctaves, int nOctaveLayers, bool extended ) : surf( 0.0, nOctaves, nOctaveLayers, extended ) {} void SurfDescriptorExtractor::compute( const Mat& image, vector& keypoints, Mat& descriptors) const { // Compute descriptors for given keypoints vector _descriptors; Mat mask; bool useProvidedKeypoints = true; Mat grayImage = image; if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY ); surf(grayImage, mask, keypoints, _descriptors, useProvidedKeypoints); descriptors.create((int)keypoints.size(), (int)surf.descriptorSize(), CV_32FC1); assert( (int)_descriptors.size() == descriptors.rows * descriptors.cols ); std::copy(_descriptors.begin(), _descriptors.end(), descriptors.begin()); } 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; } /****************************************************************************************\ * OpponentColorDescriptorExtractor * \****************************************************************************************/ OpponentColorDescriptorExtractor::OpponentColorDescriptorExtractor( const Ptr& _dextractor ) : dextractor(_dextractor) {} void convertBGRImageToOpponentColorSpace( const Mat& bgrImage, vector& 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 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_ rIt = bgrChannels[2].begin(); MatConstIterator_ gIt = bgrChannels[1].begin(); MatIterator_ dstIt = opponentChannels[0].begin(); float factor = 1.f / sqrt(2.0); for( ; dstIt != opponentChannels[0].end(); ++rIt, ++gIt, ++dstIt ) { int value = static_cast( static_cast(static_cast(*gIt)-static_cast(*rIt)) * factor ); if( value < 0 ) value = 0; if( value > 255 ) value = 255; (*dstIt) = static_cast(value); } } { // (R + G - 2B)/sqrt(6) MatConstIterator_ rIt = bgrChannels[2].begin(); MatConstIterator_ gIt = bgrChannels[1].begin(); MatConstIterator_ bIt = bgrChannels[0].begin(); MatIterator_ dstIt = opponentChannels[1].begin(); float factor = 1.f / sqrt(6.0); for( ; dstIt != opponentChannels[1].end(); ++rIt, ++gIt, ++bIt, ++dstIt ) { int value = static_cast( static_cast(static_cast(*rIt) + static_cast(*gIt) - 2*static_cast(*bIt)) * factor ); if( value < 0 ) value = 0; if( value > 255 ) value = 255; (*dstIt) = static_cast(value); } } { // (R + G + B)/sqrt(3) MatConstIterator_ rIt = bgrChannels[2].begin(); MatConstIterator_ gIt = bgrChannels[1].begin(); MatConstIterator_ bIt = bgrChannels[0].begin(); MatIterator_ dstIt = opponentChannels[2].begin(); float factor = 1.f / sqrt(3.0); for( ; dstIt != opponentChannels[2].end(); ++rIt, ++gIt, ++bIt, ++dstIt ) { int value = static_cast( static_cast(static_cast(*rIt) + static_cast(*gIt) + static_cast(*bIt)) * factor ); if( value < 0 ) value = 0; if( value > 255 ) value = 255; (*dstIt) = static_cast(value); } } } void OpponentColorDescriptorExtractor::compute( const Mat& bgrImage, vector& keypoints, Mat& descriptors ) const { vector 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(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 ); } /****************************************************************************************\ * Factory function for descriptor extractor creating * \****************************************************************************************/ Ptr createDescriptorExtractor( const string& descriptorExtractorType ) { DescriptorExtractor* de = 0; if( !descriptorExtractorType.compare( "SIFT" ) ) { de = new SiftDescriptorExtractor(); } else if( !descriptorExtractorType.compare( "SURF" ) ) { de = new SurfDescriptorExtractor(); } else if( !descriptorExtractorType.compare( "OpponentSIFT" ) ) { de = new OpponentColorDescriptorExtractor( new SiftDescriptorExtractor ); } else if( !descriptorExtractorType.compare( "OpponentSURF" ) ) { de = new OpponentColorDescriptorExtractor( new SurfDescriptorExtractor ); } return de; } }