opencv-ffi 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
//-------------------------------------------------------
|