mirror of
https://github.com/ruby-opencv/ruby-opencv
synced 2023-03-27 23:22:12 -04:00
Merge branch 'master' into documentation
This commit is contained in:
commit
1c11610b14
12 changed files with 187 additions and 14 deletions
16
examples/matching_to_many_images.rb
Normal file
16
examples/matching_to_many_images.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
require 'opencv'
|
||||
require 'benchmark'
|
||||
include OpenCV
|
||||
|
||||
data = File.join(File.dirname(__FILE__), 'matching_to_many_images')
|
||||
|
||||
query = IplImage.load File.join(data, 'query.png'), CV_LOAD_IMAGE_GRAYSCALE
|
||||
image_files = ['1.png', '2.png', '3.png'].map{|f| File.join(data, 'train', f)}
|
||||
images = image_files.map{|f| IplImage.load f, CV_LOAD_IMAGE_GRAYSCALE}
|
||||
|
||||
|
||||
matchs = query.match_descriptors(images)
|
||||
|
||||
match_index, count = matchs.max_by {|image_index, count| count}
|
||||
|
||||
puts "max match: #{image_files[match_index]}"
|
BIN
examples/matching_to_many_images/query.png
Executable file
BIN
examples/matching_to_many_images/query.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 119 KiB |
BIN
examples/matching_to_many_images/train/1.png
Executable file
BIN
examples/matching_to_many_images/train/1.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 116 KiB |
BIN
examples/matching_to_many_images/train/2.png
Executable file
BIN
examples/matching_to_many_images/train/2.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 112 KiB |
BIN
examples/matching_to_many_images/train/3.png
Executable file
BIN
examples/matching_to_many_images/train/3.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 118 KiB |
3
examples/matching_to_many_images/train/trainImages.txt
Executable file
3
examples/matching_to_many_images/train/trainImages.txt
Executable file
|
@ -0,0 +1,3 @@
|
|||
1.png
|
||||
2.png
|
||||
3.png
|
|
@ -33,8 +33,7 @@ rb_class()
|
|||
VALUE
|
||||
rb_allocate(VALUE klass)
|
||||
{
|
||||
CvChain *ptr;
|
||||
return Data_Make_Struct(klass, CvChain, 0, 0, ptr);
|
||||
return Data_Wrap_Struct(klass, mark_root_object, unregister_object, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -58,11 +57,15 @@ rb_initialize(int argc, VALUE *argv, VALUE self)
|
|||
storage = rb_cvCreateMemStorage(0);
|
||||
try {
|
||||
DATA_PTR(self) = (CvChain*)cvCreateSeq(CV_SEQ_ELTYPE_CODE, sizeof(CvChain),
|
||||
sizeof(char), storage);
|
||||
sizeof(int), storage);
|
||||
}
|
||||
catch (cv::Exception& e) {
|
||||
raise_cverror(e);
|
||||
}
|
||||
CvSeq* self_ptr = CVSEQ(self);
|
||||
cCvSeq::register_elem_class(self_ptr, rb_cFixnum);
|
||||
register_root_object(self_ptr, storage_value);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -108,7 +111,7 @@ rb_codes(VALUE self)
|
|||
cvStartReadChainPoints(chain, &reader);
|
||||
for (int i = 0; i < total; ++i) {
|
||||
CV_READ_SEQ_ELEM(reader.code, (*((CvSeqReader*)&(reader))));
|
||||
rb_ary_store(ary, i, CHR2FIX(reader.code));
|
||||
rb_ary_store(ary, i, INT2FIX(reader.code));
|
||||
}
|
||||
}
|
||||
catch (cv::Exception& e) {
|
||||
|
@ -184,7 +187,7 @@ new_object()
|
|||
VALUE storage = cCvMemStorage::new_object();
|
||||
CvSeq *seq = NULL;
|
||||
try {
|
||||
seq = cvCreateSeq(CV_SEQ_CHAIN_CONTOUR, sizeof(CvChain), sizeof(char), CVMEMSTORAGE(storage));
|
||||
seq = cvCreateSeq(CV_SEQ_CHAIN_CONTOUR, sizeof(CvChain), sizeof(int), CVMEMSTORAGE(storage));
|
||||
}
|
||||
catch (cv::Exception& e) {
|
||||
raise_cverror(e);
|
||||
|
|
|
@ -37,8 +37,7 @@ rb_class()
|
|||
VALUE
|
||||
rb_allocate(VALUE klass)
|
||||
{
|
||||
CvContour *ptr;
|
||||
return Data_Make_Struct(klass, CvContour, mark_root_object, unregister_object, ptr);
|
||||
return Data_Wrap_Struct(klass, mark_root_object, unregister_object, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -59,15 +58,15 @@ rb_initialize(int argc, VALUE *argv, VALUE self)
|
|||
else
|
||||
storage = CHECK_CVMEMSTORAGE(storage);
|
||||
|
||||
CvContour* contour = (CvContour*)DATA_PTR(self);
|
||||
try {
|
||||
contour = (CvContour*)cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvContour),
|
||||
DATA_PTR(self) = (CvContour*)cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvContour),
|
||||
sizeof(CvPoint), CVMEMSTORAGE(storage));
|
||||
}
|
||||
catch (cv::Exception& e) {
|
||||
raise_cverror(e);
|
||||
}
|
||||
register_root_object((CvSeq*)contour, storage);
|
||||
cCvSeq::register_elem_class(CVSEQ(self), cCvPoint::rb_class());
|
||||
register_root_object(CVSEQ(self), storage);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
|
|
@ -366,6 +366,7 @@ void define_ruby_class()
|
|||
rb_define_method(rb_klass, "equalize_hist", RUBY_METHOD_FUNC(rb_equalize_hist), 0);
|
||||
rb_define_method(rb_klass, "match_template", RUBY_METHOD_FUNC(rb_match_template), -1);
|
||||
rb_define_method(rb_klass, "match_shapes", RUBY_METHOD_FUNC(rb_match_shapes), -1);
|
||||
rb_define_method(rb_klass, "match_descriptors", RUBY_METHOD_FUNC(rb_match_descriptors), -1);
|
||||
|
||||
rb_define_method(rb_klass, "mean_shift", RUBY_METHOD_FUNC(rb_mean_shift), 2);
|
||||
rb_define_method(rb_klass, "cam_shift", RUBY_METHOD_FUNC(rb_cam_shift), 2);
|
||||
|
@ -5097,6 +5098,7 @@ rb_moments(int argc, VALUE *argv, VALUE self)
|
|||
*
|
||||
* Finds lines in binary image using a Hough transform.
|
||||
* * method –
|
||||
|
||||
* * The Hough transform variant, one of the following:
|
||||
* * - CV_HOUGH_STANDARD - classical or standard Hough transform.
|
||||
* * - CV_HOUGH_PROBABILISTIC - probabilistic Hough transform (more efficient in case if picture contains a few long linear segments).
|
||||
|
@ -5105,11 +5107,13 @@ rb_moments(int argc, VALUE *argv, VALUE self)
|
|||
* * theta - Angle resolution measured in radians.
|
||||
* * threshold - Threshold parameter. A line is returned by the function if the corresponding accumulator value is greater than threshold.
|
||||
* * param1 –
|
||||
|
||||
* * The first method-dependent parameter:
|
||||
* * For the classical Hough transform it is not used (0).
|
||||
* * For the probabilistic Hough transform it is the minimum line length.
|
||||
* * For the multi-scale Hough transform it is the divisor for the distance resolution . (The coarse distance resolution will be rho and the accurate resolution will be (rho / param1)).
|
||||
* * param2 –
|
||||
|
||||
* * The second method-dependent parameter:
|
||||
* * For the classical Hough transform it is not used (0).
|
||||
* * For the probabilistic Hough transform it is the maximum gap between line segments lying on the same line to treat them as a single line segment (i.e. to join them).
|
||||
|
@ -5325,6 +5329,93 @@ rb_match_shapes(int argc, VALUE *argv, VALUE self)
|
|||
return rb_float_new(result);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Port from OpenCV sample: matching_to_many_images.cpp
|
||||
* call-seq:
|
||||
* match_descriptors(<i>images[, detector_type="SURF"][, descriptor_type="SURF"][, matcher_type="FlannBased"]</i>) -> Hash
|
||||
*
|
||||
* Matching descriptors detected on one image to descriptors detected in image array.
|
||||
* Returns a Hash contains match count of each image index.
|
||||
* For example, a Hash {0 => 5, 2 => 10} means the images[0] has 5 key points matched, images[2] has 10 key points matched,
|
||||
* and all of other images in the images array have no key point matched.
|
||||
* Hence images[2] is the best match in general.
|
||||
*
|
||||
* <i>images</i> is an array of CvMat objects.
|
||||
* <i>detector_type</i> is a string, default is "SURF", options: "SURF", "FAST", "SIFT", "STAR"
|
||||
* <i>descriptor_type</i> is a string, default is "SURF", options: "SURF", "SIFT", "BRIEF"
|
||||
* <i>matcher_type</i> is a string, default is "FlannBased", options: "FlannBased", "BruteForce"
|
||||
*/
|
||||
VALUE
|
||||
rb_match_descriptors(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE images, detector_type, descriptor_type, matcher_type;
|
||||
rb_scan_args(argc, argv, "13", &images, &detector_type, &descriptor_type, &matcher_type);
|
||||
|
||||
if (RARRAY_LEN(images) == 0) {
|
||||
return rb_hash_new();
|
||||
}
|
||||
if (NIL_P(detector_type)) {
|
||||
detector_type = rb_str_new2("SURF");
|
||||
}
|
||||
if (NIL_P(descriptor_type)) {
|
||||
descriptor_type = rb_str_new2("SURF");
|
||||
}
|
||||
if (NIL_P(matcher_type)) {
|
||||
matcher_type = rb_str_new2("FlannBased");
|
||||
}
|
||||
|
||||
cv::Mat queryImage = CVMAT(self);
|
||||
std::vector<cv::Mat> trainImages;
|
||||
for(int i=0; i < RARRAY_LEN(images); i++) {
|
||||
trainImages.push_back(CVMAT_WITH_CHECK(RARRAY_PTR(images)[i]));
|
||||
}
|
||||
|
||||
cv::Ptr<cv::FeatureDetector> featureDetector = cv::FeatureDetector::create(RSTRING_PTR(detector_type));
|
||||
if (featureDetector.empty()) {
|
||||
rb_raise(rb_eArgError, "Could not create feature detector by given detector type: %s", RSTRING_PTR(detector_type));
|
||||
}
|
||||
cv::Ptr<cv::DescriptorExtractor> descriptorExtractor = cv::DescriptorExtractor::create(RSTRING_PTR(descriptor_type));
|
||||
if (descriptorExtractor.empty()) {
|
||||
rb_raise(rb_eArgError, "Could not create descriptor extractor by given descriptor type: %s", RSTRING_PTR(descriptor_type));
|
||||
}
|
||||
cv::Ptr<cv::DescriptorMatcher> descriptorMatcher;
|
||||
try {
|
||||
descriptorMatcher = cv::DescriptorMatcher::create(RSTRING_PTR(matcher_type));
|
||||
}
|
||||
catch(cv::Exception& e) {
|
||||
rb_raise(rb_eArgError, "Could not create descriptor matcher by given matcher type: %s", RSTRING_PTR(matcher_type));
|
||||
}
|
||||
|
||||
std::vector<cv::KeyPoint> queryKeypoints;
|
||||
std::vector<std::vector<cv::KeyPoint> > trainKeypoints;
|
||||
featureDetector->detect(queryImage, queryKeypoints);
|
||||
featureDetector->detect(trainImages, trainKeypoints);
|
||||
|
||||
cv::Mat queryDescriptors;
|
||||
std::vector<cv::Mat> trainDescriptors;
|
||||
descriptorExtractor->compute(queryImage, queryKeypoints, queryDescriptors);
|
||||
descriptorExtractor->compute(trainImages, trainKeypoints, trainDescriptors);
|
||||
|
||||
std::vector<cv::DMatch> matches;
|
||||
descriptorMatcher->add(trainDescriptors);
|
||||
descriptorMatcher->train();
|
||||
descriptorMatcher->match(queryDescriptors, matches);
|
||||
|
||||
VALUE _matches = rb_hash_new();
|
||||
for (size_t i=0; i<matches.size(); i++) {
|
||||
VALUE match = INT2FIX(matches[i].imgIdx);
|
||||
VALUE count = rb_hash_aref(_matches, match);
|
||||
if (NIL_P(count)) {
|
||||
count = INT2FIX(1);
|
||||
} else {
|
||||
count = INT2FIX(FIX2INT(count) + 1);
|
||||
}
|
||||
rb_hash_aset(_matches, match, count);
|
||||
}
|
||||
return _matches;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* mean_shift(window, criteria) -> comp
|
||||
|
|
|
@ -220,6 +220,8 @@ VALUE rb_equalize_hist(VALUE self);
|
|||
/* Matching*/
|
||||
VALUE rb_match_template(int argc, VALUE *argv, VALUE self);
|
||||
VALUE rb_match_shapes(int argc, VALUE *argv, VALUE self);
|
||||
VALUE rb_match_descriptors(int argc, VALUE *argv, VALUE self);
|
||||
|
||||
/* Object Tracking */
|
||||
VALUE rb_mean_shift(VALUE self, VALUE window, VALUE criteria);
|
||||
VALUE rb_cam_shift(VALUE self, VALUE window, VALUE criteria);
|
||||
|
|
|
@ -22,6 +22,8 @@ VALUE rb_class();
|
|||
void define_ruby_class();
|
||||
|
||||
VALUE seqblock_class(void *ptr);
|
||||
void register_elem_class(CvSeq *seq, VALUE klass);
|
||||
void unregister_elem_class(void *ptr);
|
||||
|
||||
VALUE rb_allocate(VALUE klass);
|
||||
|
||||
|
|
57
test/test_cvmat_matching.rb
Executable file
57
test/test_cvmat_matching.rb
Executable file
|
@ -0,0 +1,57 @@
|
|||
#!/usr/bin/env ruby
|
||||
# -*- mode: ruby; coding: utf-8-unix -*-
|
||||
require 'test/unit'
|
||||
require 'opencv'
|
||||
require File.expand_path(File.dirname(__FILE__)) + '/helper'
|
||||
|
||||
include OpenCV
|
||||
|
||||
# Tests for matching functions of OpenCV::CvMat
|
||||
class TestCvMat_matching < OpenCVTestCase
|
||||
def setup
|
||||
@query = read_test_image('query.png')
|
||||
@images = ['1.png', '2.png', '3.png'].map{|f| read_test_image('train', f)}
|
||||
end
|
||||
|
||||
def data_dir
|
||||
File.join(File.dirname(__FILE__), '..', 'examples', 'matching_to_many_images')
|
||||
end
|
||||
|
||||
def read_test_image(*path)
|
||||
IplImage.load File.join(data_dir, *path), CV_LOAD_IMAGE_GRAYSCALE
|
||||
end
|
||||
|
||||
def test_match_descriptors
|
||||
matchs = @query.match_descriptors(@images)
|
||||
match_index, count = matchs.max_by {|image_index, count| count}
|
||||
assert_equal 2, match_index
|
||||
end
|
||||
|
||||
def test_match_descriptors_with_empty_image_array
|
||||
assert_equal({}, @query.match_descriptors([]))
|
||||
end
|
||||
|
||||
def test_match_descriptors_with_wrong_detector_type_argument
|
||||
assert_raise ArgumentError do
|
||||
@query.match_descriptors(@images, "Wrong")
|
||||
end
|
||||
end
|
||||
|
||||
def test_match_descriptors_with_wrong_descriptor_type_argument
|
||||
assert_raise ArgumentError do
|
||||
@query.match_descriptors(@images, "SURF", "wrong")
|
||||
end
|
||||
end
|
||||
|
||||
def test_match_descriptors_with_wrong_matcher_type_argument
|
||||
assert_raise ArgumentError do
|
||||
@query.match_descriptors(@images, "SURF", "SURF", "wrong")
|
||||
end
|
||||
end
|
||||
|
||||
def test_match_descriptors_with_invalid_image_array
|
||||
assert_raise TypeError do
|
||||
@query.match_descriptors([DUMMY_OBJ, DUMMY_OBJ])
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue