opencv-ffi-fast 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 +4 -0
- data/Gemfile +7 -0
- data/README.md +75 -0
- data/Rakefile +22 -0
- data/ext/Rakefile +13 -0
- data/ext/fast/.gitignore +4 -0
- data/ext/fast/LICENSE +30 -0
- data/ext/fast/README +43 -0
- data/ext/fast/fast.c +71 -0
- data/ext/fast/fast.h +31 -0
- data/ext/fast/fast_10.c +4666 -0
- data/ext/fast/fast_11.c +3910 -0
- data/ext/fast/fast_12.c +3134 -0
- data/ext/fast/fast_9.c +5910 -0
- data/ext/fast/mkrf_conf.rb +6 -0
- data/ext/fast/nonmax.c +117 -0
- data/ext/mkrf-monkey.rb +85 -0
- data/ext/mkrf-rakehelper-monkey.rb +52 -0
- data/ext/mkrf_conf.rb +3 -0
- data/lib/opencv-ffi-fast.rb +1 -0
- data/lib/opencv-ffi-fast/fast.rb +113 -0
- data/lib/opencv-ffi-fast/version.rb +5 -0
- data/opencv-ffi-fast.gemspec +25 -0
- data/test/test_ext.rb +50 -0
- data/test/test_wrapper.rb +35 -0
- metadata +112 -0
data/ext/fast/nonmax.c
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#include <stdlib.h>
|
|
2
|
+
#include "fast.h"
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
#define Compare(X, Y) ((X)>=(Y))
|
|
6
|
+
|
|
7
|
+
xy* nonmax_suppression(const xy* corners, const int* scores, int num_corners, int* ret_num_nonmax)
|
|
8
|
+
{
|
|
9
|
+
int num_nonmax=0;
|
|
10
|
+
int last_row;
|
|
11
|
+
int* row_start;
|
|
12
|
+
int i, j;
|
|
13
|
+
xy* ret_nonmax;
|
|
14
|
+
const int sz = (int)num_corners;
|
|
15
|
+
|
|
16
|
+
/*Point above points (roughly) to the pixel above the one of interest, if there
|
|
17
|
+
is a feature there.*/
|
|
18
|
+
int point_above = 0;
|
|
19
|
+
int point_below = 0;
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
if(num_corners < 1)
|
|
23
|
+
{
|
|
24
|
+
*ret_num_nonmax = 0;
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
ret_nonmax = (xy*)malloc(num_corners * sizeof(xy));
|
|
29
|
+
|
|
30
|
+
/* Find where each row begins
|
|
31
|
+
(the corners are output in raster scan order). A beginning of -1 signifies
|
|
32
|
+
that there are no corners on that row. */
|
|
33
|
+
last_row = corners[num_corners-1].y;
|
|
34
|
+
row_start = (int*)malloc((last_row+1)*sizeof(int));
|
|
35
|
+
|
|
36
|
+
for(i=0; i < last_row+1; i++)
|
|
37
|
+
row_start[i] = -1;
|
|
38
|
+
|
|
39
|
+
{
|
|
40
|
+
int prev_row = -1;
|
|
41
|
+
for(i=0; i< num_corners; i++)
|
|
42
|
+
if(corners[i].y != prev_row)
|
|
43
|
+
{
|
|
44
|
+
row_start[corners[i].y] = i;
|
|
45
|
+
prev_row = corners[i].y;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
for(i=0; i < sz; i++)
|
|
52
|
+
{
|
|
53
|
+
int score = scores[i];
|
|
54
|
+
xy pos = corners[i];
|
|
55
|
+
|
|
56
|
+
/*Check left */
|
|
57
|
+
if(i > 0)
|
|
58
|
+
if(corners[i-1].x == pos.x-1 && corners[i-1].y == pos.y && Compare(scores[i-1], score))
|
|
59
|
+
continue;
|
|
60
|
+
|
|
61
|
+
/*Check right*/
|
|
62
|
+
if(i < (sz - 1))
|
|
63
|
+
if(corners[i+1].x == pos.x+1 && corners[i+1].y == pos.y && Compare(scores[i+1], score))
|
|
64
|
+
continue;
|
|
65
|
+
|
|
66
|
+
/*Check above (if there is a valid row above)*/
|
|
67
|
+
if(pos.y != 0 && row_start[pos.y - 1] != -1)
|
|
68
|
+
{
|
|
69
|
+
/*Make sure that current point_above is one
|
|
70
|
+
row above.*/
|
|
71
|
+
if(corners[point_above].y < pos.y - 1)
|
|
72
|
+
point_above = row_start[pos.y-1];
|
|
73
|
+
|
|
74
|
+
/*Make point_above point to the first of the pixels above the current point,
|
|
75
|
+
if it exists.*/
|
|
76
|
+
for(; corners[point_above].y < pos.y && corners[point_above].x < pos.x - 1; point_above++)
|
|
77
|
+
{}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
for(j=point_above; corners[j].y < pos.y && corners[j].x <= pos.x + 1; j++)
|
|
81
|
+
{
|
|
82
|
+
int x = corners[j].x;
|
|
83
|
+
if( (x == pos.x - 1 || x ==pos.x || x == pos.x+1) && Compare(scores[j], score))
|
|
84
|
+
goto cont;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/*Check below (if there is anything below)*/
|
|
90
|
+
if(pos.y != last_row && row_start[pos.y + 1] != -1 && point_below < sz) /*Nothing below*/
|
|
91
|
+
{
|
|
92
|
+
if(corners[point_below].y < pos.y + 1)
|
|
93
|
+
point_below = row_start[pos.y+1];
|
|
94
|
+
|
|
95
|
+
/* Make point below point to one of the pixels belowthe current point, if it
|
|
96
|
+
exists.*/
|
|
97
|
+
for(; point_below < sz && corners[point_below].y == pos.y+1 && corners[point_below].x < pos.x - 1; point_below++)
|
|
98
|
+
{}
|
|
99
|
+
|
|
100
|
+
for(j=point_below; j < sz && corners[j].y == pos.y+1 && corners[j].x <= pos.x + 1; j++)
|
|
101
|
+
{
|
|
102
|
+
int x = corners[j].x;
|
|
103
|
+
if( (x == pos.x - 1 || x ==pos.x || x == pos.x+1) && Compare(scores[j],score))
|
|
104
|
+
goto cont;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
ret_nonmax[num_nonmax++] = corners[i];
|
|
109
|
+
cont:
|
|
110
|
+
;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
free(row_start);
|
|
114
|
+
*ret_num_nonmax = num_nonmax;
|
|
115
|
+
return ret_nonmax;
|
|
116
|
+
}
|
|
117
|
+
|
data/ext/mkrf-monkey.rb
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
|
|
2
|
+
require 'mkrf'
|
|
3
|
+
|
|
4
|
+
# I admit it, I'm monkey-patching mkrf to get the behavior I want.
|
|
5
|
+
module Mkrf
|
|
6
|
+
|
|
7
|
+
class Generator
|
|
8
|
+
|
|
9
|
+
def rakefile_contents # :nodoc:
|
|
10
|
+
objext = CONFIG['OBJEXT']
|
|
11
|
+
cc = CONFIG['CC'] || 'gcc'
|
|
12
|
+
cpp = CONFIG['CXX'] || 'g++'
|
|
13
|
+
extension_sym = File.basename( @extension_name, ".#{CONFIG['DLEXT']}" ).to_sym
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
<<-END_RAKEFILE
|
|
17
|
+
# Generated by mkrf, monkey patched for opencv-ffi
|
|
18
|
+
require 'rake/clean'
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
SRC = FileList[#{sources.join(',')}]
|
|
22
|
+
OBJ = SRC.ext('#{objext}')
|
|
23
|
+
CC = '#{cc}'
|
|
24
|
+
CPP = '#{cpp}'
|
|
25
|
+
|
|
26
|
+
CLEAN.include(OBJ)
|
|
27
|
+
CLOBBER.include('#{@extension_name}', 'mkrf.log', 'Rakefile')
|
|
28
|
+
|
|
29
|
+
ADDITIONAL_OBJECTS = '#{objects}'
|
|
30
|
+
|
|
31
|
+
LDSHARED = "#{@available.ldshared_string} #{ldshared}"
|
|
32
|
+
|
|
33
|
+
LIBPATH = "#{library_path(CONFIG['libdir'])} #{@available.library_paths_compile_string}"
|
|
34
|
+
|
|
35
|
+
INCLUDES = "#{@available.includes_compile_string}"
|
|
36
|
+
|
|
37
|
+
LIBS = "#{@available.library_compile_string}"
|
|
38
|
+
|
|
39
|
+
CFLAGS = "#{cflags} #{defines_compile_string}"
|
|
40
|
+
|
|
41
|
+
RUBYARCHDIR = "\#{ENV["RUBYARCHDIR"]}"
|
|
42
|
+
LIBRUBYARG_SHARED = "#{CONFIG['LIBRUBYARG_SHARED']}"
|
|
43
|
+
|
|
44
|
+
task :default => :build_library
|
|
45
|
+
|
|
46
|
+
# Add one layer of indirection so I can generically call "rake build_library"
|
|
47
|
+
# and have it work ... or not work if the wrong rakefile is being run
|
|
48
|
+
task :build_library => '#{@extension_name}'
|
|
49
|
+
|
|
50
|
+
rule '.#{objext}' => '.c' do |t|
|
|
51
|
+
sh "\#{CC} \#{CFLAGS} \#{INCLUDES} -o \#{t.name} -c \#{t.source}"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
rule '.#{objext}' => '.cpp' do |t|
|
|
55
|
+
sh "\#{CPP} \#{CFLAGS} \#{INCLUDES} -o \#{t.name} -c \#{t.source}"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
DEPS = OBJ.clone.add('Rakefile')
|
|
59
|
+
desc "Build this extension"
|
|
60
|
+
file '#{@extension_name}' => DEPS do
|
|
61
|
+
sh "\#{LDSHARED} \#{LIBPATH} #{@available.ld_outfile(@extension_name)} \#{OBJ} \#{ADDITIONAL_OBJECTS} \#{LIBS} \#{LIBRUBYARG_SHARED}"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
desc "Rebuild rakefile"
|
|
65
|
+
file 'Rakefile' => 'mkrf_conf.rb' do |t|
|
|
66
|
+
ruby 'mkrf_conf.rb'
|
|
67
|
+
puts "Rebuilt Rakefile. Run \'rake #{extension_sym.to_s}\' again"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
desc "Install this extension"
|
|
71
|
+
task :install => '#{@extension_name}' do
|
|
72
|
+
makedirs "\#{RUBYARCHDIR}"
|
|
73
|
+
install "#{@extension_name}", "\#{RUBYARCHDIR}"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
#{additional_code}
|
|
77
|
+
END_RAKEFILE
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
|
|
@@ -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 @@
|
|
|
1
|
+
require "opencv-ffi-fast/version"
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
|
|
2
|
+
require 'nice-ffi'
|
|
3
|
+
require 'opencv-ffi'
|
|
4
|
+
|
|
5
|
+
module CVFFI
|
|
6
|
+
module FAST
|
|
7
|
+
|
|
8
|
+
class FASTResultsArray
|
|
9
|
+
include Enumerable
|
|
10
|
+
|
|
11
|
+
attr_accessor :points
|
|
12
|
+
attr_accessor :nPoints
|
|
13
|
+
|
|
14
|
+
def initialize( pts, nPts )
|
|
15
|
+
@points = pts
|
|
16
|
+
@nPoints = nPts
|
|
17
|
+
|
|
18
|
+
# Define a destructor do dispose of the results
|
|
19
|
+
destructor = Proc.new { pts.free }
|
|
20
|
+
ObjectSpace.define_finalizer( self, destructor )
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def each
|
|
24
|
+
if @nPoints > 0
|
|
25
|
+
0.upto(@nPoints-1) { |i|
|
|
26
|
+
yield Xy.new( @points[i] )
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
alias :size :nPoints
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class Params
|
|
36
|
+
attr_accessor :points, :threshold
|
|
37
|
+
|
|
38
|
+
VALID_SIZES = [ 9, 10, 11, 12 ]
|
|
39
|
+
|
|
40
|
+
def size_valid?( sz )
|
|
41
|
+
VALID_SIZES.include? sz
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def initialize( opts = {} )
|
|
45
|
+
p opts
|
|
46
|
+
@points = opts[:points] || 9
|
|
47
|
+
@threshold = opts[:threshold] || 20
|
|
48
|
+
|
|
49
|
+
raise "Hm, invalid size #{@points} specified for FAST keypoint detector" unless size_valid? @points
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def to_hash
|
|
53
|
+
{ :points => @points, :threshold => @threshold }
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def self.detect( img, params )
|
|
59
|
+
FASTDetect( params.points, img, params.threshold )
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self.FASTDetect( size, img, threshold )
|
|
63
|
+
nResults = FFI::MemoryPointer.new :int
|
|
64
|
+
|
|
65
|
+
if img.is_a?( IplImage )
|
|
66
|
+
# Ensure the image is b&w
|
|
67
|
+
img = img.ensure_greyscale
|
|
68
|
+
|
|
69
|
+
results = FFI::Pointer.new :pointer, method("fast#{size}_detect").call( img.imageData, img.width, img.height, img.widthStep, threshold, nResults )
|
|
70
|
+
else
|
|
71
|
+
raise ArgumentError, "Don't know how to deal with image class #{img.class}"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Dereference the two pointers
|
|
75
|
+
nPoints = nResults.read_int
|
|
76
|
+
points = FFI::Pointer.new Xy, results
|
|
77
|
+
|
|
78
|
+
FASTResultsArray.new( points, nPoints )
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def self.FAST9Detect( img, threshold ); FASTDetect( 9, img, threshold ); end
|
|
82
|
+
def self.FAST10Detect( img, threshold ); FASTDetect( 10, img, threshold ); end
|
|
83
|
+
def self.FAST11Detect( img, threshold ); FASTDetect( 11, img, threshold ); end
|
|
84
|
+
def self.FAST12Detect( img, threshold ); FASTDetect( 12, img, threshold ); end
|
|
85
|
+
|
|
86
|
+
#
|
|
87
|
+
## Here's the actual FFI interface
|
|
88
|
+
#
|
|
89
|
+
extend NiceFFI::Library
|
|
90
|
+
|
|
91
|
+
libs_dir = File.dirname(__FILE__) + "/../../ext/fast/"
|
|
92
|
+
pathset = NiceFFI::PathSet::DEFAULT.prepend( libs_dir )
|
|
93
|
+
load_library("cvffi_fast", pathset)
|
|
94
|
+
|
|
95
|
+
class Xy < NiceFFI::Struct
|
|
96
|
+
layout :x, :int,
|
|
97
|
+
:y, :int
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Leave result as pointer, not Xy.typed_pointer as it makes it easier to deference
|
|
101
|
+
# it to an array of Xy
|
|
102
|
+
|
|
103
|
+
def self.fast_detect_function( sz )
|
|
104
|
+
attach_function "fast#{sz}_detect".to_sym, [ :pointer, :int, :int, :int, :int, :pointer ], :pointer
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
fast_detect_function 9
|
|
108
|
+
fast_detect_function 10
|
|
109
|
+
fast_detect_function 11
|
|
110
|
+
fast_detect_function 12
|
|
111
|
+
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
3
|
+
require "opencv-ffi-fast/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = "opencv-ffi-fast"
|
|
7
|
+
s.version = CVFFI::FAST::VERSION
|
|
8
|
+
s.authors = ["Aaron Marburg"]
|
|
9
|
+
s.email = ["aaron.marburg@pg.canterbury.ac.nz"]
|
|
10
|
+
s.homepage = "http://github.com/amarburg/opencv-ffi-fast"
|
|
11
|
+
s.summary = %q{Edward Rosten's FAST keypoint detector algorithm, as a plug-in for OpenCV-FFI.}
|
|
12
|
+
s.description = %q{Edward Rosten's FAST keypoint detector algorithm, as a plug-in for OpenCV-FFI.}
|
|
13
|
+
|
|
14
|
+
s.rubyforge_project = "opencv-ffi-fast"
|
|
15
|
+
|
|
16
|
+
s.files = `git ls-files`.split("\n")
|
|
17
|
+
s.extensions = "ext/mkrf_conf.rb"
|
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
20
|
+
s.require_paths = ["lib"]
|
|
21
|
+
|
|
22
|
+
s.add_dependency "nice-ffi"
|
|
23
|
+
s.add_dependency "mkrf"
|
|
24
|
+
s.add_dependency "opencv-ffi"
|
|
25
|
+
end
|
data/test/test_ext.rb
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
|
|
2
|
+
require 'test/setup'
|
|
3
|
+
require 'opencv-ffi-ext/fast'
|
|
4
|
+
require 'opencv-ffi'
|
|
5
|
+
|
|
6
|
+
class TestSURF < Test::Unit::TestCase
|
|
7
|
+
|
|
8
|
+
def setup
|
|
9
|
+
@img = CVFFI::cvLoadImage( TEST_IMAGE_FILE, CVFFI::CV_LOAD_IMAGE_COLOR )
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_cvFASTDetector
|
|
14
|
+
greyImg = CVFFI::cvCreateImage( CVFFI::CvSize.new( { :height => @img.height,
|
|
15
|
+
:width => @img.width }),
|
|
16
|
+
:IPL_DEPTH_8U, 1 )
|
|
17
|
+
CVFFI::cvCvtColor( @img, greyImg, :CV_RGB2GRAY )
|
|
18
|
+
|
|
19
|
+
smallGreyImg = CVFFI::cvCreateImage( CVFFI::CvSize.new( { :height => greyImg.height/2,
|
|
20
|
+
:width => greyImg.width/2 } ),
|
|
21
|
+
:IPL_DEPTH_8U, 1 )
|
|
22
|
+
|
|
23
|
+
CVFFI::cvResize( greyImg, smallGreyImg, :CV_INTER_LINEAR )
|
|
24
|
+
|
|
25
|
+
#CVFFI::cvSaveImage( TestSetup::output_filename("greyImage.jpg"), smallGreyImg.to_ptr )
|
|
26
|
+
|
|
27
|
+
nResults = FFI::MemoryPointer.new :int
|
|
28
|
+
|
|
29
|
+
results = FFI::Pointer.new :pointer, CVFFI::FAST::fast12_detect( smallGreyImg.imageData, smallGreyImg.width, smallGreyImg.height, smallGreyImg.widthStep, 50, nResults )
|
|
30
|
+
|
|
31
|
+
# Dereference the two pointers
|
|
32
|
+
nPoints = nResults.read_int
|
|
33
|
+
points = FFI::Pointer.new CVFFI::FAST::Xy, results
|
|
34
|
+
|
|
35
|
+
#p points.inspect
|
|
36
|
+
#p nPoints.inspect
|
|
37
|
+
|
|
38
|
+
0.upto(nPoints-1) { |i|
|
|
39
|
+
pt = CVFFI::FAST::Xy.new( points[i] )
|
|
40
|
+
|
|
41
|
+
CVFFI::cvCircle( smallGreyImg, CVFFI::CvPoint.new( :x => pt.x.to_i, :y => pt.y.to_i ), 5,
|
|
42
|
+
CVFFI::CvScalar.new( :w=>255, :x=>255, :y=>255, :z=>0 ), -1, 8, 0 )
|
|
43
|
+
}
|
|
44
|
+
CVFFI::cvSaveImage( TestSetup::output_filename("greyImageFASTPts.jpg"), smallGreyImg )
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
results.free
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|