opencv-ffi 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -0
- data/Gemfile +15 -0
- data/README.md +126 -0
- data/Rakefile +52 -0
- data/docs/DocsIndex.md +1 -0
- data/docs/examples/load_image.rb +25 -0
- data/ext/Rakefile +13 -0
- data/ext/aishack-sift/.gitignore +4 -0
- data/ext/aishack-sift/Descriptor.h +34 -0
- data/ext/aishack-sift/KeyPoint.h +38 -0
- data/ext/aishack-sift/README +20 -0
- data/ext/aishack-sift/SIFT.cpp +1036 -0
- data/ext/aishack-sift/SIFT.h +84 -0
- data/ext/aishack-sift/example/.gitignore +2 -0
- data/ext/aishack-sift/example/Makefile +24 -0
- data/ext/aishack-sift/example/MySIFT.cpp +29 -0
- data/ext/aishack-sift/mkrf_conf.rb +13 -0
- data/ext/aishack-sift/siftlib.cpp +85 -0
- data/ext/eigen/.gitignore +4 -0
- data/ext/eigen/eigen_polynomial.cpp +41 -0
- data/ext/eigen/eigen_svd.cpp +100 -0
- data/ext/eigen/mkrf_conf.rb +14 -0
- data/ext/mkrf-monkey.rb +85 -0
- data/ext/mkrf-rakehelper-monkey.rb +52 -0
- data/ext/mkrf_conf.rb +3 -0
- data/ext/opencv-ffi/.gitignore +4 -0
- data/ext/opencv-ffi/matcher_helper.cpp +56 -0
- data/ext/opencv-ffi/mkrf_conf.rb +12 -0
- data/ext/opencv-ffi/vector_math.cpp +39 -0
- data/ext/opensurf/.gitignore +4 -0
- data/ext/opensurf/README +38 -0
- data/ext/opensurf/fasthessian.cpp +376 -0
- data/ext/opensurf/fasthessian.h +108 -0
- data/ext/opensurf/integral.cpp +58 -0
- data/ext/opensurf/integral.h +55 -0
- data/ext/opensurf/ipoint.cpp +108 -0
- data/ext/opensurf/ipoint.h +76 -0
- data/ext/opensurf/kmeans.h +172 -0
- data/ext/opensurf/mkrf_conf.rb +10 -0
- data/ext/opensurf/responselayer.h +92 -0
- data/ext/opensurf/surf.cpp +317 -0
- data/ext/opensurf/surf.h +66 -0
- data/ext/opensurf/surflib.cpp +98 -0
- data/ext/opensurf/surflib.h +96 -0
- data/ext/opensurf/utils.cpp +357 -0
- data/ext/opensurf/utils.h +63 -0
- data/lib/.gitignore +1 -0
- data/lib/opencv-ffi-ext/eigen.rb +84 -0
- data/lib/opencv-ffi-ext/features2d.rb +4 -0
- data/lib/opencv-ffi-ext/matcher_helper.rb +24 -0
- data/lib/opencv-ffi-ext/opensurf.rb +217 -0
- data/lib/opencv-ffi-ext/sift.rb +118 -0
- data/lib/opencv-ffi-ext/vector_math.rb +115 -0
- data/lib/opencv-ffi-wrappers.rb +7 -0
- data/lib/opencv-ffi-wrappers/core.rb +24 -0
- data/lib/opencv-ffi-wrappers/core/iplimage.rb +50 -0
- data/lib/opencv-ffi-wrappers/core/mat.rb +268 -0
- data/lib/opencv-ffi-wrappers/core/misc_draw.rb +44 -0
- data/lib/opencv-ffi-wrappers/core/point.rb +286 -0
- data/lib/opencv-ffi-wrappers/core/rect.rb +40 -0
- data/lib/opencv-ffi-wrappers/core/scalar.rb +104 -0
- data/lib/opencv-ffi-wrappers/core/size.rb +88 -0
- data/lib/opencv-ffi-wrappers/enumerable.rb +10 -0
- data/lib/opencv-ffi-wrappers/features2d.rb +17 -0
- data/lib/opencv-ffi-wrappers/features2d/image_patch.rb +322 -0
- data/lib/opencv-ffi-wrappers/features2d/star.rb +111 -0
- data/lib/opencv-ffi-wrappers/features2d/surf.rb +115 -0
- data/lib/opencv-ffi-wrappers/highgui.rb +10 -0
- data/lib/opencv-ffi-wrappers/imgproc.rb +4 -0
- data/lib/opencv-ffi-wrappers/imgproc/features.rb +35 -0
- data/lib/opencv-ffi-wrappers/imgproc/geometric.rb +39 -0
- data/lib/opencv-ffi-wrappers/matcher.rb +297 -0
- data/lib/opencv-ffi-wrappers/matrix.rb +37 -0
- data/lib/opencv-ffi-wrappers/misc.rb +41 -0
- data/lib/opencv-ffi-wrappers/misc/params.rb +34 -0
- data/lib/opencv-ffi-wrappers/sequence.rb +37 -0
- data/lib/opencv-ffi-wrappers/vectors.rb +38 -0
- data/lib/opencv-ffi.rb +12 -0
- data/lib/opencv-ffi/calib3d.rb +26 -0
- data/lib/opencv-ffi/core.rb +15 -0
- data/lib/opencv-ffi/core/draw.rb +68 -0
- data/lib/opencv-ffi/core/dynamic.rb +13 -0
- data/lib/opencv-ffi/core/library.rb +5 -0
- data/lib/opencv-ffi/core/operations.rb +122 -0
- data/lib/opencv-ffi/core/point.rb +22 -0
- data/lib/opencv-ffi/core/types.rb +172 -0
- data/lib/opencv-ffi/cvffi.rb +8 -0
- data/lib/opencv-ffi/features2d.rb +7 -0
- data/lib/opencv-ffi/features2d/library.rb +6 -0
- data/lib/opencv-ffi/features2d/star.rb +30 -0
- data/lib/opencv-ffi/features2d/surf.rb +38 -0
- data/lib/opencv-ffi/highgui.rb +31 -0
- data/lib/opencv-ffi/imgproc.rb +9 -0
- data/lib/opencv-ffi/imgproc/features.rb +37 -0
- data/lib/opencv-ffi/imgproc/geometric.rb +42 -0
- data/lib/opencv-ffi/imgproc/library.rb +6 -0
- data/lib/opencv-ffi/imgproc/misc.rb +39 -0
- data/lib/opencv-ffi/version.rb +3 -0
- data/opencv-ffi.gemspec +26 -0
- data/test/core/test_draw.rb +46 -0
- data/test/core/test_operations.rb +135 -0
- data/test/core/test_size.rb +14 -0
- data/test/core/test_text.rb +52 -0
- data/test/ext/test_eigen.rb +105 -0
- data/test/ext/test_opensurf.rb +35 -0
- data/test/ext/test_sift.rb +26 -0
- data/test/ext/test_vector_math.rb +85 -0
- data/test/features2d/test_surf.rb +63 -0
- data/test/imgproc/test_goodfeatures.rb +18 -0
- data/test/setup.rb +65 -0
- data/test/test_calib3d.rb +38 -0
- data/test/test_core.rb +26 -0
- data/test/test_ext.rb +8 -0
- data/test/test_features2d.rb +9 -0
- data/test/test_files/images/IMG_7088.JPG +0 -0
- data/test/test_files/images/IMG_7088_small.JPG +0 -0
- data/test/test_files/images/IMG_7089.JPG +0 -0
- data/test/test_highgui.rb +26 -0
- data/test/test_imgproc.rb +35 -0
- data/test/test_wrappers.rb +8 -0
- data/test/wrappers/core/test_draw.rb +41 -0
- data/test/wrappers/core/test_mat.rb +40 -0
- data/test/wrappers/core/test_operations.rb +35 -0
- data/test/wrappers/core/test_types.rb +235 -0
- data/test/wrappers/features2d/test_image_patch.rb +108 -0
- data/test/wrappers/test_imgproc.rb +87 -0
- data/test/wrappers/test_matcher.rb +96 -0
- data/test/wrappers/test_star.rb +28 -0
- data/test/wrappers/test_surf.rb +36 -0
- metadata +234 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
|
2
|
+
require 'mkrf/rakehelper'
|
3
|
+
|
4
|
+
alias :old_setup_extension :setup_extension
|
5
|
+
|
6
|
+
module Mkrf
|
7
|
+
@all_libs = []
|
8
|
+
|
9
|
+
def self.all_libs
|
10
|
+
@all_libs
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.all_libs=(a)
|
14
|
+
@all_libs = a
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def rake( rakedir, args = nil )
|
19
|
+
Dir.chdir( rakedir ) do
|
20
|
+
if args
|
21
|
+
sh "rake #{args}"
|
22
|
+
else
|
23
|
+
sh 'rake'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def setup_extension(dir, extension)
|
29
|
+
|
30
|
+
old_setup_extension( dir, extension )
|
31
|
+
|
32
|
+
ext_dir = "ext/#{dir}"
|
33
|
+
ext_so = "#{ext_dir}/#{extension}.#{Config::CONFIG['DLEXT']}"
|
34
|
+
|
35
|
+
task ext_so => FileList["#{ext_dir}/**/*.c*", "#{ext_dir}/mkrf_conf.rb"]
|
36
|
+
|
37
|
+
Mkrf::all_libs << extension.to_sym
|
38
|
+
|
39
|
+
namespace extension.to_sym do
|
40
|
+
|
41
|
+
desc "Run \"rake clean\" in #{ext_dir}"
|
42
|
+
task :clean do
|
43
|
+
rake ext_dir, 'clean'
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "Run \"rake clobber\" in #{ext_dir}"
|
47
|
+
task :clobber do
|
48
|
+
rake extd_dir, 'clobber'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
data/ext/mkrf_conf.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
#include <opencv2/core/types_c.h>
|
3
|
+
|
4
|
+
#include <stdio.h>
|
5
|
+
|
6
|
+
typedef struct {
|
7
|
+
CvPoint2D32f train, query;
|
8
|
+
double distance;
|
9
|
+
} Match_t;
|
10
|
+
|
11
|
+
typedef struct {
|
12
|
+
int length;
|
13
|
+
Match_t *d;
|
14
|
+
double *error;
|
15
|
+
} MatchSet_t;
|
16
|
+
|
17
|
+
extern "C"
|
18
|
+
double computeReprojError( const Match_t *match, const CvMat *model )
|
19
|
+
{
|
20
|
+
const double* F = model->data.db;
|
21
|
+
const CvPoint2D32f *m1 = &(match->train);
|
22
|
+
const CvPoint2D32f *m2 = &(match->query);
|
23
|
+
|
24
|
+
double a, b, c, d1, d2, s1, s2;
|
25
|
+
|
26
|
+
a = F[0]*m1->x + F[1]*m1->y + F[2];
|
27
|
+
b = F[3]*m1->x + F[4]*m1->y + F[5];
|
28
|
+
c = F[6]*m1->x + F[7]*m1->y + F[8];
|
29
|
+
|
30
|
+
s2 = 1./(a*a + b*b);
|
31
|
+
d2 = m2->x*a + m2->y*b + c;
|
32
|
+
|
33
|
+
a = F[0]*m2->x + F[3]*m2->y + F[6];
|
34
|
+
b = F[1]*m2->x + F[4]*m2->y + F[7];
|
35
|
+
c = F[2]*m2->x + F[5]*m2->y + F[8];
|
36
|
+
|
37
|
+
s1 = 1./(a*a + b*b);
|
38
|
+
d1 = m1->x*a + m1->y*b + c;
|
39
|
+
|
40
|
+
|
41
|
+
a = d1*d1*s1;
|
42
|
+
b = d2*d2*s2;
|
43
|
+
|
44
|
+
if( a>b )
|
45
|
+
return a;
|
46
|
+
else
|
47
|
+
return b;
|
48
|
+
}
|
49
|
+
|
50
|
+
extern "C"
|
51
|
+
void computeSetReprojError( MatchSet_t *set, CvMat *model )
|
52
|
+
{
|
53
|
+
for( int i = 0; i < set->length; i ++ ) {
|
54
|
+
set->error[i] = computeReprojError( &(set->d[i]), model );
|
55
|
+
}
|
56
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require '../mkrf-monkey'
|
2
|
+
|
3
|
+
# The compiler for availability checking must be specified as 'g++'
|
4
|
+
# otherwise it will use gcc and choke on Eigen
|
5
|
+
#
|
6
|
+
Mkrf::Generator.new('libcvffi', [ "*.cpp"], { :compiler=>"g++"}) { |g|
|
7
|
+
g.include_library 'stdc++'
|
8
|
+
raise "Can't find 'opencv_core'" unless g.include_library 'opencv_core', 'main', "#{ENV['HOME']}/usr/lib"
|
9
|
+
#g.include_header 'eigen3/Eigen/Core', "#{ENV['HOME']}/usr/include"
|
10
|
+
g.cflags += "-I#{ENV['HOME']}/usr/include "
|
11
|
+
}
|
12
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
#include <stdint.h>
|
3
|
+
|
4
|
+
typedef struct {
|
5
|
+
unsigned int len;
|
6
|
+
uint8_t *data;
|
7
|
+
} uint8_array_t;
|
8
|
+
|
9
|
+
typedef struct {
|
10
|
+
float d[64];
|
11
|
+
} float64_t;
|
12
|
+
|
13
|
+
typedef struct {
|
14
|
+
float d[128];
|
15
|
+
} float128_t;
|
16
|
+
|
17
|
+
extern "C"
|
18
|
+
float L2distance_32f( const float64_t *a, const float64_t *b, int len )
|
19
|
+
{
|
20
|
+
// Start with brute force algorithm
|
21
|
+
float distance = 0.0;
|
22
|
+
for( int i = 0; i < len; i++ ) {
|
23
|
+
distance += (a->d[i] - b->d[i])*(a->d[i] - b->d[i]);
|
24
|
+
}
|
25
|
+
return distance;
|
26
|
+
}
|
27
|
+
|
28
|
+
extern "C"
|
29
|
+
float L2distance_8u( const uint8_array_t a, const uint8_array_t b )
|
30
|
+
{
|
31
|
+
if( a.len != b.len ) { return -1.0; }
|
32
|
+
|
33
|
+
float distance = 0.0;
|
34
|
+
for( unsigned int i = 0; i < a.len; i++ ) {
|
35
|
+
distance += (a.data[i] - b.data[i])*(a.data[i]-b.data[i]);
|
36
|
+
}
|
37
|
+
|
38
|
+
return distance;
|
39
|
+
}
|
data/ext/opensurf/README
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
This is a version of Chris Evans' OpenSURF C++ library, from:
|
2
|
+
|
3
|
+
http://www.chrisevansdev.com/computer-vision-opensurf.html
|
4
|
+
|
5
|
+
distributed under the GPL.
|
6
|
+
|
7
|
+
All *.cpp/*.h files are from the 27/05/2010 source package bag surflib.cpp which
|
8
|
+
is my own C++ to C interface layer.
|
9
|
+
|
10
|
+
Chris' original README follows:
|
11
|
+
|
12
|
+
/***********************************************************
|
13
|
+
* --- OpenSURF --- *
|
14
|
+
* This library is distributed under the GNU GPL. Please *
|
15
|
+
* use the contact form at http://www.chrisevansdev.com *
|
16
|
+
* for more information. *
|
17
|
+
* *
|
18
|
+
* C. Evans, Research Into Robust Visual Features, *
|
19
|
+
* MSc University of Bristol, 2008. *
|
20
|
+
* *
|
21
|
+
************************************************************/
|
22
|
+
|
23
|
+
Thanks for downloading the OpenSURF library. There are 3 different
|
24
|
+
ways to get going with the library:
|
25
|
+
|
26
|
+
1) Build using the supplied makefile and run.
|
27
|
+
2) Open the Visual Studio 2005 .sln file (uses OpenCV 1)
|
28
|
+
3) Open the Visual Studio 2008 .sln file (uses OpenCV 2)
|
29
|
+
|
30
|
+
There are a several examples of code in main.cpp which can be configured
|
31
|
+
to run by change the value of PROCEDURE which is defined at the top.
|
32
|
+
|
33
|
+
If you have any questions contact me via the form on http://www.chrisevansdev.com.
|
34
|
+
|
35
|
+
If you want to stay up to date with the library follow @chrisevansdev on twitter.
|
36
|
+
|
37
|
+
Please also support the library by visiting our sponsors on http://www.chrisevansdev.com.
|
38
|
+
|
@@ -0,0 +1,376 @@
|
|
1
|
+
/***********************************************************
|
2
|
+
* --- OpenSURF --- *
|
3
|
+
* This library is distributed under the GNU GPL. Please *
|
4
|
+
* use the contact form at http://www.chrisevansdev.com *
|
5
|
+
* for more information. *
|
6
|
+
* *
|
7
|
+
* C. Evans, Research Into Robust Visual Features, *
|
8
|
+
* MSc University of Bristol, 2008. *
|
9
|
+
* *
|
10
|
+
************************************************************/
|
11
|
+
|
12
|
+
#include "integral.h"
|
13
|
+
#include "ipoint.h"
|
14
|
+
#include "utils.h"
|
15
|
+
|
16
|
+
#include <vector>
|
17
|
+
|
18
|
+
#include "responselayer.h"
|
19
|
+
#include "fasthessian.h"
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
using namespace std;
|
24
|
+
using namespace cv;
|
25
|
+
|
26
|
+
//-------------------------------------------------------
|
27
|
+
|
28
|
+
//! Constructor without image
|
29
|
+
FastHessian::FastHessian(std::vector<Ipoint> &ipts,
|
30
|
+
const int octaves, const int intervals, const int init_sample,
|
31
|
+
const float thresh)
|
32
|
+
: ipts(ipts), i_width(0), i_height(0)
|
33
|
+
{
|
34
|
+
// Save parameter set
|
35
|
+
saveParameters(octaves, intervals, init_sample, thresh);
|
36
|
+
}
|
37
|
+
|
38
|
+
//-------------------------------------------------------
|
39
|
+
|
40
|
+
//! Constructor with image
|
41
|
+
FastHessian::FastHessian(IplImage *img, std::vector<Ipoint> &ipts,
|
42
|
+
const int octaves, const int intervals, const int init_sample,
|
43
|
+
const float thresh)
|
44
|
+
: ipts(ipts), i_width(0), i_height(0)
|
45
|
+
{
|
46
|
+
// Save parameter set
|
47
|
+
saveParameters(octaves, intervals, init_sample, thresh);
|
48
|
+
|
49
|
+
// Set the current image
|
50
|
+
setIntImage(img);
|
51
|
+
}
|
52
|
+
|
53
|
+
//-------------------------------------------------------
|
54
|
+
|
55
|
+
FastHessian::~FastHessian()
|
56
|
+
{
|
57
|
+
for (unsigned int i = 0; i < responseMap.size(); ++i)
|
58
|
+
{
|
59
|
+
delete responseMap[i];
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
//-------------------------------------------------------
|
64
|
+
|
65
|
+
//! Save the parameters
|
66
|
+
void FastHessian::saveParameters(const int octaves, const int intervals,
|
67
|
+
const int init_sample, const float thresh)
|
68
|
+
{
|
69
|
+
// Initialise variables with bounds-checked values
|
70
|
+
this->octaves =
|
71
|
+
(octaves > 0 && octaves <= 4 ? octaves : OCTAVES);
|
72
|
+
this->intervals =
|
73
|
+
(intervals > 0 && intervals <= 4 ? intervals : INTERVALS);
|
74
|
+
this->init_sample =
|
75
|
+
(init_sample > 0 && init_sample <= 6 ? init_sample : INIT_SAMPLE);
|
76
|
+
this->thresh = (thresh >= 0 ? thresh : THRES);
|
77
|
+
}
|
78
|
+
|
79
|
+
|
80
|
+
//-------------------------------------------------------
|
81
|
+
|
82
|
+
//! Set or re-set the integral image source
|
83
|
+
void FastHessian::setIntImage(IplImage *img)
|
84
|
+
{
|
85
|
+
// Change the source image
|
86
|
+
this->img = img;
|
87
|
+
|
88
|
+
i_height = img->height;
|
89
|
+
i_width = img->width;
|
90
|
+
}
|
91
|
+
|
92
|
+
//-------------------------------------------------------
|
93
|
+
|
94
|
+
//! Find the image features and write into vector of features
|
95
|
+
void FastHessian::getIpoints()
|
96
|
+
{
|
97
|
+
// filter index map
|
98
|
+
static const int filter_map [OCTAVES][INTERVALS] = {{0,1,2,3}, {1,3,4,5}, {3,5,6,7}, {5,7,8,9}, {7,9,10,11}};
|
99
|
+
|
100
|
+
// Clear the vector of exisiting ipts
|
101
|
+
ipts.clear();
|
102
|
+
|
103
|
+
// Build the response map
|
104
|
+
buildResponseMap();
|
105
|
+
|
106
|
+
// Get the response layers
|
107
|
+
ResponseLayer *b, *m, *t;
|
108
|
+
for (int o = 0; o < octaves; ++o) for (int i = 0; i <= 1; ++i)
|
109
|
+
{
|
110
|
+
b = responseMap.at(filter_map[o][i]);
|
111
|
+
m = responseMap.at(filter_map[o][i+1]);
|
112
|
+
t = responseMap.at(filter_map[o][i+2]);
|
113
|
+
|
114
|
+
// loop over middle response layer at density of the most
|
115
|
+
// sparse layer (always top), to find maxima across scale and space
|
116
|
+
for (int r = 0; r < t->height; ++r)
|
117
|
+
{
|
118
|
+
for (int c = 0; c < t->width; ++c)
|
119
|
+
{
|
120
|
+
if (isExtremum(r, c, t, m, b))
|
121
|
+
{
|
122
|
+
interpolateExtremum(r, c, t, m, b);
|
123
|
+
}
|
124
|
+
}
|
125
|
+
}
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
//-------------------------------------------------------
|
130
|
+
|
131
|
+
//! Build map of DoH responses
|
132
|
+
void FastHessian::buildResponseMap()
|
133
|
+
{
|
134
|
+
// Calculate responses for the first 4 octaves:
|
135
|
+
// Oct1: 9, 15, 21, 27
|
136
|
+
// Oct2: 15, 27, 39, 51
|
137
|
+
// Oct3: 27, 51, 75, 99
|
138
|
+
// Oct4: 51, 99, 147,195
|
139
|
+
// Oct5: 99, 195,291,387
|
140
|
+
|
141
|
+
// Deallocate memory and clear any existing response layers
|
142
|
+
for(unsigned int i = 0; i < responseMap.size(); ++i)
|
143
|
+
delete responseMap[i];
|
144
|
+
responseMap.clear();
|
145
|
+
|
146
|
+
// Get image attributes
|
147
|
+
int w = (i_width / init_sample);
|
148
|
+
int h = (i_height / init_sample);
|
149
|
+
int s = (init_sample);
|
150
|
+
|
151
|
+
// Calculate approximated determinant of hessian values
|
152
|
+
if (octaves >= 1)
|
153
|
+
{
|
154
|
+
responseMap.push_back(new ResponseLayer(w, h, s, 9));
|
155
|
+
responseMap.push_back(new ResponseLayer(w, h, s, 15));
|
156
|
+
responseMap.push_back(new ResponseLayer(w, h, s, 21));
|
157
|
+
responseMap.push_back(new ResponseLayer(w, h, s, 27));
|
158
|
+
}
|
159
|
+
|
160
|
+
if (octaves >= 2)
|
161
|
+
{
|
162
|
+
responseMap.push_back(new ResponseLayer(w/2, h/2, s*2, 39));
|
163
|
+
responseMap.push_back(new ResponseLayer(w/2, h/2, s*2, 51));
|
164
|
+
}
|
165
|
+
|
166
|
+
if (octaves >= 3)
|
167
|
+
{
|
168
|
+
responseMap.push_back(new ResponseLayer(w/4, h/4, s*4, 75));
|
169
|
+
responseMap.push_back(new ResponseLayer(w/4, h/4, s*4, 99));
|
170
|
+
}
|
171
|
+
|
172
|
+
if (octaves >= 4)
|
173
|
+
{
|
174
|
+
responseMap.push_back(new ResponseLayer(w/8, h/8, s*8, 147));
|
175
|
+
responseMap.push_back(new ResponseLayer(w/8, h/8, s*8, 195));
|
176
|
+
}
|
177
|
+
|
178
|
+
if (octaves >= 5)
|
179
|
+
{
|
180
|
+
responseMap.push_back(new ResponseLayer(w/16, h/16, s*16, 291));
|
181
|
+
responseMap.push_back(new ResponseLayer(w/16, h/16, s*16, 387));
|
182
|
+
}
|
183
|
+
|
184
|
+
// Extract responses from the image
|
185
|
+
for (unsigned int i = 0; i < responseMap.size(); ++i)
|
186
|
+
{
|
187
|
+
buildResponseLayer(responseMap[i]);
|
188
|
+
}
|
189
|
+
}
|
190
|
+
|
191
|
+
//-------------------------------------------------------
|
192
|
+
|
193
|
+
//! Calculate DoH responses for supplied layer
|
194
|
+
void FastHessian::buildResponseLayer(ResponseLayer *rl)
|
195
|
+
{
|
196
|
+
float *responses = rl->responses; // response storage
|
197
|
+
unsigned char *laplacian = rl->laplacian; // laplacian sign storage
|
198
|
+
int step = rl->step; // step size for this filter
|
199
|
+
int b = (rl->filter - 1) / 2 + 1; // border for this filter
|
200
|
+
int l = rl->filter / 3; // lobe for this filter (filter size / 3)
|
201
|
+
int w = rl->filter; // filter size
|
202
|
+
float inverse_area = 1.f/(w*w); // normalisation factor
|
203
|
+
float Dxx, Dyy, Dxy;
|
204
|
+
|
205
|
+
for(int r, c, ar = 0, index = 0; ar < rl->height; ++ar)
|
206
|
+
{
|
207
|
+
for(int ac = 0; ac < rl->width; ++ac, index++)
|
208
|
+
{
|
209
|
+
// get the image coordinates
|
210
|
+
r = ar * step;
|
211
|
+
c = ac * step;
|
212
|
+
|
213
|
+
// Compute response components
|
214
|
+
Dxx = BoxIntegral(img, r - l + 1, c - b, 2*l - 1, w)
|
215
|
+
- BoxIntegral(img, r - l + 1, c - l / 2, 2*l - 1, l)*3;
|
216
|
+
Dyy = BoxIntegral(img, r - b, c - l + 1, w, 2*l - 1)
|
217
|
+
- BoxIntegral(img, r - l / 2, c - l + 1, l, 2*l - 1)*3;
|
218
|
+
Dxy = + BoxIntegral(img, r - l, c + 1, l, l)
|
219
|
+
+ BoxIntegral(img, r + 1, c - l, l, l)
|
220
|
+
- BoxIntegral(img, r - l, c - l, l, l)
|
221
|
+
- BoxIntegral(img, r + 1, c + 1, l, l);
|
222
|
+
|
223
|
+
// Normalise the filter responses with respect to their size
|
224
|
+
Dxx *= inverse_area;
|
225
|
+
Dyy *= inverse_area;
|
226
|
+
Dxy *= inverse_area;
|
227
|
+
|
228
|
+
// Get the determinant of hessian response & laplacian sign
|
229
|
+
responses[index] = (Dxx * Dyy - 0.81f * Dxy * Dxy);
|
230
|
+
laplacian[index] = (Dxx + Dyy >= 0 ? 1 : 0);
|
231
|
+
|
232
|
+
#ifdef RL_DEBUG
|
233
|
+
// create list of the image coords for each response
|
234
|
+
rl->coords.push_back(std::make_pair<int,int>(r,c));
|
235
|
+
#endif
|
236
|
+
}
|
237
|
+
}
|
238
|
+
}
|
239
|
+
|
240
|
+
//-------------------------------------------------------
|
241
|
+
|
242
|
+
//! Non Maximal Suppression function
|
243
|
+
int FastHessian::isExtremum(int r, int c, ResponseLayer *t, ResponseLayer *m, ResponseLayer *b)
|
244
|
+
{
|
245
|
+
// bounds check
|
246
|
+
int layerBorder = (t->filter + 1) / (2 * t->step);
|
247
|
+
if (r <= layerBorder || r >= t->height - layerBorder || c <= layerBorder || c >= t->width - layerBorder)
|
248
|
+
return 0;
|
249
|
+
|
250
|
+
// check the candidate point in the middle layer is above thresh
|
251
|
+
float candidate = m->getResponse(r, c, t);
|
252
|
+
if (candidate < thresh)
|
253
|
+
return 0;
|
254
|
+
|
255
|
+
for (int rr = -1; rr <=1; ++rr)
|
256
|
+
{
|
257
|
+
for (int cc = -1; cc <=1; ++cc)
|
258
|
+
{
|
259
|
+
// if any response in 3x3x3 is greater candidate not maximum
|
260
|
+
if (
|
261
|
+
t->getResponse(r+rr, c+cc) >= candidate ||
|
262
|
+
((rr != 0 || cc != 0) && m->getResponse(r+rr, c+cc, t) >= candidate) ||
|
263
|
+
b->getResponse(r+rr, c+cc, t) >= candidate
|
264
|
+
)
|
265
|
+
return 0;
|
266
|
+
}
|
267
|
+
}
|
268
|
+
|
269
|
+
return 1;
|
270
|
+
}
|
271
|
+
|
272
|
+
//-------------------------------------------------------
|
273
|
+
|
274
|
+
//! Interpolate scale-space extrema to subpixel accuracy to form an image feature.
|
275
|
+
void FastHessian::interpolateExtremum(int r, int c, ResponseLayer *t, ResponseLayer *m, ResponseLayer *b)
|
276
|
+
{
|
277
|
+
// get the step distance between filters
|
278
|
+
// check the middle filter is mid way between top and bottom
|
279
|
+
int filterStep = (m->filter - b->filter);
|
280
|
+
assert(filterStep > 0 && t->filter - m->filter == m->filter - b->filter);
|
281
|
+
|
282
|
+
// Get the offsets to the actual location of the extremum
|
283
|
+
double xi = 0, xr = 0, xc = 0;
|
284
|
+
interpolateStep(r, c, t, m, b, &xi, &xr, &xc );
|
285
|
+
|
286
|
+
// If point is sufficiently close to the actual extremum
|
287
|
+
if( fabs( xi ) < 0.5f && fabs( xr ) < 0.5f && fabs( xc ) < 0.5f )
|
288
|
+
{
|
289
|
+
Ipoint ipt;
|
290
|
+
ipt.x = static_cast<float>((c + xc) * t->step);
|
291
|
+
ipt.y = static_cast<float>((r + xr) * t->step);
|
292
|
+
ipt.scale = static_cast<float>((0.1333f) * (m->filter + xi * filterStep));
|
293
|
+
ipt.laplacian = static_cast<int>(m->getLaplacian(r,c,t));
|
294
|
+
ipts.push_back(ipt);
|
295
|
+
}
|
296
|
+
}
|
297
|
+
|
298
|
+
//-------------------------------------------------------
|
299
|
+
|
300
|
+
//! Performs one step of extremum interpolation.
|
301
|
+
void FastHessian::interpolateStep(int r, int c, ResponseLayer *t, ResponseLayer *m, ResponseLayer *b,
|
302
|
+
double* xi, double* xr, double* xc )
|
303
|
+
{
|
304
|
+
CvMat* dD, * H, * H_inv, X;
|
305
|
+
double x[3] = { 0 };
|
306
|
+
|
307
|
+
dD = deriv3D( r, c, t, m, b );
|
308
|
+
H = hessian3D( r, c, t, m, b );
|
309
|
+
H_inv = cvCreateMat( 3, 3, CV_64FC1 );
|
310
|
+
cvInvert( H, H_inv, CV_SVD );
|
311
|
+
cvInitMatHeader( &X, 3, 1, CV_64FC1, x, CV_AUTOSTEP );
|
312
|
+
cvGEMM( H_inv, dD, -1, NULL, 0, &X, 0 );
|
313
|
+
|
314
|
+
cvReleaseMat( &dD );
|
315
|
+
cvReleaseMat( &H );
|
316
|
+
cvReleaseMat( &H_inv );
|
317
|
+
|
318
|
+
*xi = x[2];
|
319
|
+
*xr = x[1];
|
320
|
+
*xc = x[0];
|
321
|
+
}
|
322
|
+
|
323
|
+
//-------------------------------------------------------
|
324
|
+
|
325
|
+
//! Computes the partial derivatives in x, y, and scale of a pixel.
|
326
|
+
CvMat* FastHessian::deriv3D(int r, int c, ResponseLayer *t, ResponseLayer *m, ResponseLayer *b)
|
327
|
+
{
|
328
|
+
CvMat* dI;
|
329
|
+
double dx, dy, ds;
|
330
|
+
|
331
|
+
dx = (m->getResponse(r, c + 1, t) - m->getResponse(r, c - 1, t)) / 2.0;
|
332
|
+
dy = (m->getResponse(r + 1, c, t) - m->getResponse(r - 1, c, t)) / 2.0;
|
333
|
+
ds = (t->getResponse(r, c) - b->getResponse(r, c, t)) / 2.0;
|
334
|
+
|
335
|
+
dI = cvCreateMat( 3, 1, CV_64FC1 );
|
336
|
+
cvmSet( dI, 0, 0, dx );
|
337
|
+
cvmSet( dI, 1, 0, dy );
|
338
|
+
cvmSet( dI, 2, 0, ds );
|
339
|
+
|
340
|
+
return dI;
|
341
|
+
}
|
342
|
+
|
343
|
+
//-------------------------------------------------------
|
344
|
+
|
345
|
+
//! Computes the 3D Hessian matrix for a pixel.
|
346
|
+
CvMat* FastHessian::hessian3D(int r, int c, ResponseLayer *t, ResponseLayer *m, ResponseLayer *b)
|
347
|
+
{
|
348
|
+
CvMat* H;
|
349
|
+
double v, dxx, dyy, dss, dxy, dxs, dys;
|
350
|
+
|
351
|
+
v = m->getResponse(r, c, t);
|
352
|
+
dxx = m->getResponse(r, c + 1, t) + m->getResponse(r, c - 1, t) - 2 * v;
|
353
|
+
dyy = m->getResponse(r + 1, c, t) + m->getResponse(r - 1, c, t) - 2 * v;
|
354
|
+
dss = t->getResponse(r, c) + b->getResponse(r, c, t) - 2 * v;
|
355
|
+
dxy = ( m->getResponse(r + 1, c + 1, t) - m->getResponse(r + 1, c - 1, t) -
|
356
|
+
m->getResponse(r - 1, c + 1, t) + m->getResponse(r - 1, c - 1, t) ) / 4.0;
|
357
|
+
dxs = ( t->getResponse(r, c + 1) - t->getResponse(r, c - 1) -
|
358
|
+
b->getResponse(r, c + 1, t) + b->getResponse(r, c - 1, t) ) / 4.0;
|
359
|
+
dys = ( t->getResponse(r + 1, c) - t->getResponse(r - 1, c) -
|
360
|
+
b->getResponse(r + 1, c, t) + b->getResponse(r - 1, c, t) ) / 4.0;
|
361
|
+
|
362
|
+
H = cvCreateMat( 3, 3, CV_64FC1 );
|
363
|
+
cvmSet( H, 0, 0, dxx );
|
364
|
+
cvmSet( H, 0, 1, dxy );
|
365
|
+
cvmSet( H, 0, 2, dxs );
|
366
|
+
cvmSet( H, 1, 0, dxy );
|
367
|
+
cvmSet( H, 1, 1, dyy );
|
368
|
+
cvmSet( H, 1, 2, dys );
|
369
|
+
cvmSet( H, 2, 0, dxs );
|
370
|
+
cvmSet( H, 2, 1, dys );
|
371
|
+
cvmSet( H, 2, 2, dss );
|
372
|
+
|
373
|
+
return H;
|
374
|
+
}
|
375
|
+
|
376
|
+
//-------------------------------------------------------
|