Commit 5e38cf80 authored by Vladislav Vinogradov's avatar Vladislav Vinogradov

added FAST_GPU and ORB_GPU classes

parent e46e13a7
......@@ -1522,6 +1522,159 @@ public:
GpuMat maxPosBuffer;
};
////////////////////////////////// FAST //////////////////////////////////////////
class CV_EXPORTS FAST_GPU
{
public:
enum
{
LOCATION_ROW = 0,
RESPONSE_ROW,
ROWS_COUNT
};
// all features have same size
static const int FEATURE_SIZE = 7;
explicit FAST_GPU(int threshold, bool nonmaxSupression = true, double keypointsRatio = 0.05);
//! finds the keypoints using FAST detector
//! supports only CV_8UC1 images
void operator ()(const GpuMat& image, const GpuMat& mask, GpuMat& keypoints);
void operator ()(const GpuMat& image, const GpuMat& mask, std::vector<KeyPoint>& keypoints);
//! download keypoints from device to host memory
void downloadKeypoints(const GpuMat& d_keypoints, std::vector<KeyPoint>& keypoints);
//! convert keypoints to KeyPoint vector
void convertKeypoints(const Mat& h_keypoints, std::vector<KeyPoint>& keypoints);
//! release temporary buffer's memory
void release();
bool nonmaxSupression;
int threshold;
//! max keypoints = keypointsRatio * img.size().area()
double keypointsRatio;
//! find keypoints and compute it's response if nonmaxSupression is true
//! return count of detected keypoints
int calcKeyPointsLocation(const GpuMat& image, const GpuMat& mask);
//! get final array of keypoints
//! performs nonmax supression if needed
//! return final count of keypoints
int getKeyPoints(GpuMat& keypoints);
private:
GpuMat kpLoc_;
int count_;
GpuMat score_;
GpuMat d_keypoints_;
};
////////////////////////////////// ORB //////////////////////////////////////////
class CV_EXPORTS ORB_GPU
{
public:
enum
{
X_ROW = 0,
Y_ROW,
RESPONSE_ROW,
ANGLE_ROW,
OCTAVE_ROW,
SIZE_ROW,
ROWS_COUNT
};
enum
{
DEFAULT_FAST_THRESHOLD = 20
};
//! Constructor
//! n_features - the number of desired features
//! detector_params - parameters to use
explicit ORB_GPU(size_t n_features = 500, const ORB::CommonParams& detector_params = ORB::CommonParams());
//! Compute the ORB features on an image
//! image - the image to compute the features (supports only CV_8UC1 images)
//! mask - the mask to apply
//! keypoints - the resulting keypoints
void operator()(const GpuMat& image, const GpuMat& mask, std::vector<KeyPoint>& keypoints);
void operator()(const GpuMat& image, const GpuMat& mask, GpuMat& keypoints);
//! Compute the ORB features and descriptors on an image
//! image - the image to compute the features (supports only CV_8UC1 images)
//! mask - the mask to apply
//! keypoints - the resulting keypoints
//! descriptors - descriptors array
void operator()(const GpuMat& image, const GpuMat& mask, std::vector<KeyPoint>& keypoints, GpuMat& descriptors);
void operator()(const GpuMat& image, const GpuMat& mask, GpuMat& keypoints, GpuMat& descriptors);
//! download keypoints from device to host memory
void downloadKeyPoints(GpuMat& d_keypoints, std::vector<KeyPoint>& keypoints);
//! convert keypoints to KeyPoint vector
void convertKeyPoints(Mat& d_keypoints, std::vector<KeyPoint>& keypoints);
//! returns the descriptor size in bytes
inline int descriptorSize() const { return kBytes; }
void setParams(size_t n_features, const ORB::CommonParams& detector_params);
inline void setFastParams(int threshold, bool nonmaxSupression = true)
{
fastDetector_.threshold = threshold;
fastDetector_.nonmaxSupression = nonmaxSupression;
}
//! release temporary buffer's memory
void release();
//! if true, image will be blurred before descriptors calculation
bool blurForDescriptor;
private:
enum { kBytes = 32 };
void buildScalePyramids(const GpuMat& image, const GpuMat& mask);
void computeKeyPointsPyramid();
void computeDescriptors(GpuMat& descriptors);
void mergeKeyPoints(GpuMat& keypoints);
ORB::CommonParams params_;
// The number of desired features per scale
std::vector<size_t> n_features_per_level_;
// Points to compute BRIEF descriptors from
GpuMat pattern_;
std::vector<GpuMat> imagePyr_;
std::vector<GpuMat> maskPyr_;
GpuMat buf_;
std::vector<GpuMat> keyPointsPyr_;
std::vector<int> keyPointsCount_;
FAST_GPU fastDetector_;
Ptr<FilterEngine_GPU> blurFilter;
GpuMat d_keypoints_;
};
////////////////////////////////// Optical Flow //////////////////////////////////////////
class CV_EXPORTS BroxOpticalFlow
......
......@@ -122,11 +122,50 @@ PERF_TEST_P(DevInfo, SURF, testing::ValuesIn(devices()))
{
surf(img, GpuMat(), keypoints, descriptors);
}
}
PERF_TEST_P(DevInfo, FAST, testing::ValuesIn(devices()))
{
DeviceInfo devInfo = GetParam();
setDevice(devInfo.deviceID());
Mat img_host = readImage("gpu/perf/aloe.jpg", CV_LOAD_IMAGE_GRAYSCALE);
ASSERT_FALSE(img_host.empty());
Mat keypoints_host(keypoints);
Mat descriptors_host(descriptors);
SANITY_CHECK(keypoints_host);
SANITY_CHECK(descriptors_host);
GpuMat img(img_host);
GpuMat keypoints;
FAST_GPU fastGPU(20);
declare.time(2.0);
TEST_CYCLE(100)
{
fastGPU(img, GpuMat(), keypoints);
}
}
PERF_TEST_P(DevInfo, ORB, testing::ValuesIn(devices()))
{
DeviceInfo devInfo = GetParam();
setDevice(devInfo.deviceID());
Mat img_host = readImage("gpu/perf/aloe.jpg", CV_LOAD_IMAGE_GRAYSCALE);
ASSERT_FALSE(img_host.empty());
GpuMat img(img_host);
GpuMat keypoints, descriptors;
ORB_GPU orbGPU(4000);
declare.time(2.0);
TEST_CYCLE(100)
{
orbGPU(img, GpuMat(), keypoints, descriptors);
}
}
This diff is collapsed.
This diff is collapsed.
/*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.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., 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 GpuMaterials provided with the distribution.
//
// * The name of the copyright holders 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 bpied warranties, including, but not limited to, the bpied
// 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 cv;
using namespace cv::gpu;
using namespace std;
#if !defined (HAVE_CUDA)
cv::gpu::FAST_GPU::FAST_GPU(int, bool, double) { throw_nogpu(); }
void cv::gpu::FAST_GPU::operator ()(const GpuMat&, const GpuMat&, GpuMat&) { throw_nogpu(); }
void cv::gpu::FAST_GPU::operator ()(const GpuMat&, const GpuMat&, std::vector<KeyPoint>&) { throw_nogpu(); }
void cv::gpu::FAST_GPU::downloadKeypoints(const GpuMat&, std::vector<KeyPoint>&) { throw_nogpu(); }
void cv::gpu::FAST_GPU::convertKeypoints(const Mat&, std::vector<KeyPoint>&) { throw_nogpu(); }
void cv::gpu::FAST_GPU::release() { throw_nogpu(); }
int cv::gpu::FAST_GPU::calcKeyPointsLocation(const GpuMat&, const GpuMat&) { throw_nogpu(); return 0; }
int cv::gpu::FAST_GPU::getKeyPoints(GpuMat&) { throw_nogpu(); return 0; }
#else /* !defined (HAVE_CUDA) */
cv::gpu::FAST_GPU::FAST_GPU(int _threshold, bool _nonmaxSupression, double _keypointsRatio) :
nonmaxSupression(_nonmaxSupression), threshold(_threshold), keypointsRatio(_keypointsRatio), count_(0)
{
}
void cv::gpu::FAST_GPU::operator ()(const GpuMat& image, const GpuMat& mask, std::vector<KeyPoint>& keypoints)
{
if (image.empty())
return;
(*this)(image, mask, d_keypoints_);
downloadKeypoints(d_keypoints_, keypoints);
}
void cv::gpu::FAST_GPU::downloadKeypoints(const GpuMat& d_keypoints, std::vector<KeyPoint>& keypoints)
{
if (d_keypoints.empty())
return;
Mat h_keypoints(d_keypoints);
convertKeypoints(h_keypoints, keypoints);
}
void cv::gpu::FAST_GPU::convertKeypoints(const Mat& h_keypoints, std::vector<KeyPoint>& keypoints)
{
if (h_keypoints.empty())
return;
CV_Assert(h_keypoints.rows == ROWS_COUNT && h_keypoints.elemSize() == 4);
int npoints = h_keypoints.cols;
keypoints.resize(npoints);
const short2* loc_row = h_keypoints.ptr<short2>(LOCATION_ROW);
const float* response_row = h_keypoints.ptr<float>(RESPONSE_ROW);
for (int i = 0; i < npoints; ++i)
{
KeyPoint kp(loc_row[i].x, loc_row[i].y, static_cast<float>(FEATURE_SIZE), -1, response_row[i]);
keypoints[i] = kp;
}
}
void cv::gpu::FAST_GPU::operator ()(const GpuMat& img, const GpuMat& mask, GpuMat& keypoints)
{
calcKeyPointsLocation(img, mask);
keypoints.cols = getKeyPoints(keypoints);
}
namespace cv { namespace gpu { namespace device
{
namespace fast
{
int calcKeypoints_gpu(DevMem2Db img, DevMem2Db mask, short2* kpLoc, int maxKeypoints, DevMem2Di score, int threshold);
int nonmaxSupression_gpu(const short2* kpLoc, int count, DevMem2Di score, short2* loc, float* response);
}
}}}
int cv::gpu::FAST_GPU::calcKeyPointsLocation(const GpuMat& img, const GpuMat& mask)
{
using namespace cv::gpu::device::fast;
CV_Assert(img.type() == CV_8UC1);
CV_Assert(mask.empty() || (mask.type() == CV_8UC1 && mask.size() == img.size()));
int maxKeypoints = static_cast<int>(keypointsRatio * img.size().area());
ensureSizeIsEnough(1, maxKeypoints, CV_16SC2, kpLoc_);
if (nonmaxSupression)
{
ensureSizeIsEnough(img.size(), CV_32SC1, score_);
score_.setTo(Scalar::all(0));
}
count_ = calcKeypoints_gpu(img, mask, kpLoc_.ptr<short2>(), maxKeypoints, nonmaxSupression ? score_ : DevMem2Di(), threshold);
count_ = std::min(count_, maxKeypoints);
return count_;
}
int cv::gpu::FAST_GPU::getKeyPoints(GpuMat& keypoints)
{
using namespace cv::gpu::device::fast;
if (count_ == 0)
return 0;
ensureSizeIsEnough(ROWS_COUNT, count_, CV_32FC1, keypoints);
if (nonmaxSupression)
return nonmaxSupression_gpu(kpLoc_.ptr<short2>(), count_, score_, keypoints.ptr<short2>(LOCATION_ROW), keypoints.ptr<float>(RESPONSE_ROW));
GpuMat locRow(1, count_, kpLoc_.type(), keypoints.ptr(0));
kpLoc_.colRange(0, count_).copyTo(locRow);
keypoints.row(1).setTo(Scalar::all(0));
return count_;
}
void cv::gpu::FAST_GPU::release()
{
kpLoc_.release();
score_.release();
d_keypoints_.release();
}
#endif /* !defined (HAVE_CUDA) */
This diff is collapsed.
......@@ -70,22 +70,6 @@ struct SURF : testing::TestWithParam<cv::gpu::DeviceInfo>
cv::SURF fdetector_gold; fdetector_gold.extended = false;
fdetector_gold(image, mask, keypoints_gold, descriptors_gold);
}
bool isSimilarKeypoints(const cv::KeyPoint& p1, const cv::KeyPoint& p2)
{
const float maxPtDif = 1.f;
const float maxSizeDif = 1.f;
const float maxAngleDif = 2.f;
const float maxResponseDif = 0.1f;
float dist = (float)cv::norm(p1.pt - p2.pt);
return (dist < maxPtDif &&
fabs(p1.size - p2.size) < maxSizeDif &&
abs(p1.angle - p2.angle) < maxAngleDif &&
abs(p1.response - p2.response) < maxResponseDif &&
p1.octave == p2.octave &&
p1.class_id == p2.class_id );
}
};
TEST_P(SURF, EmptyDataTest)
......@@ -652,4 +636,169 @@ INSTANTIATE_TEST_CASE_P(Features2D, BruteForceMatcher, testing::Combine(
testing::Values(cv::gpu::BruteForceMatcher_GPU_base::L1Dist, cv::gpu::BruteForceMatcher_GPU_base::L2Dist),
testing::Values(57, 64, 83, 128, 179, 256, 304)));
/////////////////////////////////////////////////////////////////////////////////////////////////
// FAST
struct FAST : testing::TestWithParam<cv::gpu::DeviceInfo>
{
cv::gpu::DeviceInfo devInfo;
cv::Mat image;
int threshold;
std::vector<cv::KeyPoint> keypoints_gold;
virtual void SetUp()
{
devInfo = GetParam();
cv::gpu::setDevice(devInfo.deviceID());
image = readImage("features2d/aloe.png", CV_LOAD_IMAGE_GRAYSCALE);
ASSERT_FALSE(image.empty());
cv::RNG& rng = cvtest::TS::ptr()->get_rng();
threshold = rng.uniform(15, 80);
cv::FAST(image, keypoints_gold, threshold);
}
};
struct HashEq
{
size_t hash;
inline HashEq(size_t hash_) : hash(hash_) {}
inline bool operator ()(const cv::KeyPoint& kp) const
{
return kp.hash() == hash;
}
};
struct KeyPointCompare
{
inline bool operator ()(const cv::KeyPoint& kp1, const cv::KeyPoint& kp2) const
{
return kp1.pt.y < kp2.pt.y || (kp1.pt.y == kp2.pt.y && kp1.pt.x < kp2.pt.x);
}
};
TEST_P(FAST, Accuracy)
{
std::vector<cv::KeyPoint> keypoints;
ASSERT_NO_THROW(
cv::gpu::FAST_GPU fastGPU(threshold);
fastGPU(cv::gpu::GpuMat(image), cv::gpu::GpuMat(), keypoints);
);
ASSERT_EQ(keypoints.size(), keypoints_gold.size());
std::sort(keypoints.begin(), keypoints.end(), KeyPointCompare());
for (size_t i = 0; i < keypoints_gold.size(); ++i)
{
const cv::KeyPoint& kp1 = keypoints[i];
const cv::KeyPoint& kp2 = keypoints_gold[i];
size_t h1 = kp1.hash();
size_t h2 = kp2.hash();
ASSERT_EQ(h1, h2);
}
}
INSTANTIATE_TEST_CASE_P(Features2D, FAST, testing::ValuesIn(devices()));
/////////////////////////////////////////////////////////////////////////////////////////////////
// ORB
struct ORB : testing::TestWithParam<cv::gpu::DeviceInfo>
{
cv::gpu::DeviceInfo devInfo;
cv::Mat image;
cv::Mat mask;
int npoints;
std::vector<cv::KeyPoint> keypoints_gold;
cv::Mat descriptors_gold;
virtual void SetUp()
{
devInfo = GetParam();
cv::gpu::setDevice(devInfo.deviceID());
image = readImage("features2d/aloe.png", CV_LOAD_IMAGE_GRAYSCALE);
ASSERT_FALSE(image.empty());
mask = cv::Mat(image.size(), CV_8UC1, cv::Scalar::all(1));
mask(cv::Range(0, image.rows / 2), cv::Range(0, image.cols / 2)).setTo(cv::Scalar::all(0));
npoints = 4000;
cv::ORB orbCPU(npoints);
orbCPU(image, mask, keypoints_gold, descriptors_gold);
}
};
int getValidMatchesCount(const std::vector<cv::KeyPoint>& keypoints1, const std::vector<cv::KeyPoint>& keypoints2, const std::vector<cv::DMatch>& matches)
{
int count = 0;
for (size_t i = 0; i < matches.size(); ++i)
{
const cv::DMatch& m = matches[i];
const cv::KeyPoint& kp1 = keypoints1[m.queryIdx];
const cv::KeyPoint& kp2 = keypoints2[m.trainIdx];
bool isEq =
fabs(kp1.pt.x - kp2.pt.x) <= 1 &&
fabs(kp1.pt.y - kp2.pt.y) <= 1 &&
//fabs(kp1.size - kp2.size) < 1 &&
//fabs(kp1.angle - kp2.angle) <= 1 &&
//fabs(kp1.response - kp2.response) < 1 &&
//kp1.octave == kp2.octave &&
//kp1.class_id == kp2.class_id
true;
if (isEq)
++count;
}
return count;
}
TEST_P(ORB, Accuracy)
{
std::vector<cv::KeyPoint> keypoints;
cv::Mat descriptors;
ASSERT_NO_THROW(
cv::gpu::ORB_GPU orbGPU(npoints);
cv::gpu::GpuMat d_descriptors;
orbGPU(cv::gpu::GpuMat(image), cv::gpu::GpuMat(mask), keypoints, d_descriptors);
d_descriptors.download(descriptors);
);
cv::BruteForceMatcher<cv::Hamming> matcher;
std::vector<cv::DMatch> matches;
matcher.match(descriptors_gold, descriptors, matches);
int count = getValidMatchesCount(keypoints_gold, keypoints, matches);
double ratio = 100.0 * count / matches.size();
ASSERT_GE(ratio, 70.0);
}
INSTANTIATE_TEST_CASE_P(Features2D, ORB, testing::ValuesIn(devices()));
#endif // HAVE_CUDA
......@@ -362,30 +362,81 @@ TEST(meanShift)
TEST(SURF)
{
Mat src1 = imread(abspath("aloeL.jpg"), CV_LOAD_IMAGE_GRAYSCALE);
Mat src2 = imread(abspath("aloeR.jpg"), CV_LOAD_IMAGE_GRAYSCALE);
if (src1.empty()) throw runtime_error("can't open aloeL.jpg");
if (src2.empty()) throw runtime_error("can't open aloeR.jpg");
gpu::GpuMat d_src1(src1);
gpu::GpuMat d_src2(src2);
Mat src = imread(abspath("aloeL.jpg"), CV_LOAD_IMAGE_GRAYSCALE);
if (src.empty()) throw runtime_error("can't open aloeL.jpg");
SURF surf;
vector<KeyPoint> keypoints1, keypoints2;
vector<float> descriptors1, descriptors2;
vector<KeyPoint> keypoints;
vector<float> descriptors;
surf(src, Mat(), keypoints, descriptors);
CPU_ON;
surf(src1, Mat(), keypoints1, descriptors1);
surf(src2, Mat(), keypoints2, descriptors2);
surf(src, Mat(), keypoints, descriptors);
CPU_OFF;
gpu::SURF_GPU d_surf;
gpu::GpuMat d_keypoints1, d_keypoints2;
gpu::GpuMat d_descriptors1, d_descriptors2;
gpu::GpuMat d_src(src);
gpu::GpuMat d_keypoints;
gpu::GpuMat d_descriptors;
d_surf(d_src, gpu::GpuMat(), d_keypoints, d_descriptors);
GPU_ON;
d_surf(d_src, gpu::GpuMat(), d_keypoints, d_descriptors);
GPU_OFF;
}
TEST(FAST)
{
Mat src = imread(abspath("aloeL.jpg"), CV_LOAD_IMAGE_GRAYSCALE);
if (src.empty()) throw runtime_error("can't open aloeL.jpg");
vector<KeyPoint> keypoints;
FAST(src, keypoints, 20);
CPU_ON;
FAST(src, keypoints, 20);
CPU_OFF;
gpu::FAST_GPU d_FAST(20);
gpu::GpuMat d_src(src);
gpu::GpuMat d_keypoints;
d_FAST(d_src, gpu::GpuMat(), d_keypoints);
GPU_ON;
d_FAST(d_src, gpu::GpuMat(), d_keypoints);
GPU_OFF;
}
TEST(ORB)
{
Mat src = imread(abspath("aloeL.jpg"), CV_LOAD_IMAGE_GRAYSCALE);
if (src.empty()) throw runtime_error("can't open aloeL.jpg");
ORB orb(4000);
vector<KeyPoint> keypoints;
Mat descriptors;
orb(src, Mat(), keypoints, descriptors);
CPU_ON;
orb(src, Mat(), keypoints, descriptors);
CPU_OFF;
gpu::ORB_GPU d_orb;
gpu::GpuMat d_src(src);
gpu::GpuMat d_keypoints;
gpu::GpuMat d_descriptors;
d_orb(d_src, gpu::GpuMat(), d_keypoints, d_descriptors);
GPU_ON;
d_surf(d_src1, gpu::GpuMat(), d_keypoints1, d_descriptors1);
d_surf(d_src2, gpu::GpuMat(), d_keypoints2, d_descriptors2);
d_orb(d_src, gpu::GpuMat(), d_keypoints, d_descriptors);
GPU_OFF;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment