From 9196cb13aa8e3ab4b58139c75ce7017e44a2d969 Mon Sep 17 00:00:00 2001 From: Ryan Baumann Date: Tue, 19 Aug 2008 11:01:28 -0400 Subject: [PATCH] Initial commit, with some minor changes from orig (date, exec bit, line endings, /usr/bin/env) --- History.txt | 5 + License.txt | 30 + Manifest.txt | 115 + README.txt | 47 + Rakefile | 34 + examples/convexhull.rb | 41 + examples/face_detect.rb | 25 + examples/houghcircle.rb | 23 + examples/inpaint.png | 2 + examples/inpaint.rb | 43 + examples/paint.rb | 72 + examples/snake.rb | 43 + examples/stuff.jpg | 1 + ext/curve.cpp | 103 + ext/curve.h | 34 + ext/cvavgcomp.cpp | 67 + ext/cvavgcomp.h | 39 + ext/cvbox2d.cpp | 114 + ext/cvbox2d.h | 53 + ext/cvcapture.cpp | 276 ++ ext/cvcapture.h | 54 + ext/cvchain.cpp | 184 ++ ext/cvchain.h | 43 + ext/cvchaincode.cpp | 49 + ext/cvchaincode.h | 43 + ext/cvcircle32f.cpp | 90 + ext/cvcircle32f.h | 53 + ext/cvcondensation.cpp | 230 ++ ext/cvcondensation.h | 49 + ext/cvconnectedcomp.cpp | 115 + ext/cvconnectedcomp.h | 46 + ext/cvcontour.cpp | 219 ++ ext/cvcontour.h | 47 + ext/cvcontourtree.cpp | 86 + ext/cvcontourtree.h | 41 + ext/cvconvexitydefect.cpp | 103 + ext/cvconvexitydefect.h | 42 + ext/cverror.cpp | 140 + ext/cverror.h | 79 + ext/cvfont.cpp | 173 ++ ext/cvfont.h | 56 + ext/cvhaarclassifiercascade.cpp | 159 + ext/cvhaarclassifiercascade.h | 41 + ext/cvhistogram.cpp | 200 ++ ext/cvhistogram.h | 51 + ext/cvindex.cpp | 73 + ext/cvindex.h | 40 + ext/cvline.cpp | 106 + ext/cvline.h | 52 + ext/cvmat.cpp | 4809 ++++++++++++++++++++++++++++++ ext/cvmat.h | 286 ++ ext/cvmatnd.cpp | 44 + ext/cvmatnd.h | 28 + ext/cvmemstorage.cpp | 64 + ext/cvmemstorage.h | 53 + ext/cvmoments.cpp | 204 ++ ext/cvmoments.h | 48 + ext/cvpoint.cpp | 229 ++ ext/cvpoint.h | 59 + ext/cvpoint2d32f.cpp | 213 ++ ext/cvpoint2d32f.h | 61 + ext/cvpoint3d32f.cpp | 245 ++ ext/cvpoint3d32f.h | 64 + ext/cvrect.cpp | 340 +++ ext/cvrect.h | 79 + ext/cvscalar.cpp | 227 ++ ext/cvscalar.h | 63 + ext/cvseq.cpp | 583 ++++ ext/cvseq.h | 71 + ext/cvset.cpp | 63 + ext/cvset.h | 39 + ext/cvsize.cpp | 223 ++ ext/cvsize.h | 63 + ext/cvsize2d32f.cpp | 180 ++ ext/cvsize2d32f.h | 59 + ext/cvslice.cpp | 82 + ext/cvslice.h | 53 + ext/cvsparsemat.cpp | 44 + ext/cvsparsemat.h | 28 + ext/cvtermcriteria.cpp | 183 ++ ext/cvtermcriteria.h | 71 + ext/cvtwopoints.cpp | 98 + ext/cvtwopoints.h | 50 + ext/cvvector.cpp | 206 ++ ext/cvvector.h | 54 + ext/cvvideowriter.cpp | 116 + ext/cvvideowriter.h | 41 + ext/extconf.rb | 61 + ext/gui.cpp | 65 + ext/gui.h | 33 + ext/iplconvkernel.cpp | 177 ++ ext/iplconvkernel.h | 52 + ext/iplimage.cpp | 238 ++ ext/iplimage.h | 54 + ext/mouseevent.cpp | 184 ++ ext/mouseevent.h | 59 + ext/opencv.cpp | 481 +++ ext/opencv.h | 356 +++ ext/point3dset.cpp | 41 + ext/point3dset.h | 31 + ext/pointset.cpp | 238 ++ ext/pointset.h | 69 + ext/trackbar.cpp | 122 + ext/trackbar.h | 65 + ext/window.cpp | 368 +++ ext/window.h | 56 + images/CvMat_sobel.png | 2 + images/CvMat_sub_rect.png | 2 + images/CvSeq_relationmap.png | 2 + images/face_detect_from_lena.jpg | 1 + lib/opencv.rb | 3 + lib/version.rb | 3 + metadata | 191 ++ setup/setup.cygwin.rb | 120 + setup/setup.mingw.rb | 99 + setup/setup.mswin32.rb | 103 + test/test_opencv.rb | 6 + 117 files changed, 16536 insertions(+) create mode 100644 History.txt create mode 100644 License.txt create mode 100644 Manifest.txt create mode 100644 README.txt create mode 100644 Rakefile create mode 100755 examples/convexhull.rb create mode 100755 examples/face_detect.rb create mode 100755 examples/houghcircle.rb create mode 100644 examples/inpaint.png create mode 100755 examples/inpaint.rb create mode 100755 examples/paint.rb create mode 100755 examples/snake.rb create mode 100644 examples/stuff.jpg create mode 100644 ext/curve.cpp create mode 100644 ext/curve.h create mode 100644 ext/cvavgcomp.cpp create mode 100644 ext/cvavgcomp.h create mode 100644 ext/cvbox2d.cpp create mode 100644 ext/cvbox2d.h create mode 100644 ext/cvcapture.cpp create mode 100644 ext/cvcapture.h create mode 100644 ext/cvchain.cpp create mode 100644 ext/cvchain.h create mode 100644 ext/cvchaincode.cpp create mode 100644 ext/cvchaincode.h create mode 100644 ext/cvcircle32f.cpp create mode 100644 ext/cvcircle32f.h create mode 100644 ext/cvcondensation.cpp create mode 100644 ext/cvcondensation.h create mode 100644 ext/cvconnectedcomp.cpp create mode 100644 ext/cvconnectedcomp.h create mode 100644 ext/cvcontour.cpp create mode 100644 ext/cvcontour.h create mode 100644 ext/cvcontourtree.cpp create mode 100644 ext/cvcontourtree.h create mode 100644 ext/cvconvexitydefect.cpp create mode 100644 ext/cvconvexitydefect.h create mode 100644 ext/cverror.cpp create mode 100644 ext/cverror.h create mode 100644 ext/cvfont.cpp create mode 100644 ext/cvfont.h create mode 100644 ext/cvhaarclassifiercascade.cpp create mode 100644 ext/cvhaarclassifiercascade.h create mode 100644 ext/cvhistogram.cpp create mode 100644 ext/cvhistogram.h create mode 100644 ext/cvindex.cpp create mode 100644 ext/cvindex.h create mode 100644 ext/cvline.cpp create mode 100644 ext/cvline.h create mode 100644 ext/cvmat.cpp create mode 100644 ext/cvmat.h create mode 100644 ext/cvmatnd.cpp create mode 100644 ext/cvmatnd.h create mode 100644 ext/cvmemstorage.cpp create mode 100644 ext/cvmemstorage.h create mode 100644 ext/cvmoments.cpp create mode 100644 ext/cvmoments.h create mode 100644 ext/cvpoint.cpp create mode 100644 ext/cvpoint.h create mode 100644 ext/cvpoint2d32f.cpp create mode 100644 ext/cvpoint2d32f.h create mode 100644 ext/cvpoint3d32f.cpp create mode 100644 ext/cvpoint3d32f.h create mode 100644 ext/cvrect.cpp create mode 100644 ext/cvrect.h create mode 100644 ext/cvscalar.cpp create mode 100644 ext/cvscalar.h create mode 100644 ext/cvseq.cpp create mode 100644 ext/cvseq.h create mode 100644 ext/cvset.cpp create mode 100644 ext/cvset.h create mode 100644 ext/cvsize.cpp create mode 100644 ext/cvsize.h create mode 100644 ext/cvsize2d32f.cpp create mode 100644 ext/cvsize2d32f.h create mode 100644 ext/cvslice.cpp create mode 100644 ext/cvslice.h create mode 100644 ext/cvsparsemat.cpp create mode 100644 ext/cvsparsemat.h create mode 100644 ext/cvtermcriteria.cpp create mode 100644 ext/cvtermcriteria.h create mode 100644 ext/cvtwopoints.cpp create mode 100644 ext/cvtwopoints.h create mode 100644 ext/cvvector.cpp create mode 100644 ext/cvvector.h create mode 100644 ext/cvvideowriter.cpp create mode 100644 ext/cvvideowriter.h create mode 100755 ext/extconf.rb create mode 100644 ext/gui.cpp create mode 100644 ext/gui.h create mode 100644 ext/iplconvkernel.cpp create mode 100644 ext/iplconvkernel.h create mode 100644 ext/iplimage.cpp create mode 100644 ext/iplimage.h create mode 100644 ext/mouseevent.cpp create mode 100644 ext/mouseevent.h create mode 100644 ext/opencv.cpp create mode 100644 ext/opencv.h create mode 100644 ext/point3dset.cpp create mode 100644 ext/point3dset.h create mode 100644 ext/pointset.cpp create mode 100644 ext/pointset.h create mode 100644 ext/trackbar.cpp create mode 100644 ext/trackbar.h create mode 100644 ext/window.cpp create mode 100644 ext/window.h create mode 100644 images/CvMat_sobel.png create mode 100644 images/CvMat_sub_rect.png create mode 100644 images/CvSeq_relationmap.png create mode 100644 images/face_detect_from_lena.jpg create mode 100755 lib/opencv.rb create mode 100755 lib/version.rb create mode 100644 metadata create mode 100755 setup/setup.cygwin.rb create mode 100755 setup/setup.mingw.rb create mode 100755 setup/setup.mswin32.rb create mode 100755 test/test_opencv.rb diff --git a/History.txt b/History.txt new file mode 100644 index 00000000..c301152d --- /dev/null +++ b/History.txt @@ -0,0 +1,5 @@ +=== 0.0.6 / 2008-06-27 + +* First gem release. + + * Some OpenCV function wrapped. diff --git a/License.txt b/License.txt new file mode 100644 index 00000000..9261a652 --- /dev/null +++ b/License.txt @@ -0,0 +1,30 @@ +The BSD Liscense + +Copyright (c) 2008, Masakazu Yonekura +All rights reserved. + +Redistribution and use of this software in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of Masakazu Yonekura. nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of Masakazu Yonekura. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. diff --git a/Manifest.txt b/Manifest.txt new file mode 100644 index 00000000..b7477d89 --- /dev/null +++ b/Manifest.txt @@ -0,0 +1,115 @@ +History.txt +Manifest.txt +README.txt +License.txt +Rakefile +examples/convexhull.rb +examples/face_detect.rb +examples/houghcircle.rb +examples/inpaint.png +examples/inpaint.rb +examples/paint.rb +examples/snake.rb +examples/stuff.jpg +ext/curve.cpp +ext/curve.h +ext/cvavgcomp.cpp +ext/cvavgcomp.h +ext/cvbox2d.cpp +ext/cvbox2d.h +ext/cvcapture.cpp +ext/cvcapture.h +ext/cvchain.cpp +ext/cvchain.h +ext/cvchaincode.cpp +ext/cvchaincode.h +ext/cvcircle32f.cpp +ext/cvcircle32f.h +ext/cvcondensation.cpp +ext/cvcondensation.h +ext/cvconnectedcomp.cpp +ext/cvconnectedcomp.h +ext/cvcontour.cpp +ext/cvcontour.h +ext/cvcontourtree.cpp +ext/cvcontourtree.h +ext/cvconvexitydefect.cpp +ext/cvconvexitydefect.h +ext/cverror.cpp +ext/cverror.h +ext/cvfont.cpp +ext/cvfont.h +ext/cvhaarclassifiercascade.cpp +ext/cvhaarclassifiercascade.h +ext/cvhistogram.cpp +ext/cvhistogram.h +ext/cvindex.cpp +ext/cvindex.h +ext/cvline.cpp +ext/cvline.h +ext/cvmat.cpp +ext/cvmat.h +ext/cvmatnd.cpp +ext/cvmatnd.h +ext/cvmemstorage.cpp +ext/cvmemstorage.h +ext/cvmoments.cpp +ext/cvmoments.h +ext/cvpoint.cpp +ext/cvpoint.h +ext/cvpoint2d32f.cpp +ext/cvpoint2d32f.h +ext/cvpoint3d32f.cpp +ext/cvpoint3d32f.h +ext/cvrect.cpp +ext/cvrect.h +ext/cvscalar.cpp +ext/cvscalar.h +ext/cvseq.cpp +ext/cvseq.h +ext/cvset.cpp +ext/cvset.h +ext/cvsize.cpp +ext/cvsize.h +ext/cvsize2d32f.cpp +ext/cvsize2d32f.h +ext/cvslice.cpp +ext/cvslice.h +ext/cvsparsemat.cpp +ext/cvsparsemat.h +ext/cvtermcriteria.cpp +ext/cvtermcriteria.h +ext/cvtwopoints.cpp +ext/cvtwopoints.h +ext/cvvector.cpp +ext/cvvector.h +ext/cvvideowriter.cpp +ext/cvvideowriter.h +ext/extconf.rb +ext/gui.cpp +ext/gui.h +ext/iplconvkernel.cpp +ext/iplconvkernel.h +ext/iplimage.cpp +ext/iplimage.h +ext/mouseevent.cpp +ext/mouseevent.h +ext/opencv.cpp +ext/opencv.h +ext/point3dset.cpp +ext/point3dset.h +ext/pointset.cpp +ext/pointset.h +ext/trackbar.cpp +ext/trackbar.h +ext/window.cpp +ext/window.h +images/CvMat_sobel.png +images/CvMat_sub_rect.png +images/CvSeq_relationmap.png +images/face_detect_from_lena.jpg +lib/opencv.rb +lib/version.rb +setup/setup.cygwin.rb +setup/setup.mingw.rb +setup/setup.mswin32.rb diff --git a/README.txt b/README.txt new file mode 100644 index 00000000..8e994cbd --- /dev/null +++ b/README.txt @@ -0,0 +1,47 @@ += opencv + +OpenCV Sourceforge Project +http://sourceforge.net/projects/opencvlibrary/ + +Ruby/OpenCV Author's Web Page +http://blueruby.mydns.jp/opencv + +== DESCRIPTION: + +OpenCV Ruby Wrapper + +== FEATURES/PROBLEMS: + +* First release rubygems, Some OpenCV function wrapped. + +== SYNOPSIS: + +# Show image via GUI Window. + +require "rubygems" +gem "opencv" +require "opencv" + +image = OpenCV::IplImage.load("sample.jpg") +window = OpenCV::GUI::Window.new("preview") +window.show(image) +OpenCV::GUI::wait_key + +# other sample code, see examples/*.rb + +== REQUIREMENTS: + +* OpenCV 1.0 or later. + http://sourceforge.net/projects/opencvlibrary/ +* ffcall (optional) + http://www.haible.de/bruno/packages-ffcall.html + +== INSTALL: + +gem install opencv + +== LICENSE: + +The BSD Liscense + +see LICENSE.txt diff --git a/Rakefile b/Rakefile new file mode 100644 index 00000000..f90e03a1 --- /dev/null +++ b/Rakefile @@ -0,0 +1,34 @@ +# -*- ruby -*- + +require 'rubygems' +require 'hoe' +require './lib/version' + +Hoe.new('opencv', OpenCV::VERSION) do |p| + p.author = ['Masakazu Yonekura'] + p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n") + p.description = < %w{ext/extconf.rb} + } + p.summary = 'OpenCV wrapper for Ruby.' + # p.test_globs = 'spec/**/*_spec.rb' + p.clean_globs |= ['*.o'] + + p.url = 'http://blueruby.mydns.jp/opencv' + + p.extra_deps << ['hoe'] +end + +# vim: syntax=Ruby diff --git a/examples/convexhull.rb b/examples/convexhull.rb new file mode 100755 index 00000000..23d9afa9 --- /dev/null +++ b/examples/convexhull.rb @@ -0,0 +1,41 @@ +#!/usr/bin/env ruby +# convexhull.rb +gem "opencv" +require "opencv" +require "pp" +include OpenCV + +window = GUI::Window.new("convexhull") +pp CvCapture::INTERFACE +capture = CvCapture::open + +accuracy = 0.1 +t = window.set_trackbar("accuracy", 100, 1){|v| + accuracy = 0.1 * v +} + +while true + key = GUI::wait_key(1) + image = capture.query + gray = image.BGR2GRAY + bin = gray.threshold_binary(0x44, 0xFF) + contours = bin.find_contours + while contours + image.poly_line! contours.approx(:accuracy => accuracy), :color => CvScalar::Red + contours.convexity_defects.each{|cd| + image.circle! cd.start, 1, :color => CvScalar::Blue + image.circle! cd.end, 1, :color => CvScalar::Blue + image.circle! cd.depth_point, 1, :color => CvScalar::Blue + } + + contours = contours.h_next + end + #pts = gray.good_features_to_track(0.01, 10) + #puts pts.length + window.show image + next unless key + case key.chr + when "\e" + exit + end +end diff --git a/examples/face_detect.rb b/examples/face_detect.rb new file mode 100755 index 00000000..defe1dd6 --- /dev/null +++ b/examples/face_detect.rb @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +# face_detect.rb +require "rubygems" +gem "opencv" +require "opencv" + +include OpenCV + +window = GUI::Window.new("face detect") +capture = CvCapture.open +detector = CvHaarClassifierCascade::load("C:/Program Files/OpenCV/data/haarcascades/haarcascade_frontalface_alt.xml") + +while true + key = GUI::wait_key(1) + image = capture.query + detector.detect_objects(image){|i| + image.rectangle! i.top_left, i.bottom_right, :color => CvColor::Red + } + window.show image + next unless key + case key.chr + when "\e" + exit + end +end diff --git a/examples/houghcircle.rb b/examples/houghcircle.rb new file mode 100755 index 00000000..c228a4e0 --- /dev/null +++ b/examples/houghcircle.rb @@ -0,0 +1,23 @@ +#!/usr/bin/env ruby +# houghcircle.rb +require "rubygems" +gem "opencv" +require "opencv" +include OpenCV + +original_window = GUI::Window.new "original" +hough_window = GUI::Window.new "hough circles" + +image = IplImage::load "stuff.jpg" +gray = image.BGR2GRAY + +result = image.clone +original_window.show image +detect = gray.hough_circles_gradient(2.0, 10, 200, 50) +puts detect.size +detect.each{|circle| + puts "#{circle.center.x},#{circle.center.y} - #{circle.radius}" + result.circle! circle.center, circle.radius, :color => CvColor::Red, :thickness => 3 +} +hough_window.show result +GUI::wait_key diff --git a/examples/inpaint.png b/examples/inpaint.png new file mode 100644 index 00000000..91d64e97 --- /dev/null +++ b/examples/inpaint.png @@ -0,0 +1,2 @@ +‰PNG + diff --git a/examples/inpaint.rb b/examples/inpaint.rb new file mode 100755 index 00000000..d0979ac4 --- /dev/null +++ b/examples/inpaint.rb @@ -0,0 +1,43 @@ +#!/usr/bin/env ruby +# inpaint.rb +require "rubygems" +gem "opencv" +require "opencv" + +include OpenCV + +owindow = GUI::Window.new "original" +mwindow = GUI::Window.new "mask" +iwindow = GUI::Window.new "inpaint" + +image = IplImage::load "inpaint.png" +b, g, r = image.split +original_mask = r.threshold_binary_inverse(0x00, 0xFF) & b.threshold_binary_inverse(0x00, 0xFF) +mask = original_mask.copy + +num_dilate = 3 +radius = 5 +dilate_bar = mwindow.set_trackbar("dilate", 10, num_dilate){|v| + num_dilate = v + mask = original_mask.dilate(nil, num_dilate) + mwindow.show mask +} + +radius_bar = mwindow.set_trackbar("radius", 30, radius){|v| + radius = v +} + +owindow.show image +mwindow.show mask + +while key = GUI::wait_key + case key.chr + when "\e" # esc + exit + when "n" + iwindow.show image.inpaint_ns(mask, radius) + when "t" + iwindow.show image.inpaint_telea(mask, radius) + end +end + diff --git a/examples/paint.rb b/examples/paint.rb new file mode 100755 index 00000000..82602051 --- /dev/null +++ b/examples/paint.rb @@ -0,0 +1,72 @@ +#!/usr/bin/env ruby +# paint.rb +require "rubygems" +gem "opencv" +require "opencv" + +include OpenCV + +window = GUI::Window.new("free canvas") +canvas = CvMat.new(500, 500, 0, 3).fill!(0xFF) # create white canvas +window.show canvas + +colors = CvColor::constants.collect{|i| i.to_s } + +usage =< CvColor::Black, + :tickness => 1 +} + +window.on_mouse{|m| + case m.event + when :move + if m.left_button? + canvas.line!(point, m, opt) if point + point = m + end + when :left_button_down + canvas.line!(m, m, opt) + point = m + when :left_button_up + point = nil + when :right_button_down + mask = canvas.flood_fill!(m, opt[:color]) + end + window.show canvas +} + +color_name = '' +while key = GUI.wait_key + next if key < 0 + case key.chr + when "\e" # [esc] - exit + exit + when '1'..'9' + puts "change thickness to #{key.chr.to_i}." + opt[:thickness] = key.chr.to_i + else + color_name << key.chr + choice = colors.find_all{|i| i =~ /\A#{color_name}/i} + if choice.size == 1 + color,= choice + puts "change color to #{color}." + opt[:color] = CvColor::const_get(color) + end + color_name = '' if choice.length < 2 + end +end + diff --git a/examples/snake.rb b/examples/snake.rb new file mode 100755 index 00000000..4c357768 --- /dev/null +++ b/examples/snake.rb @@ -0,0 +1,43 @@ +#!/usr/bin/env ruby +# snake.rb +require "rubygems" +gem "opencv" +require "opencv" +include OpenCV + +puts < CvColor::White, :thickness => -1) +display = image.GRAY2BGR + +window.show display + +points = [] + +window.on_mouse{|mouse| + case mouse.event + when :left_button_down + display[mouse.x, mouse.y] = CvColor::Red + puts "set point (#{mouse.x},#{mouse.y})" + points << CvPoint.new(mouse.x, mouse.y) + window.show display + when :right_button_down + if points.length < 3 + puts "please set more point!" + next + end + points = image.snake_image(points, 1.0, 0.5, 1.5, CvSize.new(3, 3), 100) + display = image.GRAY2BGR + display.poly_line! points, :color => CvColor::Red, :is_closed => true + window.show display + end +} + +GUI::wait_key + diff --git a/examples/stuff.jpg b/examples/stuff.jpg new file mode 100644 index 00000000..6255ad5e --- /dev/null +++ b/examples/stuff.jpg @@ -0,0 +1 @@ +ÿØÿà \ No newline at end of file diff --git a/ext/curve.cpp b/ext/curve.cpp new file mode 100644 index 00000000..2bf2d870 --- /dev/null +++ b/ext/curve.cpp @@ -0,0 +1,103 @@ +/************************************************************ + + curve.cpp - + + $Author: lsxi $ + + Copyright (C) 2005 Masakazu Yonekura + +************************************************************/ +#include"curve.h" +/* + * Document-class: OpenCV::Curve + * + * Curve sequence. + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CURVE + +VALUE module; + +VALUE +rb_module() +{ + return module; +} + +void +define_ruby_module() +{ + if(module) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + module = rb_define_module_under(opencv, "Curve"); + rb_define_method(module, "close?", RUBY_METHOD_FUNC(rb_closed_q), 0); + rb_define_method(module, "convex?", RUBY_METHOD_FUNC(rb_convex_q), 0); + rb_define_method(module, "hole?", RUBY_METHOD_FUNC(rb_hole_q), 0); + rb_define_method(module, "simple?", RUBY_METHOD_FUNC(rb_simple_q), 0); + rb_define_method(module, "arc_length", RUBY_METHOD_FUNC(rb_arc_length), -1); +} + +/* + * If curve is closed, return true. Otherwise return false. + */ +VALUE +rb_closed_q(VALUE self) +{ + return CV_IS_SEQ_CLOSED(CVSEQ(self)) ? Qtrue : Qfalse; +} + +/* + * If curve is convex, return true. Otherwise return false. + */ +VALUE +rb_convex_q(VALUE self) +{ + return CV_IS_SEQ_CONVEX(CVSEQ(self)) ? Qtrue : Qfalse; +} + +/* + * If curve is hole(inner contour), return true. Otherwise return false. + */ +VALUE +rb_hole_q(VALUE self) +{ + return CV_IS_SEQ_HOLE(CVSEQ(self)) ? Qtrue : Qfalse; +} + +/* + * no idia. + */ +VALUE +rb_simple_q(VALUE self) +{ + return CV_IS_SEQ_SIMPLE(CVSEQ(self)) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * arc_length([slice = nil][,is_closed = nil]) -> float + * + * Calculates contour perimeter or curve length. + * slice is starting and ending points of the curve. + * is_closed is indicates whether the curve is closed or not. There are 3 cases: + * * is_closed = true - the curve is assumed to be unclosed. + * * is_closed = false - the curve is assumed to be closed. + * * is_closed = nil (default) use self#close? + */ +VALUE +rb_arc_length(int argc, VALUE *argv, VALUE self) +{ + VALUE slice, is_closed; + rb_scan_args(argc, argv, "02", &slice, &is_closed); + return rb_float_new(cvArcLength(CVARR(self), NIL_P(slice) ? CV_WHOLE_SEQ : VALUE_TO_CVSLICE(slice), TRUE_OR_FALSE(is_closed, -1))); +} + +__NAMESPACE_END_CURVE +__NAMESPACE_END_OPENCV + diff --git a/ext/curve.h b/ext/curve.h new file mode 100644 index 00000000..ededafa6 --- /dev/null +++ b/ext/curve.h @@ -0,0 +1,34 @@ +/************************************************************ + + curve.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVSEQ_CURVE_H +#define RUBY_OPENCV_CVSEQ_CURVE_H + +#include"opencv.h" + +#define __NAMESPACE_BEGIN_CURVE namespace mCurve{ +#define __NAMESPACE_END_CURVE } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CURVE + +VALUE rb_module(); + +void define_ruby_module(); + +VALUE rb_closed_q(VALUE self); +VALUE rb_convex_q(VALUE self); +VALUE rb_hole_q(VALUE self); +VALUE rb_simple_q(VALUE self); +VALUE rb_arc_length(int argc, VALUE *argv, VALUE self); + +__NAMESPACE_END_CURVE +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVSEQ_CURVE_H diff --git a/ext/cvavgcomp.cpp b/ext/cvavgcomp.cpp new file mode 100644 index 00000000..4ce69ed3 --- /dev/null +++ b/ext/cvavgcomp.cpp @@ -0,0 +1,67 @@ +/************************************************************ + + cvavgcomp.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include "cvavgcomp.h" +/* + * Document-class: OpenCV::CvAvgComp + * + * CvRect with parameter "neighbors". + * CvHaarClassifierCascade#detect_object. + * + * typedef struct CvAvgComp{ + * CvRect rect; + * int neighbors; + * } + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_AVGCOMP + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * cvrect = rb_define_class_under(opencv, "CvRect", rb_cObject); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(), cvrect = cCvRect::rb_class(); + rb_klass = rb_define_class_under(opencv, "CvAvgComp", cvrect); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_method(rb_klass, "neighbors", RUBY_METHOD_FUNC(rb_neighbors), 0); +} + +VALUE +rb_allocate(VALUE klass) +{ + CvAvgComp *ptr; + return Data_Make_Struct(klass, CvAvgComp, 0, -1, ptr); +} + +/* + * Return neighbors. + */ +VALUE +rb_neighbors(VALUE self) +{ + return INT2FIX(CVAVGCOMP(self)->neighbors); +} + +__NAMESPACE_END_AVGCOMP +__NAMESPACE_END_OPENCV diff --git a/ext/cvavgcomp.h b/ext/cvavgcomp.h new file mode 100644 index 00000000..5eb6f828 --- /dev/null +++ b/ext/cvavgcomp.h @@ -0,0 +1,39 @@ +/********************************************************************** + + cvavgcomp.h + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +**********************************************************************/ +#ifndef RUBY_OPENCV_AVGCOMP_H +#define RUBY_OPENCV_AVGCOMP_H + +#define __NAMESPACE_BEGIN_AVGCOMP namespace cCvAvgComp{ +#define __NAMESPACE_END_AVGCOMP } + +#include + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_AVGCOMP + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_allocate(VALUE klass); +VALUE rb_neighbors(VALUE self); + +__NAMESPACE_END_AVGCOMP + +inline CvAvgComp *CVAVGCOMP(VALUE object){ + CvAvgComp *ptr; + Data_Get_Struct(object, CvAvgComp, ptr); + return ptr; +} + +__NAMESPACE_END_OPENCV + + +#endif // RUBY_OPENCV_AVGCOMP_H diff --git a/ext/cvbox2d.cpp b/ext/cvbox2d.cpp new file mode 100644 index 00000000..1b07b9a5 --- /dev/null +++ b/ext/cvbox2d.cpp @@ -0,0 +1,114 @@ +/************************************************************ + + cvbox2d.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include "cvbox2d.h" +/* + * Document-class: OpenCV::CvBox2D + * + * C structure is here. + * typdef struct CvBox2D{ + * CvPoint2D32f center; // center of the box. + * CvSize2D32f size; // box width and length + * float angle; // angle between the horizonal axis and the first side (i.e length) in radians + * }CvBox2D; + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVBOX2D + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if(rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + rb_klass = rb_define_class_under(opencv, "CvBox2D", rb_cObject); + rb_define_method(rb_klass, "center", RUBY_METHOD_FUNC(rb_center), 0); + rb_define_method(rb_klass, "size", RUBY_METHOD_FUNC(rb_size), 0); + rb_define_method(rb_klass, "angle", RUBY_METHOD_FUNC(rb_angle), 0); + rb_define_method(rb_klass, "points", RUBY_METHOD_FUNC(rb_points), 0); +} + +VALUE +rb_allocate(VALUE klass) +{ + CvBox2D *ptr; + return Data_Make_Struct(klass, CvBox2D, 0, -1, ptr); +} + +/* + * Return center point of box as CvPoint2D32f. + */ +VALUE +rb_center(VALUE self) +{ + return REFER_OBJECT(cCvPoint2D32f::rb_class(), &CVBOX2D(self)->center, self); +} + +/* + * Return size of box as CvSize2D32f. + */ +VALUE +rb_size(VALUE self) +{ + return REFER_OBJECT(cCvSize2D32f::rb_class(), &CVBOX2D(self)->size, self); +} + +/* + * Return angle of box as Float. + */ +VALUE +rb_angle(VALUE self) +{ + return rb_float_new(CVBOX2D(self)->angle); +} + +/* + * Find box vertices. Return Array contain 4 CvPoint2D32f. + */ +VALUE +rb_points(VALUE self) +{ + const int n = 4; + CvPoint2D32f p[n]; + cvBoxPoints(*CVBOX2D(self), p); + VALUE points = rb_ary_new2(n); + for(int i = 0; i < n; i++) + rb_ary_store(points, i, cCvPoint2D32f::new_object(p[i])); + return points; +} + +VALUE +new_object() +{ + return rb_allocate(cCvBox2D::rb_class()); +} + +VALUE +new_object(CvBox2D box) +{ + VALUE object = rb_allocate(rb_klass); + *CVBOX2D(object) = box; + return object; +} + +__NAMESPACE_END_CVBOX2D +__NAMESPACE_END_OPENCV diff --git a/ext/cvbox2d.h b/ext/cvbox2d.h new file mode 100644 index 00000000..b069ca74 --- /dev/null +++ b/ext/cvbox2d.h @@ -0,0 +1,53 @@ +/************************************************************ + + cvbox2d.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVBOX2D_H +#define RUBY_OPENCV_CVBOX2D_H + +#include"opencv.h" + +#define __NAMESPACE_BEGIN_CVBOX2D namespace cCvBox2D{ +#define __NAMESPACE_END_CVBOX2D } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVBOX2D + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_allocate(VALUE klass); + +VALUE rb_center(VALUE self); +VALUE rb_size(VALUE self); +VALUE rb_angle(VALUE self); +VALUE rb_points(VALUE self); + +VALUE new_object(); +VALUE new_object(CvBox2D box); + +__NAMESPACE_END_CVBOX2D + +inline CvBox2D *CVBOX2D(VALUE object){ + CvBox2D *ptr; + Data_Get_Struct(object, CvBox2D, ptr); + return ptr; +} + +inline CvBox2D VALUE_TO_CVBOX2D(VALUE object){ + if(rb_obj_is_kind_of(object, cCvBox2D::rb_class())) { + return *CVBOX2D(object); + }else{ + rb_raise(rb_eTypeError, "require %s or compatible object.", rb_class2name(cCvBox2D::rb_class())); + } +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVBOX2D_H diff --git a/ext/cvcapture.cpp b/ext/cvcapture.cpp new file mode 100644 index 00000000..840800bf --- /dev/null +++ b/ext/cvcapture.cpp @@ -0,0 +1,276 @@ +/************************************************************ + + cvcapture.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include"cvcapture.h" +/* + * Document-class: OpenCV::CvCapture + * + * Capture image from video stream. + * + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVCAPTURE + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + + rb_klass = rb_define_class_under(opencv, "CvCapture", rb_cData); + + VALUE video_interface = rb_hash_new(); + /* {:any, :mil, :vfw, :v4l, :v4l2, :fireware, :ieee1394, :dc1394, :cmu1394, :stereo, :tyzx, :tyzx_left, :tyzx_right, :tyzx_color, :tyzx_z, :qt, :qtuicktime}: video source */ + rb_define_const(rb_klass, "INTERFACE", video_interface); + rb_hash_aset(video_interface, ID2SYM(rb_intern("any")), INT2FIX(CV_CAP_ANY)); + rb_hash_aset(video_interface, ID2SYM(rb_intern("mil")), INT2FIX(CV_CAP_MIL)); + rb_hash_aset(video_interface, ID2SYM(rb_intern("vfw")), INT2FIX(CV_CAP_VFW)); + rb_hash_aset(video_interface, ID2SYM(rb_intern("v4l")), INT2FIX(CV_CAP_V4L)); + rb_hash_aset(video_interface, ID2SYM(rb_intern("v4l2")), INT2FIX(CV_CAP_V4L2)); + rb_hash_aset(video_interface, ID2SYM(rb_intern("fireware")), INT2FIX(CV_CAP_FIREWARE)); + rb_hash_aset(video_interface, ID2SYM(rb_intern("ieee1394")), INT2FIX(CV_CAP_IEEE1394)); + rb_hash_aset(video_interface, ID2SYM(rb_intern("dc1394")), INT2FIX(CV_CAP_DC1394)); + rb_hash_aset(video_interface, ID2SYM(rb_intern("cmu1394")), INT2FIX(CV_CAP_CMU1394)); + rb_hash_aset(video_interface, ID2SYM(rb_intern("stereo")), INT2FIX(CV_CAP_STEREO)); + rb_hash_aset(video_interface, ID2SYM(rb_intern("tyzx")), INT2FIX(CV_CAP_TYZX)); + rb_hash_aset(video_interface, ID2SYM(rb_intern("tyzx_left")), INT2FIX(CV_TYZX_LEFT)); + rb_hash_aset(video_interface, ID2SYM(rb_intern("tyzx_right")), INT2FIX(CV_TYZX_RIGHT)); + rb_hash_aset(video_interface, ID2SYM(rb_intern("tyzx_color")), INT2FIX(CV_TYZX_COLOR)); + rb_hash_aset(video_interface, ID2SYM(rb_intern("tyzx_z")), INT2FIX(CV_TYZX_Z)); + rb_hash_aset(video_interface, ID2SYM(rb_intern("qt")), INT2FIX(CV_CAP_QT)); + rb_hash_aset(video_interface, ID2SYM(rb_intern("quicktime")), INT2FIX(CV_CAP_QT)); + + rb_define_singleton_method(rb_klass, "open", RUBY_METHOD_FUNC(rb_open), -1); + + rb_define_method(rb_klass, "grab", RUBY_METHOD_FUNC(rb_grab), 0); + rb_define_method(rb_klass, "retrieve", RUBY_METHOD_FUNC(rb_retrieve), 0); + rb_define_method(rb_klass, "query", RUBY_METHOD_FUNC(rb_query), 0); + rb_define_method(rb_klass, "millisecond", RUBY_METHOD_FUNC(rb_millisecond), 0); + rb_define_method(rb_klass, "frames", RUBY_METHOD_FUNC(rb_frames), 0); + rb_define_method(rb_klass, "size", RUBY_METHOD_FUNC(rb_size), 0); + rb_define_method(rb_klass, "width", RUBY_METHOD_FUNC(rb_width), 0); + rb_define_method(rb_klass, "height", RUBY_METHOD_FUNC(rb_height), 0); + rb_define_method(rb_klass, "fps", RUBY_METHOD_FUNC(rb_fps), 0); + rb_define_method(rb_klass, "fourcc", RUBY_METHOD_FUNC(rb_fourcc), 0); + rb_define_method(rb_klass, "frame_count", RUBY_METHOD_FUNC(rb_frame_count), 0); +} + +void +free(void *ptr) +{ + if(ptr) + cvReleaseCapture((CvCapture**)&ptr); +} + +/* + * call-seq: + * CvCapture.open([dev = -1]) + * + * Reading video stream from the specified file or camera device. + * If dev is string (i.e "stream.avi"), reading video stream from file. + * If dev is number or symbol(include CvCapture::INTERFACE), + * reading video stream from camera. + * Currently two camera interfaces can be used on Windows: + * * Video for Windows(VFW) + * * Matrox Imaging Library(MIL) + * and two on Linux + * * V4L + * * FireWire(IEEE1394). + * If there is only one camera or it does not matter what camera to use nil may be passed. + */ +VALUE +rb_open(int argc, VALUE *argv, VALUE self) +{ + VALUE device, i; + rb_scan_args(argc, argv, "01", &device); + CvCapture *capture = 0; + switch (TYPE(device)) { + case T_STRING: + capture = cvCaptureFromFile(StringValueCStr(device)); + break; + case T_FIXNUM: + capture = cvCaptureFromCAM(FIX2INT(device)); + break; + case T_SYMBOL: + i = rb_hash_aref(rb_const_get(rb_class(), rb_intern("INTERFACE")), device); + if (NIL_P(i)) + rb_raise(rb_eArgError, "undefined interface."); + capture = cvCaptureFromCAM(NUM2INT(i)); + break; + case T_NIL: + capture = cvCaptureFromCAM(CV_CAP_ANY); + break; + } + if (!capture) + rb_raise(rb_eStandardError, "Invalid capture format."); + return Data_Wrap_Struct(rb_klass, 0, free, capture); +} + + +/* + * call-seq: + * grab -> true or false + * + * Grabbed frame is stored internally. To grab frame + * fast that is important for syncronization in case of reading from + * several cameras simultaneously. The grabbed frames are not exposed because + * they may be stored in compressed format (as defined by camera/driver). + * To retrieve the grabbed frame, retrieve should be used. + * + * If grabbed frame was success, return true. Otherwise return false. + */ +VALUE +rb_grab(VALUE self) +{ + return cvGrabFrame(CVCAPTURE(self)) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * retrieve -> CvMat or nil + * + * Gets the image grabbed with grab. + */ +VALUE +rb_retrieve(VALUE self) +{ + IplImage *frame = cvRetrieveFrame(CVCAPTURE(self)); + if(!frame) + return Qnil; + VALUE image = cIplImage::new_object(cvSize(frame->width, frame->height), CV_MAKETYPE(CV_8U, frame->nChannels)); + if (frame->origin == IPL_ORIGIN_TL) { + cvCopy(frame, CVARR(image)); + } else { + cvFlip(frame, CVARR(image)); + } + return image; +} + +/* + * call-seq: + * query -> CvMat or nil + * + * Grabs and returns a frame camera or file. Just a combination of grab and retrieve in one call. + */ +VALUE +rb_query(VALUE self) +{ + IplImage *frame = cvQueryFrame(CVCAPTURE(self)); + if(!frame) + return Qnil; + VALUE image = cIplImage::new_object(cvSize(frame->width, frame->height), CV_MAKETYPE(CV_8U, frame->nChannels)); + if (frame->origin == IPL_ORIGIN_TL) { + cvCopy(frame, CVARR(image)); + } else { + cvFlip(frame, CVARR(image)); + } + return image; +} + +/* + * Film current position in milliseconds or video capture timestamp. + */ +VALUE +rb_millisecond(VALUE self) +{ + return rb_dbl2big(cvGetCaptureProperty(CVCAPTURE(self), CV_CAP_PROP_POS_MSEC)); +} + +/* + * 0-based index of the frame to be decoded/captured next + */ +VALUE +rb_frames(VALUE self) +{ + return rb_float_new(cvGetCaptureProperty(CVCAPTURE(self), CV_CAP_PROP_POS_FRAMES)); +} + +/* + * Relative position of video file (0 - start of the film, 1 - end of the film) + */ +VALUE +rb_avi_ratio(VALUE self) +{ + return rb_float_new(cvGetCaptureProperty(CVCAPTURE(self), CV_CAP_PROP_POS_AVI_RATIO)); +} + +/* + * Size of frames in the video stream. + */ +VALUE +rb_size(VALUE self) +{ + return cCvSize::new_object(cvSize((int)cvGetCaptureProperty(CVCAPTURE(self), CV_CAP_PROP_FRAME_WIDTH), (int)cvGetCaptureProperty(CVCAPTURE(self), CV_CAP_PROP_FRAME_HEIGHT))); +} + +/* + * Width of frames in the video stream. + */ +VALUE +rb_width(VALUE self) +{ + return rb_dbl2big(cvGetCaptureProperty(CVCAPTURE(self), CV_CAP_PROP_FRAME_WIDTH)); +} + +/* + * Height of frames in the video stream. + */ +VALUE +rb_height(VALUE self) +{ + return rb_dbl2big(cvGetCaptureProperty(CVCAPTURE(self), CV_CAP_PROP_FRAME_HEIGHT)); +} + +/* + * Frame rate + */ +VALUE +rb_fps(VALUE self) +{ + return rb_dbl2big(cvGetCaptureProperty(CVCAPTURE(self), CV_CAP_PROP_FPS)); +} + +/* + * 4character code of codec. see http://www.fourcc.org/ + */ +VALUE +rb_fourcc(VALUE self) +{ + char str[4]; + double fourcc = cvGetCaptureProperty(CVCAPTURE(self), CV_CAP_PROP_FOURCC); + sprintf(str, "%s", (char*)&fourcc); + return rb_str_new2(str); +} + +/* + * Number of frames in video file. + */ +VALUE +rb_frame_count(VALUE self) +{ + return rb_dbl2big(cvGetCaptureProperty(CVCAPTURE(self), CV_CAP_PROP_FRAME_COUNT)); +} + + +__NAMESPACE_END_CVCAPTURE +__NAMESPACE_END_OPENCV diff --git a/ext/cvcapture.h b/ext/cvcapture.h new file mode 100644 index 00000000..13638528 --- /dev/null +++ b/ext/cvcapture.h @@ -0,0 +1,54 @@ +/************************************************************ + + cvcapture.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVCAPTURE_H +#define RUBY_OPENCV_CVCAPTURE_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVCAPTURE namespace cCvCapture{ +#define __NAMESPACE_END_CVCAPTURE } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVCAPTURE + + +VALUE rb_class(); + +void define_ruby_class(); + +void free(void *ptr); +VALUE rb_open(int argc, VALUE *argv, VALUE klass); + +VALUE rb_grab(VALUE self); +VALUE rb_retrieve(VALUE self); +VALUE rb_query(VALUE self); + +VALUE rb_millisecond(VALUE self); +VALUE rb_frames(VALUE self); +VALUE rb_avi_ratio(VALUE self); +VALUE rb_size(VALUE self); +VALUE rb_width(VALUE self); +VALUE rb_height(VALUE self); +VALUE rb_fps(VALUE self); +VALUE rb_fourcc(VALUE self); +VALUE rb_frame_count(VALUE self); + +__NAMESPACE_END_CVCAPTURE + + +inline CvCapture *CVCAPTURE(VALUE object){ + CvCapture *ptr; + Data_Get_Struct(object, CvCapture, ptr); + return ptr; +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVCAPTURE_H diff --git a/ext/cvchain.cpp b/ext/cvchain.cpp new file mode 100644 index 00000000..8058dd91 --- /dev/null +++ b/ext/cvchain.cpp @@ -0,0 +1,184 @@ +/************************************************************ + + cvchain.cpp - + + $Author: lsxi $ + + Copyright (C) 2007 Masakazu Yonekura + +************************************************************/ +#include "cvchain.h" +/* + * Document-class: OpenCV::CvChain + * + * Freeman chain code. + * CvMat#find_contours(:method => :code) + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVCHAIN + +#define APPROX_CHAIN_OPTION(op) NIL_P(op) ? rb_const_get(rb_class(), rb_intern("APPROX_CHAIN_OPTION")) : rb_funcall(rb_const_get(rb_class(), rb_intern("APPROX_CHAIN_OPTION")), rb_intern("merge"), 1, op) +#define APPROX_CHAIN_METHOD(op) CVMETHOD("APPROX_CHAIN_METHOD", rb_hash_aref(op, ID2SYM(rb_intern("method"))), CV_CHAIN_APPROX_SIMPLE) +#define APPROX_CHAIN_PARAMETER(op) NUM2INT(rb_hash_aref(op, ID2SYM(rb_intern("parameter")))) +#define APPROX_CHAIN_MINIMAL_PARAMETER(op) NUM2INT(rb_hash_aref(op, ID2SYM(rb_intern("minimal_parameter")))) +#define APPROX_CHAIN_RECURSIVE(op) ({VALUE _recursive = rb_hash_aref(op, ID2SYM(rb_intern("recursive"))); NIL_P(_recursive) ? 0 : _recursive == Qfalse ? 0 : 1;}) + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * cvseq = rb_define_class_under(opencv, "CvSeq"); + * curve = rb_define_module_under(opencv, "Curve"); + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + VALUE cvseq = cCvSeq::rb_class(); + VALUE curve = mCurve::rb_module(); + + rb_klass = rb_define_class_under(opencv, "CvChain", cvseq); + rb_include_module(rb_klass, curve); + VALUE approx_chain_option = rb_hash_new(); + rb_define_const(rb_klass, "APPROX_CHAIN_OPTION", approx_chain_option); + rb_hash_aset(approx_chain_option, ID2SYM(rb_intern("method")), ID2SYM(rb_intern("approx_simple"))); + rb_hash_aset(approx_chain_option, ID2SYM(rb_intern("parameter")), rb_float_new(0)); + rb_hash_aset(approx_chain_option, ID2SYM(rb_intern("minimal_parameter")), INT2FIX(0)); + rb_hash_aset(approx_chain_option, ID2SYM(rb_intern("recursive")), Qfalse); + + rb_define_method(rb_klass, "origin", RUBY_METHOD_FUNC(rb_origin), 0); + rb_define_method(rb_klass, "origin=", RUBY_METHOD_FUNC(rb_set_origin), 0); + rb_define_method(rb_klass, "codes", RUBY_METHOD_FUNC(rb_codes), 0); + rb_define_method(rb_klass, "points", RUBY_METHOD_FUNC(rb_points), 0); + rb_define_method(rb_klass, "approx_chain", RUBY_METHOD_FUNC(rb_approx_chain), -1); + rb_define_alias(rb_klass, "approx", "approx_chain"); +} + +/* + * call-seq: + * origin -> cvpoint + * + * Return Freeman chain code origin. + */ +VALUE +rb_origin(VALUE self) +{ + return cCvPoint::new_object(CVCHAIN(self)->origin); +} + +/* + * call-seq: + * origin = point -> self + * + * Set Freeman chain code origin. + */ +VALUE +rb_set_origin(VALUE self, VALUE origin) +{ + CVCHAIN(self)->origin = VALUE_TO_CVPOINT(origin); + return self; +} + +/* + * call-seq: + * codes -> array(contain fixnum) + * + * Return Freeman chain codes. + */ +VALUE +rb_codes(VALUE self) +{ + CvChain *chain = CVCHAIN(self); + CvChainPtReader reader; + CvPoint p = chain->origin; + VALUE ary = rb_ary_new2(chain->total); + cvStartReadChainPoints(chain, &reader); + for (int i = 0; i < chain->total; i++) { + CV_READ_SEQ_ELEM(reader.code, (*((CvSeqReader*)&(reader)))); + rb_ary_store(ary, i, CHR2FIX(reader.code)); + } + return ary; +} + +/* + * call-seq: + * points -> array(contain cvpoint) + * + * Return points that represent by Freeman chain code. + */ +VALUE +rb_points(VALUE self) +{ + CvChain *chain = CVCHAIN(self); + CvChainPtReader reader; + CvPoint p = chain->origin; + VALUE ary = rb_ary_new2(chain->total); + cvStartReadChainPoints(chain, &reader); + for (int i = 0; i < chain->total; i++) { + CV_READ_CHAIN_POINT(p, reader); + rb_ary_store(ary, i, cCvPoint::new_object(p)); + } + return ary; +} + +/* + * call-seq: + * approx_chain([approx_chain_option]) -> cvcontour + * + * Approximates Freeman chain(s) with polygonal curve. + * approx_chain_option should be Hash include these keys. + * :method - Approximation method. + * :approx_none - translate all the points from the chain code into points; + * :approx_simple(default) - compress horizontal, vertical, and diagonal segments, that is, + * the function leaves only their ending points. + * :approx_tc89_l1 + * :approx_tc89_kcos - apply one of the flavors of Teh-Chin chain approximation algorithm. + * If set the difference between the current pixel and seed pixel is considered, + * otherwise difference between neighbor pixels is considered (the range is floating). + * :parameter - Method parameter (not used now). + * :minimal_perimeter (default 0) + * Approximates only those contours whose perimeters are not less than minimal_perimeter. Other chains are removed from the resulting structure. + * :recursive (default false) + * If not nil or false, the function approximates all chains that access can be obtained to + * from self by h_next or v_next links. If 0, the single chain is approximated. + * + */ +VALUE +rb_approx_chain(int argc, VALUE *argv, VALUE self) +{ + VALUE approx_chain_option, storage; + rb_scan_args(argc, argv, "01", &approx_chain_option); + approx_chain_option = APPROX_CHAIN_OPTION(approx_chain_option); + /* can't compile VC + storage = cCvMemStorage::new_object(); + CvSeq *seq = cvApproxChains(CVSEQ(self), CVMEMSTORAGE(storage), + APPROX_CHAIN_METHOD(approx_chain_option), + APPROX_CHAIN_PARAMETER(approx_chain_option), + APPROX_CHAIN_MINIMAL_PARAMETER(approx_chain_option), + APPROX_CHAIN_RECURSIVE(approx_chain_option)); + + return cCvSeq::new_sequence(cCvContour::rb_class(), seq, cCvPoint::rb_class(), storage); + */ + return Qnil; +} + +VALUE +new_object() +{ + VALUE storage = cCvMemStorage::new_object(); + CvSeq *seq = cvCreateSeq(CV_SEQ_CHAIN_CONTOUR, sizeof(CvChain), sizeof(CvChainCode), CVMEMSTORAGE(storage)); + VALUE object = cCvSeq::new_sequence(cCvChain::rb_class(), seq, cCvChainCode::rb_class(), storage); + return object; +} + +__NAMESPACE_END_CVCHAIN +__NAMESPACE_END_OPENCV diff --git a/ext/cvchain.h b/ext/cvchain.h new file mode 100644 index 00000000..fa06aabb --- /dev/null +++ b/ext/cvchain.h @@ -0,0 +1,43 @@ +/************************************************************ + + cvchain.h - + + $Author: lsxi $ + + Copyright (C) 2007 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVCHAIN_H +#define RUBY_OPENCV_CVCHAIN_H +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVCHAIN namespace cCvChain{ +#define __NAMESPACE_END_CVCHAIN } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVCHAIN + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_origin(VALUE self); +VALUE rb_set_origin(VALUE self, VALUE origin); +VALUE rb_codes(VALUE self); +VALUE rb_points(VALUE self); +VALUE rb_approx_chain(int argc, VALUE *argv, VALUE self); + +VALUE new_object(); + +__NAMESPACE_END_CVCHAIN + +inline CvChain* +CVCHAIN(VALUE object){ + CvChain *ptr; + Data_Get_Struct(object, CvChain, ptr); + return ptr; +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVCHAIN_H diff --git a/ext/cvchaincode.cpp b/ext/cvchaincode.cpp new file mode 100644 index 00000000..f7e26b98 --- /dev/null +++ b/ext/cvchaincode.cpp @@ -0,0 +1,49 @@ +/************************************************************ + + cvchaincode.cpp - + + $Author: lsxi $ + + Copyright (C) 2007 Masakazu Yonekura + +************************************************************/ +#include "cvchaincode.h" +/* + * Document-class: OpenCV::CvChainCode + * + * Freeman chain code. + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVCHAINCODE + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + + rb_klass = rb_define_class_under(opencv, "CvChainCode", rb_cObject); +} + +VALUE +rb_to_i(VALUE self) +{ + return CHR2FIX(CVCHAINCODE(self)->code); +} + +__NAMESPACE_END_CVCHAINCODE +__NAMESPACE_END_OPENCV diff --git a/ext/cvchaincode.h b/ext/cvchaincode.h new file mode 100644 index 00000000..be326635 --- /dev/null +++ b/ext/cvchaincode.h @@ -0,0 +1,43 @@ +/************************************************************ + + opchaincode.h - + + $Author: lsxi $ + + Copyright (C) 2008 Masakazu Yonekura + + ************************************************************/ +#ifndef RUBY_OPENCV_CVCHAINCODE_H +#define RUBY_OPENCV_CVCHAINCODE_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVCHAINCODE namespace cCvChainCode{ +#define __NAMESPACE_END_CVCHAINCODE } + +typedef struct CvChainCode{ + char code; +}CvChainCode; + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVCHAINCODE + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_to_i(VALUE self); + +__NAMESPACE_END_CVCHAINCODE + +inline CvChainCode* +CVCHAINCODE(VALUE object){ + CvChainCode *ptr; + Data_Get_Struct(object, CvChainCode, ptr); + return ptr; +} + + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVCHAINCODE_H diff --git a/ext/cvcircle32f.cpp b/ext/cvcircle32f.cpp new file mode 100644 index 00000000..4480e792 --- /dev/null +++ b/ext/cvcircle32f.cpp @@ -0,0 +1,90 @@ +/************************************************************ + + cvcircle32f.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include "cvcircle32f.h" +/* + * Document-class: OpenCV::CvCircle32f + * + * Combination of center and radius. + * + * see CvMat#hough_circles + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVCIRCLE32F + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + + rb_klass = rb_define_class_under(opencv, "CvCircle32f", rb_cObject); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_method(rb_klass, "center", RUBY_METHOD_FUNC(rb_center), 0); + rb_define_method(rb_klass, "radius", RUBY_METHOD_FUNC(rb_radius), 0); + + //rb_define_method(rb_klass, "to_s", RUBY_METHOD_FUNC(rb_to_s), 0); + rb_define_method(rb_klass, "to_ary", RUBY_METHOD_FUNC(rb_to_ary), 0); +} + +VALUE +rb_allocate(VALUE klass) +{ + CvCircle32f *ptr; + return Data_Make_Struct(klass, CvCircle32f, 0, -1, ptr); +} + +/* + * Return parameter on center. + */ +VALUE +rb_center(VALUE self) +{ + return cCvPoint2D32f::new_object(CVCIRCLE32F(self)->center); +} + +/* + * Return parameter on radius. + */ +VALUE +rb_radius(VALUE self) +{ + return rb_float_new(CVCIRCLE32F(self)->radius); +} + +VALUE +rb_to_ary(VALUE self) +{ + return rb_ary_new3(2, rb_center(self), rb_radius(self)); +} + +VALUE +new_object(CvCircle32f circle32f) +{ + VALUE object = rb_allocate(rb_klass); + *CVCIRCLE32F(object) = circle32f; + return object; +} + +__NAMESPACE_END_CVCIRCLE32F +__NAMESPACE_END_OPENCV diff --git a/ext/cvcircle32f.h b/ext/cvcircle32f.h new file mode 100644 index 00000000..cccfa368 --- /dev/null +++ b/ext/cvcircle32f.h @@ -0,0 +1,53 @@ +/************************************************************ + + cvcircle32f.h - + + $Author: lsxi $ + + Copyright (C) 2007 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVCIRCLE32F_H +#define RUBY_OPENCV_CVCIRCLE32F_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVCIRCLE32F namespace cCvCircle32f{ +#define __NAMESPACE_END_CVCIRCLE32F } + +__NAMESPACE_BEGIN_OPENCV + +typedef struct CvCircle32f{ + CvPoint2D32f center; + float radius; +} CvCircle32f; + +__NAMESPACE_BEGIN_CVCIRCLE32F + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_allocate(VALUE klass); +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); +VALUE rb_center(VALUE self); +VALUE rb_radius(VALUE self); + +VALUE rb_to_s(VALUE self); +VALUE rb_to_ary(VALUE self); + +VALUE new_object(CvCircle32f circle32f); + +__NAMESPACE_END_CVCIRCLE32F + +inline CvCircle32f* +CVCIRCLE32F(VALUE object) +{ + CvCircle32f *ptr; + Data_Get_Struct(object, CvCircle32f, ptr); + return ptr; +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVCIRCLE32F_H diff --git a/ext/cvcondensation.cpp b/ext/cvcondensation.cpp new file mode 100644 index 00000000..be74c864 --- /dev/null +++ b/ext/cvcondensation.cpp @@ -0,0 +1,230 @@ +/************************************************************ + + cvcondensation.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include "cvcondensation.h" +/* + * Document-class: OpenCV::CvConDensation + * + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVCONDENSATION + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if(rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + rb_klass = rb_define_class_under(opencv, "CvConDensation", rb_cObject); + rb_define_method(rb_klass, "dp", RUBY_METHOD_FUNC(rb_dp), 0); + rb_define_method(rb_klass, "mp", RUBY_METHOD_FUNC(rb_mp), 0); + rb_define_method(rb_klass, "dynamic_matrix", RUBY_METHOD_FUNC(rb_dynamic_matrix), 0); + rb_define_method(rb_klass, "confidence", RUBY_METHOD_FUNC(rb_confidence), 0); + rb_define_method(rb_klass, "cumulative", RUBY_METHOD_FUNC(rb_cumulative), 0); + rb_define_method(rb_klass, "state", RUBY_METHOD_FUNC(rb_state), 0); + rb_define_method(rb_klass, "samples_num", RUBY_METHOD_FUNC(rb_samples_num), 0); + rb_define_method(rb_klass, "init_sample_set", RUBY_METHOD_FUNC(rb_init_sample_set), 2); + rb_define_method(rb_klass, "update_by_time", RUBY_METHOD_FUNC(rb_update_by_time), 0); + rb_define_alias(rb_klass, "update", "update_by_time"); + rb_define_method(rb_klass, "each_sample", RUBY_METHOD_FUNC(rb_each_sample), 0); + rb_define_method(rb_klass, "calculate_confidence", RUBY_METHOD_FUNC(rb_calculate_confidence), 0); +} + +/* + * call-seq: + * dp -> int + * + * Return dimension of state vector + */ +VALUE +rb_dp(VALUE self) +{ + return INT2FIX(CVCONDENSATION(self)->DP); +} + +/* + * call-seq: + * mp -> int + * + * Return demension of measurement vector. + */ +VALUE +rb_mp(VALUE self) +{ + return INT2FIX(CVCONDENSATION(self)->MP); +} + +/* + * call-seq: + * dynamic_matrix -> mat + * + * Return matrix of the linear Dynamics system. + */ +VALUE +rb_dynamic_matrix(VALUE self) +{ + CvConDensation *cd = CVCONDENSATION(self); + return DEPEND_OBJECT(cCvMat::rb_class(), cvInitMatHeader(ALLOC(CvMat), cd->DP, cd->DP, CV_MAKETYPE(CV_32F, 1), cd->DynamMatr), self); +} + +/* + * call-seq: + * confidence -> mat + * + * Return confidence for each sample. + */ +VALUE +rb_confidence(VALUE self) +{ + CvConDensation *cd = CVCONDENSATION(self); + return DEPEND_OBJECT(cCvMat::rb_class(), cvInitMatHeader(ALLOC(CvMat), cd->SamplesNum, 1, CV_MAKETYPE(CV_32F, 1), cd->flConfidence), self); +} + +/* + * call-seq: + * cumulative -> mat + * + * Return cumulative confidence. + */ +VALUE +rb_cumulative(VALUE self) +{ + CvConDensation *cd = CVCONDENSATION(self); + return DEPEND_OBJECT(cCvMat::rb_class(), cvInitMatHeader(ALLOC(CvMat), cd->SamplesNum, 1, CV_MAKETYPE(CV_32F, 1), cd->flCumulative), self); +} + +/* + * call-seq: + * state -> mat + * + * Return vector of state + */ +VALUE +rb_state(VALUE self) +{ + CvConDensation *cd = CVCONDENSATION(self); + return DEPEND_OBJECT(cCvMat::rb_class(), cvInitMatHeader(ALLOC(CvMat), cd->DP, 1, CV_MAKETYPE(CV_32F, 1), cd->State), self); +} + +/* + * call-seq: + * samples_num -> int + * + * Return number of the samples + */ +VALUE +rb_samples_num(VALUE self) +{ + return INT2FIX(CVCONDENSATION(self)->SamplesNum); +} + +/* + * call-seq: + * init_sample_set(upper, lower) + * + * Initializes sample set for ConDensation algorithm. + * Fills the samples with values within specified(lower to upper) ranges. + */ +VALUE +rb_init_sample_set(VALUE self, VALUE lower, VALUE upper) +{ + CvConDensation *cd = CVCONDENSATION(self); + CvMat *lower_bound = CVMAT(lower), *upper_bound = CVMAT(upper), lb_stub, ub_stub; + int lower_type = lower_bound->type, upper_type = lower_bound->type; + if (lower_type != CV_32FC1 || lower_bound->cols != 1) { + if (CV_MAT_DEPTH(lower_type) == CV_32F) { + lower_bound = cvReshape(lower_bound, &lb_stub, 1, lower_bound->rows * lower_bound->cols); + } else { + lower = cCvMat::new_object(cvSize(lower_bound->rows * lower_bound->cols, 1), CV_MAKETYPE(CV_32S, 1)); + cvConvertScale(lower_bound, CVARR(lower)); + lower_bound = CVMAT(lower); + } + } + if (upper_type != CV_32FC1 || upper_bound->cols != 1) { + if (CV_MAT_DEPTH(upper_type) == CV_32F) { + upper_bound = cvReshape(upper_bound, &ub_stub, 1, upper_bound->rows * upper_bound->cols); + } else { + upper = cCvMat::new_object(cvSize(upper_bound->rows * upper_bound->cols, 1), CV_MAKETYPE(CV_32F, 1)); + cvConvertScale(upper_bound, CVARR(upper)); + upper_bound = CVMAT(upper); + } + } + if (lower_bound->rows != cd->DP || upper_bound->rows != cd->DP) { + rb_raise(rb_eTypeError, "sample matrix step unmatch."); + } + cvConDensInitSampleSet(cd, lower_bound, upper_bound); + return self; +} + +/* + * call-seq: + * update_by_time + * + * Estimates subsequent model state. + */ +VALUE +rb_update_by_time(VALUE self) +{ + cvConDensUpdateByTime(CVCONDENSATION(self)); + return self; +} + +/* + * call-seq: + * each_sample{|mat| ... } + * + * Evaluate each sample by given block. + */ +VALUE +rb_each_sample(VALUE self) +{ + CvConDensation *cd = CVCONDENSATION(self); + if (rb_block_given_p()) { + for (int i = 0; i < cd->SamplesNum; i++) { + rb_yield(DEPEND_OBJECT(cCvMat::rb_class(), cvInitMatHeader(ALLOC(CvMat), cd->DP, 1, CV_MAKETYPE(CV_32F, 1), cd->flSamples[i]), self)); + } + } + return self; +} + +/* + * call-seq: + * calculate_confidence{|value| ... } + * + * Evalute each sample by given block, then return value set to confidence. + */ +VALUE +rb_calculate_confidence(VALUE self) +{ + VALUE value; + CvConDensation *cd = CVCONDENSATION(self); + if (rb_block_given_p()) { + for (int i = 0; i < cd->SamplesNum; i++) { + value = rb_yield(DEPEND_OBJECT(cCvMat::rb_class(), cvInitMatHeader(ALLOC(CvMat), cd->DP, 1, CV_MAKETYPE(CV_32F, 1), cd->flSamples[i]), self)); + cd->flConfidence[i] = NUM2DBL(value); + } + } + return self; +} + +__NAMESPACE_END_CVCONDENSATION +__NAMESPACE_END_OPENCV diff --git a/ext/cvcondensation.h b/ext/cvcondensation.h new file mode 100644 index 00000000..dd3950e1 --- /dev/null +++ b/ext/cvcondensation.h @@ -0,0 +1,49 @@ +/************************************************************ + + cvcondensation.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVCONDENSATION_H +#define RUBY_OPENCV_CVCONDENSATION_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVCONDENSATION namespace cCvConDensation{ +#define __NAMESPACE_END_CVCONDENSATION } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVCONDENSATION + +VALUE rb_class(); +void define_ruby_class(); + +VALUE rb_dp(VALUE self); +VALUE rb_mp(VALUE self); +VALUE rb_dynamic_matrix(VALUE self); +VALUE rb_state(VALUE self); +VALUE rb_confidence(VALUE self); +VALUE rb_cumulative(VALUE self); +VALUE rb_samples_num(VALUE self); + +VALUE rb_init_sample_set(VALUE self, VALUE lower, VALUE upper); +VALUE rb_update_by_time(VALUE self); +VALUE rb_each_sample(VALUE self); +VALUE rb_calculate_confidence(VALUE self); + +__NAMESPACE_END_CVCONDENSATION + +inline CvConDensation* +CVCONDENSATION(VALUE object) +{ + CvConDensation *ptr; + Data_Get_Struct(object, CvConDensation, ptr); + return ptr; +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVCONDENSATION_H diff --git a/ext/cvconnectedcomp.cpp b/ext/cvconnectedcomp.cpp new file mode 100644 index 00000000..a3f5907b --- /dev/null +++ b/ext/cvconnectedcomp.cpp @@ -0,0 +1,115 @@ +/************************************************************ + + cvconnectedcomp.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2007 Masakazu Yonekura + +************************************************************/ +#include "cvconnectedcomp.h" +/* + * Document-class: OpenCV::CvConnectedComp + * + * see CvMat#flood_fill + * + * C structure is here. + * typedef struct CvConnectedComp + * { + * double area; + * CvScalar value; + * CvRect rect; + * CvSeq* contour; + * } CvConnectedComp; + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVCONNECTEDCOMP + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + + rb_klass = rb_define_class_under(opencv, "CvConnectedComp", rb_cObject); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_method(rb_klass, "area", RUBY_METHOD_FUNC(rb_area), 0); + rb_define_method(rb_klass, "value", RUBY_METHOD_FUNC(rb_value), 0); + rb_define_method(rb_klass, "rect", RUBY_METHOD_FUNC(rb_rect), 0); + rb_define_method(rb_klass, "rect=", RUBY_METHOD_FUNC(rb_set_rect), 0); +} + +VALUE +rb_allocate(VALUE klass) +{ + CvConnectedComp *ptr; + return Data_Make_Struct(klass, CvConnectedComp, 0, -1, ptr); +} + +/* + * Return area of connected component. + */ +VALUE +rb_area(VALUE self) +{ + return rb_float_new(CVCONNECTEDCOMP(self)->area); +} + +/* + * Return average color of the connected component. + */ +VALUE +rb_value(VALUE self) +{ + return REFER_OBJECT(cCvScalar::rb_class(), &CVCONNECTEDCOMP(self)->value, self); +} + +/* + * Return ROI of the component. + */ +VALUE +rb_rect(VALUE self) +{ + return REFER_OBJECT(cCvRect::rb_class(), &CVCONNECTEDCOMP(self)->rect, self); +} + +/* + * Set ROI of the component. + */ +VALUE +rb_set_rect(VALUE self, VALUE rect) +{ + CVCONNECTEDCOMP(self)->rect = VALUE_TO_CVRECT(rect); + return self; +} + +VALUE +new_object() +{ + return rb_allocate(rb_klass); +} + +VALUE +new_object(CvConnectedComp comp) +{ + VALUE object = rb_allocate(rb_klass); + *CVCONNECTEDCOMP(object) = comp; + return object; +} + +__NAMESPACE_END_CVCONNECTEDCOMP +__NAMESPACE_END_OPENCV diff --git a/ext/cvconnectedcomp.h b/ext/cvconnectedcomp.h new file mode 100644 index 00000000..8d11f763 --- /dev/null +++ b/ext/cvconnectedcomp.h @@ -0,0 +1,46 @@ +/************************************************************ + + cvconnectedcomp.h - + + $Author: lsxi $ + + Copyright (C) 2005-2007 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVCONNECTEDCOMP_H +#define RUBY_OPENCV_CVCONNECTEDCOMP_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVCONNECTEDCOMP namespace cCvConnectedComp{ +#define __NAMESPACE_END_CVCONNECTEDCOMP } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVCONNECTEDCOMP + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_allocate(VALUE klass); + +VALUE rb_area(VALUE self); +VALUE rb_value(VALUE self); +VALUE rb_rect(VALUE self); +VALUE rb_set_rect(VALUE self, VALUE rect); +VALUE rb_contour(VALUE self); + +VALUE new_object(); +VALUE new_object(CvConnectedComp comp); + +__NAMESPACE_END_CVCONNECTEDCOMP + +inline CvConnectedComp *CVCONNECTEDCOMP(VALUE object){ + CvConnectedComp *ptr; + Data_Get_Struct(object, CvConnectedComp, ptr); + return ptr; +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVCONNECTEDCOMP_H diff --git a/ext/cvcontour.cpp b/ext/cvcontour.cpp new file mode 100644 index 00000000..2678b833 --- /dev/null +++ b/ext/cvcontour.cpp @@ -0,0 +1,219 @@ +/************************************************************ + + cvcontour.cpp - + + $Author: lsxi $ + + Copyright (C) 2007 Masakazu Yonekura + +************************************************************/ +#include "cvcontour.h" +/* + * Document-class: OpenCV::CvContour + * + * Contour. + * CvMat#find_contours + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVCONTOUR + +#define APPROX_POLY_OPTION(op) NIL_P(op) ? rb_const_get(rb_class(), rb_intern("APPROX_OPTION")) : rb_funcall(rb_const_get(rb_class(), rb_intern("APPROX_OPTION")), rb_intern("merge"), 1, op) +#define APPROX_POLY_METHOD(op) CVMETHOD("APPROX_POLY_METHOD", rb_hash_aref(op, ID2SYM(rb_intern("method"))), CV_POLY_APPROX_DP) +#define APPROX_POLY_ACCURACY(op) NUM2DBL(rb_hash_aref(op, ID2SYM(rb_intern("accuracy")))) +#define APPROX_POLY_RECURSIVE(op) ({VALUE _recursive = rb_hash_aref(op, ID2SYM(rb_intern("recursive"))); NIL_P(_recursive) ? 0 : _recursive == Qfalse ? 0 : 1;}) + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * cvseq = rb_define_class_under(opencv, "CvSeq"); + * curve = rb_define_module_under(opencv, "Curve"); + * pointset = rb_define_module_under(opencv, "PointSet"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + VALUE cvseq = cCvSeq::rb_class(); + VALUE curve = mCurve::rb_module(); + VALUE pointset = mPointSet::rb_module(); + + rb_klass = rb_define_class_under(opencv, "CvContour", cvseq); + rb_include_module(rb_klass, curve); + rb_include_module(rb_klass, pointset); + + VALUE approx_option = rb_hash_new(); + rb_define_const(rb_klass, "APPROX_OPTION", approx_option); + rb_hash_aset(approx_option, ID2SYM(rb_intern("method")), INT2FIX(CV_POLY_APPROX_DP)); + rb_hash_aset(approx_option, ID2SYM(rb_intern("accuracy")), rb_float_new(1.0)); + rb_hash_aset(approx_option, ID2SYM(rb_intern("recursive")), Qfalse); + + rb_define_private_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); + rb_define_method(rb_klass, "rect", RUBY_METHOD_FUNC(rb_rect), 0); + rb_define_method(rb_klass, "color", RUBY_METHOD_FUNC(rb_color), 0); + rb_define_method(rb_klass, "color=", RUBY_METHOD_FUNC(rb_set_color), 1); + rb_define_method(rb_klass, "reserved", RUBY_METHOD_FUNC(rb_reserved), 0); + rb_define_method(rb_klass, "approx_poly", RUBY_METHOD_FUNC(rb_approx_poly), -1); + rb_define_alias(rb_klass, "approx", "approx_poly"); + rb_define_method(rb_klass, "bounding_rect", RUBY_METHOD_FUNC(rb_bounding_rect), 0); + rb_define_method(rb_klass, "create_tree", RUBY_METHOD_FUNC(rb_create_tree), -1); + rb_define_method(rb_klass, "in?", RUBY_METHOD_FUNC(rb_in_q), 1); + rb_define_method(rb_klass, "measure_distance", RUBY_METHOD_FUNC(rb_measure_distance), 1); +} + +VALUE +rb_initialize(int argc, VALUE *argv, VALUE self) +{ + /* + VALUE storage; + CvSeq *seq = 0; + rb_scan_args(argc, argv, "01", &storage); + + storage = CHECK_CVMEMSTORAGE(storage); + seq = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), CVMEMSTORAGE(storage)); + DATA_PTR(self) = seq; + resist_root_object(seq, storage); + st_insert(cCvSeq::seqblock_klass, (st_data_t)seq, (st_data_t)klass); + */ + return self; +} + +VALUE +rb_rect(VALUE self) +{ + return cCvRect::new_object(CVCONTOUR(self)->rect); +} + +VALUE +rb_color(VALUE self) +{ + return INT2NUM(CVCONTOUR(self)->color); +} + +VALUE +rb_set_color(VALUE self, VALUE color) +{ + CVCONTOUR(self)->color = NUM2INT(color); + return self; +} + +VALUE +rb_reserved(VALUE self) +{ + return rb_ary_new3(3, + INT2NUM(CVCONTOUR(self)->reserved[0]), + INT2NUM(CVCONTOUR(self)->reserved[1]), + INT2NUM(CVCONTOUR(self)->reserved[2])); +} + +/* + * call-seq: + * approx_poly(approx_poly_option) -> cvcontour + * + * Approximates polygonal curve(s) with desired precision. + * approx_poly_option should be Hash include these keys. + * :method - Approximation method. + * :dp - corresponds to Douglas-Peucker algorithm. + * :accuracy - approximation accuracy. (high-accuracy will create more simple contours) + * :recursive - (default false) + * If not nil or false, the function approximates all chains that access can be obtained to + * from self by h_next or v_next links. If 0, approximated this one. + */ + +VALUE +rb_approx_poly(int argc, VALUE *argv, VALUE self) +{ + VALUE approx_poly_option, storage; + rb_scan_args(argc, argv, "01", &approx_poly_option); + approx_poly_option = APPROX_POLY_OPTION(approx_poly_option); + storage = cCvMemStorage::new_object(); + /* + CvSeq *contour = cvApproxPoly(CVCONTOUR(self), sizeof(CvContour), CVMEMSTORAGE(storage), + APPROX_POLY_METHOD(approx_poly_option), + APPROX_POLY_ACCURACY(approx_poly_option), + APPROX_POLY_RECURSIVE(approx_poly_option)); + return cCvSeq::new_sequence(cCvContour::rb_class(), contour, cCvPoint::rb_class(), storage); + */ + return Qnil; +} + +/* + * call-seq: + * bounding_rect -> rect + * + * Calculates up-right bounding rectangle of point set. + * + */ +VALUE +rb_bounding_rect(VALUE self) +{ + return cCvRect::new_object(cvBoundingRect(CVCONTOUR(self), 1)); +} + +/* + * call-seq: + * create_tree([threshold = 0.0]) -> cvcontourtree + * + * Creates hierarchical representation of contour. + * If the parameter threshold is less than or equal to 0, + * the method creates full binary tree representation. + * If the threshold is greater than 0, the function creates + * representation with the precision threshold: + */ +VALUE +rb_create_tree(int argc, VALUE *argv, VALUE self) +{ + VALUE threshold, storage; + rb_scan_args(argc, argv, "01", &threshold); + storage = cCvMemStorage::new_object(); + CvContourTree *tree = cvCreateContourTree(CVSEQ(self), CVMEMSTORAGE(storage), IF_DBL(threshold, 0.0)); + return cCvSeq::new_sequence(cCvContourTree::rb_class(), (CvSeq*)tree, cCvPoint::rb_class(), storage); +} + +/* + * call-seq: + * in?(point) -> true or nil or false + * + * Determines whether the point is inside contour(true), outside(false), or lies on an edge(nil). + */ +VALUE +rb_in_q(VALUE self, VALUE point) +{ + double n = cvPointPolygonTest(CVARR(self), VALUE_TO_CVPOINT2D32F(point), 0); + return n == 0 ? Qnil : n > 0 ? Qtrue : Qfalse; +} + +/* + * call-seq: + * measure_distance(point) -> float + * + * Return distance between the point and the nearest contour edge. + */ +VALUE +rb_measure_distance(VALUE self, VALUE point) +{ + return rb_float_new(cvPointPolygonTest(CVARR(self), VALUE_TO_CVPOINT2D32F(point), 1)); +} + + +VALUE new_object() +{ + VALUE storage = cCvMemStorage::new_object(); + CvSeq *seq = cvCreateSeq(CV_SEQ_CONTOUR, sizeof(CvContour), sizeof(CvPoint), CVMEMSTORAGE(storage)); + VALUE object = cCvSeq::new_sequence(cCvContour::rb_class(), seq, cCvPoint::rb_class(), storage); + return object; +} + +__NAMESPACE_END_CVCONTOUR +__NAMESPACE_END_OPENCV + diff --git a/ext/cvcontour.h b/ext/cvcontour.h new file mode 100644 index 00000000..8eea828f --- /dev/null +++ b/ext/cvcontour.h @@ -0,0 +1,47 @@ +/************************************************************ + + cvcontour.h - + + $Author: lsxi $ + + Copyright (C) 2007 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVCONTOUR_H +#define RUBY_OPENCV_CVCONTOUR_H +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVCONTOUR namespace cCvContour{ +#define __NAMESPACE_END_CVCONTOUR } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVCONTOUR + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); +VALUE rb_rect(VALUE self); +VALUE rb_color(VALUE self); +VALUE rb_set_color(VALUE self, VALUE color); +VALUE rb_reserved(VALUE self); +VALUE rb_approx_poly(int argc, VALUE *argv, VALUE self); +VALUE rb_bounding_rect(VALUE self); +VALUE rb_create_tree(int argc, VALUE *argv, VALUE self); +VALUE rb_in_q(VALUE self, VALUE point); +VALUE rb_measure_distance(VALUE self, VALUE point); + +VALUE new_object(); +__NAMESPACE_END_CVCONTOUR + +inline CvContour* +CVCONTOUR(VALUE object){ + CvContour *ptr; + Data_Get_Struct(object, CvContour, ptr); + return ptr; +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVCONTOUR_H diff --git a/ext/cvcontourtree.cpp b/ext/cvcontourtree.cpp new file mode 100644 index 00000000..ccbfe4db --- /dev/null +++ b/ext/cvcontourtree.cpp @@ -0,0 +1,86 @@ +/************************************************************ + + cvcontourtree.cpp - + + $Author: lsxi $ + + Copyright (C) 2007 Masakazu Yonekura + +************************************************************/ +#include "cvcontour.h" +/* + * Document-class: OpenCV::CvContourTree + * + * Contour tree. CvContour#create_tree + * + * C structure is here. + * typedef struct CvContourTree{ + * CV_SEQUENCE_FIELDS() + * CvPoint p1; + * CvPoint p2; + * }CvContourTree; + * + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVCONTOURTREE + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * cvseq = rb_define_class_under(opencv, "CvSeq"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + VALUE cvseq = cCvSeq::rb_class(); + + rb_klass = rb_define_class_under(opencv, "CvContourTree", cvseq); + rb_define_method(rb_klass, "p1", RUBY_METHOD_FUNC(rb_p1), 0); + rb_define_method(rb_klass, "p2", RUBY_METHOD_FUNC(rb_p2), 0); + rb_define_method(rb_klass, "contour", RUBY_METHOD_FUNC(rb_contour), 0); + +} + +VALUE +rb_p1(VALUE self) +{ + return REFER_OBJECT(cCvPoint::rb_class(), &CVCONTOURTREE(self)->p1, self); +} + +VALUE +rb_p2(VALUE self) +{ + return REFER_OBJECT(cCvPoint::rb_class(), &CVCONTOURTREE(self)->p2, self); +} + +/* + * call-seq: + * contour([criteria = 0]) -> cvcontour + * + * Restores the contour from its binary tree representation. + * The parameter criteria determines the accuracy and/or the number of tree levels + * used for reconstruction, so it is possible to build approximated contour. + */ +VALUE +rb_contour(int argc, VALUE *argv, VALUE self) +{ + VALUE criteria, storage; + rb_scan_args(argc, argv, "01", &criteria); + CvSeq *contour = cvContourFromContourTree(CVCONTOURTREE(self), CVMEMSTORAGE(storage), VALUE_TO_CVTERMCRITERIA(criteria)); + return cCvSeq::new_sequence(cCvContour::rb_class(), contour, cCvPoint::rb_class(), storage); +} + +__NAMESPACE_END_CVCONTOURTREE +__NAMESPACE_END_OPENCV diff --git a/ext/cvcontourtree.h b/ext/cvcontourtree.h new file mode 100644 index 00000000..1b2f9008 --- /dev/null +++ b/ext/cvcontourtree.h @@ -0,0 +1,41 @@ +/************************************************************ + + cvcontourtree.h - + + $Author: lsxi $ + + Copyright (C) 2007 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVCONTOURTREE_H +#define RUBY_OPENCV_CVCONTOURTREE_H +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVCONTOURTREE namespace cCvContourTree{ +#define __NAMESPACE_END_CVCONTOURTREE } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVCONTOURTREE + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_p1(VALUE self); +VALUE rb_p2(VALUE self); +VALUE rb_contour(int argc, VALUE *argv, VALUE self); + +VALUE new_object(); + +__NAMESPACE_END_CVCONTOURTREE + +inline CvContourTree* +CVCONTOURTREE(VALUE object){ + CvContourTree *ptr; + Data_Get_Struct(object, CvContourTree, ptr); + return ptr; +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVCONTOUR_H diff --git a/ext/cvconvexitydefect.cpp b/ext/cvconvexitydefect.cpp new file mode 100644 index 00000000..9c5c8f5f --- /dev/null +++ b/ext/cvconvexitydefect.cpp @@ -0,0 +1,103 @@ +/************************************************************ + + cvconvexitydefect.cpp - + + $Author: lsxi $ + + Copyright (C) 2007 Masakazu Yonekura + +************************************************************/ +#include "cvconvexitydefect.h" +/* + * Document-class: OpenCV::CvConvexityDefect + * + * Convexity. + * C structure is here. + * typedef struct CvConvexityDefect { + * CvPoint* start; + * CvPoint* end; + * CvPoint* depth_point; + * float depth; + * }CvConvexityDefect; + * + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVCONVEXITYDEFECT + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + + rb_klass = rb_define_class_under(opencv, "CvConvexityDefect", rb_cObject); + rb_define_method(rb_klass, "start", RUBY_METHOD_FUNC(rb_start), 0); + rb_define_method(rb_klass, "end", RUBY_METHOD_FUNC(rb_end), 0); + rb_define_method(rb_klass, "depth_point", RUBY_METHOD_FUNC(rb_depth_point), 0); + rb_define_method(rb_klass, "depth", RUBY_METHOD_FUNC(rb_depth), 0); +} + +/* + * call-seq: + * start -> cvpoint + * + * Return start point as CvPoint. + */ +VALUE +rb_start(VALUE self) +{ + return cCvPoint::new_object(*CVCONVEXITYDEFECT(self)->start); +} + +/* + * call-seq: + * end -> cvpoint + * + * Return end point as CvPoint. + */ +VALUE +rb_end(VALUE self) +{ + return cCvPoint::new_object(*CVCONVEXITYDEFECT(self)->end); +} + +/* + * call-seq: + * depth_point -> cvpoint + * + * Return depth point as CvPoint. + */ +VALUE +rb_depth_point(VALUE self) +{ + return cCvPoint::new_object(*CVCONVEXITYDEFECT(self)->depth_point); +} + +/* + * call-seq: + * depth -> float + * + * Return depth. + */ +VALUE +rb_depth(VALUE self) +{ + return rb_float_new(CVCONVEXITYDEFECT(self)->depth); +} + +__NAMESPACE_END_CVCONVEXITYDEFECT +__NAMESPACE_END_OPENCV diff --git a/ext/cvconvexitydefect.h b/ext/cvconvexitydefect.h new file mode 100644 index 00000000..be5c98a3 --- /dev/null +++ b/ext/cvconvexitydefect.h @@ -0,0 +1,42 @@ +/************************************************************ + + cvconvexitydefect.h - + + $Author: lsxi $ + + Copyright (C) 2007 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVCONVEXITYDEFECT_H +#define RUBY_OPENCV_CVCONVEXITYDEFECT_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVCONVEXITYDEFECT namespace cCvConvexityDefect{ +#define __NAMESPACE_END_CVCONVEXITYDEFECT } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVCONVEXITYDEFECT + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_start(VALUE self); +VALUE rb_end(VALUE self); +VALUE rb_depth_point(VALUE self); +VALUE rb_depth(VALUE self); + +__NAMESPACE_END_CVCONVEXITYDEFECT + +inline CvConvexityDefect* +CVCONVEXITYDEFECT(VALUE object) +{ + CvConvexityDefect *ptr; + Data_Get_Struct(object, CvConvexityDefect, ptr); + return ptr; +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVCONVEXITYDEFECT_H diff --git a/ext/cverror.cpp b/ext/cverror.cpp new file mode 100644 index 00000000..7220a729 --- /dev/null +++ b/ext/cverror.cpp @@ -0,0 +1,140 @@ +/************************************************************ + + cverror.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include "cverror.h" +/* + * Document-module: OpenCV::CvError + * + * =Internal OpenCV errors + * + * This module collect OpenCV internal error wrapper classes. + * * CvStatusBackTrace + * * CvStatusError + * * CvStatusInternal + * * CvStatusNoMemory + * * CvStatusBadArgument + * * CvStatusNoConverge + * * CvStatusAutoTrace + * + * * CvHeaderIsNull + * * CvBadImageSize + * * CvBadOffset + * * CvBadDataPointer + * * CvBadStep + * * CvBadModelOrChannelSequence + * * CvBadNumChannels + * * CvBadAlphaChannel + * * CvBadOrder + * * CvBadOrigin + * * CvBadAlign + * * CvBadCallback + * * CvBadTileSize + * * CvBadCOI + * * CvBadROISize + * + * * CvMaskIsTiled + * + * * CvStatusNullPointer + * * CvStatusVectorLengthError + * * CvStatusFilterStructContentError + * * CvStatusKernelStructContentError + * * CvStatusFilterOffsetError + * + * * CvStatusBadSize + * * CvStatusDivByZero + * * CvStatusInplaceNotSupported + * * CvStatusObjectNotFound + * * CvStatusUnmatchedFormant + * * CvStatusUnsupportedFormats + * * CvStatusOutOfRange + * * CvStatusParseError + * * CvStatusNotImplemented + * * CvStsBadMemoryBlock + */ +#define RESIST_CVERROR(object_name, error_code, parent) st_insert(cv_error, (st_data_t)error_code, (st_data_t)rb_define_class_under(rb_module_opencv(), object_name, parent)) + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVERROR + +st_table *cv_error = st_init_numtable(); + +VALUE module; + +void +define_ruby_module() +{ + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + + module = rb_define_module_under(opencv, "CvError"); + RESIST_CVERROR("CvStatusBackTrace", CV_StsBackTrace, rb_eStandardError); + RESIST_CVERROR("CvStatusError", CV_StsError, rb_eStandardError); + RESIST_CVERROR("CvStatusInternal", CV_StsInternal, rb_eStandardError); + RESIST_CVERROR("CvStatusNoMemory", CV_StsNoMem, rb_eNoMemError); + RESIST_CVERROR("CvStatusBadArgument", CV_StsBadArg, rb_eArgError); + RESIST_CVERROR("CvStatusBadFunction", CV_StsBadFunc, rb_eStandardError); + RESIST_CVERROR("CvStatusNoConverge", CV_StsNoConv, rb_eStandardError); + RESIST_CVERROR("CvStatusAutoTrace", CV_StsAutoTrace, rb_eStandardError); + + RESIST_CVERROR("CvHeaderIsNull", CV_HeaderIsNull, rb_eStandardError); + RESIST_CVERROR("CvBadImageSize", CV_BadImageSize, rb_eRangeError); + RESIST_CVERROR("CvBadOffset", CV_BadOffset, rb_eStandardError); + RESIST_CVERROR("CvBadDataPointer", CV_BadDataPtr, rb_eStandardError); + RESIST_CVERROR("CvBadStep", CV_BadStep, rb_eStandardError); + RESIST_CVERROR("CvBadModelOrChannelSequence", CV_BadModelOrChSeq, rb_eStandardError); + RESIST_CVERROR("CvBadNumChannels", CV_BadNumChannels, rb_eStandardError); + RESIST_CVERROR("CvBadNumChannel1U", CV_BadNumChannel1U, rb_eStandardError); + RESIST_CVERROR("CvNBadDepth", CV_BadDepth, rb_eStandardError); + RESIST_CVERROR("CvBadAlphaChannel", CV_BadAlphaChannel, rb_eStandardError); + RESIST_CVERROR("CvBadOrder", CV_BadOrder, rb_eStandardError); + RESIST_CVERROR("CvBadOrigin", CV_BadOrigin, rb_eStandardError); + RESIST_CVERROR("CvBadAlign", CV_BadAlign, rb_eStandardError); + RESIST_CVERROR("CvBadCallBack", CV_BadCallBack, rb_eStandardError); + RESIST_CVERROR("CvBadTileSize", CV_BadTileSize, rb_eStandardError); + RESIST_CVERROR("CvBadCOI", CV_BadCOI, rb_eStandardError); + RESIST_CVERROR("CvBadROISize", CV_BadROISize, rb_eStandardError); + + RESIST_CVERROR("CvMaskIsTiled", CV_MaskIsTiled, rb_eStandardError); + + RESIST_CVERROR("CvStatusNullPointer", CV_StsNullPtr, rb_eStandardError); + RESIST_CVERROR("CvStatusVectorLengthError", CV_StsVecLengthErr, rb_eStandardError); + RESIST_CVERROR("CvStatusFilterStructContentError", CV_StsFilterStructContentErr, rb_eStandardError); + RESIST_CVERROR("CvStatusKernelStructContentError", CV_StsKernelStructContentErr, rb_eStandardError); + RESIST_CVERROR("CvStatusFilterOffsetError", CV_StsFilterOffsetErr, rb_eStandardError); + + RESIST_CVERROR("CvStatusBadSize", CV_StsBadSize, rb_eStandardError); + RESIST_CVERROR("CvStatusDivByZero", CV_StsDivByZero, rb_eStandardError); + RESIST_CVERROR("CvStatusInplaceNotSupported", CV_StsInplaceNotSupported, rb_eStandardError); + RESIST_CVERROR("CvStatusObjectNotFound", CV_StsObjectNotFound, rb_eStandardError); + RESIST_CVERROR("CvStatusUnmatchedFormats", CV_StsUnmatchedFormats, rb_eStandardError); + RESIST_CVERROR("CvStatusBadFlag", CV_StsBadFlag, rb_eStandardError); + RESIST_CVERROR("CvStatusBadPoint", CV_StsBadPoint, rb_eStandardError); + RESIST_CVERROR("CvStatusBadMask", CV_StsBadMask, rb_eStandardError); + RESIST_CVERROR("CvStatusUnmatchedSizes", CV_StsUnmatchedSizes, rb_eStandardError); + RESIST_CVERROR("CvStatusUnsupportedFormat", CV_StsUnsupportedFormat, rb_eStandardError); + RESIST_CVERROR("CvStatusOutOfRange", CV_StsOutOfRange, rb_eStandardError); + RESIST_CVERROR("CvStatusParseError", CV_StsParseError, rb_eStandardError); + RESIST_CVERROR("CvStatusNotImplemented", CV_StsNotImplemented, rb_eNotImpError); + RESIST_CVERROR("CvStsBadMemoryBlock", CV_StsBadMemBlock,rb_eStandardError); +} + +VALUE +by_code(int error_code) +{ + VALUE klass = 0; + st_lookup(cv_error, (st_data_t)error_code, (st_data_t*)&klass); + return klass ? klass : rb_eStandardError; +} + +__NAMESPACE_END_CVERROR +__NAMESPACE_END_OPENCV diff --git a/ext/cverror.h b/ext/cverror.h new file mode 100644 index 00000000..455f3e67 --- /dev/null +++ b/ext/cverror.h @@ -0,0 +1,79 @@ +/************************************************************ + + cverror.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVERROR_H +#define RUBY_OPENCV_CVERROR_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVERROR namespace mCvError{ +#define __NAMESPACE_END_CVERROR } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVERROR + +/* + VALUE + status_back_trace, + status_error, + status_internal, + status_no_memory, + status_bad_argument, + status_bad_function, + status_no_converge, + status_auto_trace, + + header_is_null, + bad_image_size, + bad_offset, + bad_data_pointer, + bad_step, + bad_model_or_channel_seqence, + bad_num_channels, + bad_num_channel1U, + bad_depth, + bad_alpha_channel, + bad_order, + bad_origin, + bad_align, + bad_callback, + bad_tile_size, + bad_COI, + bad_ROI_size, + + mask_is_tiled, + + status_null_pointer, + status_vector_length_error, + status_filter_struct_content_error, + status_kernel_struct_content_error, + status_filter_offset_error, + + status_bad_size, + status_div_by_zero, + status_inplace_not_supported, + status_object_not_found, + status_unmatched_formats, + status_bad_flags, + status_bad_point, + status_bad_mask, + status_unmatched_sizes, + status_unsupported_format, + status_out_of_range, + status_parse_error, + status_not_implemented, + status_bad_memory_block; +*/ +void define_ruby_module(); +VALUE by_code(int error_code); + +__NAMESPACE_END_CVERROR +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVERROR_H diff --git a/ext/cvfont.cpp b/ext/cvfont.cpp new file mode 100644 index 00000000..c390a9b5 --- /dev/null +++ b/ext/cvfont.cpp @@ -0,0 +1,173 @@ +/************************************************************ + + cvfont.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include "cvfont.h" +/* + * Document-class: OpenCV::CvFont + * + * Font structure that can be passed to text rendering functions. + * see CvMat#put_text, CvMat#put_text! + */ + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVFONT + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + + rb_klass = rb_define_class_under(opencv, "CvFont", rb_cObject); + rb_define_alloc_func(rb_klass, rb_allocate); + VALUE face = rb_hash_new(); + rb_define_const(rb_klass, "FACE", face); + rb_hash_aset(face, ID2SYM(rb_intern("simplex")), INT2FIX(CV_FONT_HERSHEY_SIMPLEX)); + rb_hash_aset(face, ID2SYM(rb_intern("plain")), INT2FIX(CV_FONT_HERSHEY_PLAIN)); + rb_hash_aset(face, ID2SYM(rb_intern("duplex")), INT2FIX(CV_FONT_HERSHEY_DUPLEX)); + rb_hash_aset(face, ID2SYM(rb_intern("triplex")), INT2FIX(CV_FONT_HERSHEY_TRIPLEX)); + rb_hash_aset(face, ID2SYM(rb_intern("complex_small")), INT2FIX(CV_FONT_HERSHEY_COMPLEX_SMALL)); + rb_hash_aset(face, ID2SYM(rb_intern("script_simplex")), INT2FIX(CV_FONT_HERSHEY_SCRIPT_SIMPLEX)); + rb_hash_aset(face, ID2SYM(rb_intern("script_complex")), INT2FIX(CV_FONT_HERSHEY_SCRIPT_COMPLEX)); + + VALUE default_option = rb_hash_new(); + rb_define_const(rb_klass, "FONT_OPTION", default_option); + rb_hash_aset(default_option, ID2SYM(rb_intern("hscale")), rb_float_new(1.0)); + rb_hash_aset(default_option, ID2SYM(rb_intern("vscale")), rb_float_new(1.0)); + rb_hash_aset(default_option, ID2SYM(rb_intern("shear")), INT2FIX(0)); + rb_hash_aset(default_option, ID2SYM(rb_intern("thickness")), INT2FIX(1)); + rb_hash_aset(default_option, ID2SYM(rb_intern("line_type")), INT2FIX(8)); + + rb_define_private_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); +} + +VALUE +rb_allocate(VALUE klass) +{ + CvFont *ptr; + return Data_Make_Struct(klass, CvFont, 0, -1, ptr); +} + + +/* + * call-seq: + * CvFont.new(face[,font_option]) -> font + * + * Create font object. + * face is font name identifier. + * + * Only a subset of Hershey fonts (http://sources.isc.org/utils/misc/hershey-font.txt) are supported now: + * * :simplex - normal size sans-serif font + * * :plain - small size sans-serif font + * * :duplex - normal size sans-serif font (more complex than :simplex) + * * :complex - normal size serif font + * * :triplex - normal size serif font (more complex than :complex) + * * :complex_small - smaller version of :complex + * * :script_simplex - hand-writing style font + * * :script_complex - more complex variant of :script_simplex + * + * font_option should be Hash include these keys. + * :hscale + * Horizontal scale. If equal to 1.0, the characters have the original width depending on the font type. + * If equal to 0.5, the characters are of half the original width. + * :vscale + * Vertical scale. If equal to 1.0, the characters have the original height depending on the font type. + * If equal to 0.5, the characters are of half the original height. + * :shear + * Approximate tangent of the character slope relative to the vertical line. + * Zero value means a non-italic font, 1.0f means ~45degree slope, etc. + * :thickness + * Thickness of the text strokes. + * :line_type + * Type of the strokes, see CvMat#Line description. + * :italic + * If value is not nil or false that means italic or oblique font. + * + * note: font_option's default value is CvFont::FONT_OPTION. + * + * e.g. Create Font + * OpenCV::CvFont.new(:simplex, :hscale => 2, :vslace => 2, :italic => true) + * # create 2x bigger than normal, italic type font. + */ +VALUE +rb_initialize(int argc, VALUE *argv, VALUE self) +{ + VALUE face, font_option; + rb_scan_args(argc, argv, "11", &face, &font_option); + Check_Type(face, T_SYMBOL); + face = rb_hash_aref(rb_const_get(cCvFont::rb_class(), rb_intern("FACE")), face); + if (NIL_P(face)) { + rb_raise(rb_eArgError, "undefined face."); + } + font_option = FONT_OPTION(font_option); + /* + cvInitFont(CVFONT(self), + (FIX2INT(face) | FO_ITALIC(font_option)), + FO_HSCALE(font_option), + FO_VSCALE(font_option), + FO_SHEAR(font_option), + FO_THICKNESS(font_option), + FO_LINE_TYPE(font_option)); + */ + return self; +} + + +VALUE +rb_face(VALUE self) +{ + return FIX2INT(CVFONT(self)->font_face); +} + +VALUE +rb_hscale(VALUE self) +{ + return rb_float_new(CVFONT(self)->hscale); +} + +VALUE +rb_vscale(VALUE self) +{ + return rb_float_new(CVFONT(self)->vscale); +} + +VALUE +rb_shear(VALUE self) +{ + return rb_float_new(CVFONT(self)->shear); +} + +VALUE +rb_thickness(VALUE self) +{ + return FIX2INT(CVFONT(self)->thickness); +} + +VALUE +rb_line_type(VALUE self) +{ + return FIX2INT(CVFONT(self)->line_type); +} + +__NAMESPACE_END_CVFONT +__NAMESPACE_END_OPENCV diff --git a/ext/cvfont.h b/ext/cvfont.h new file mode 100644 index 00000000..1b76090e --- /dev/null +++ b/ext/cvfont.h @@ -0,0 +1,56 @@ +/************************************************************ + + cvfont.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVFONT_H +#define RUBY_OPENCV_CVFONT_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVFONT namespace cCvFont{ +#define __NAMESPACE_END_CVFONT } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVFONT + +#define FONT_OPTION(op) NIL_P(op) ? rb_const_get(rb_class(), rb_intern("FONT_OPTION")) : rb_funcall(rb_const_get(rb_class(), rb_intern("FONT_OPTION")), rb_intern("merge"), 1, font_option) +#define FO_ITALIC(op) ({VALUE _italic = rb_hash_aref(op, ID2SYM(rb_intern("italic"))); NIL_P(_italic) ? 0 : _italic == Qfalse ? 0 : 1;}) +#define FO_HSCALE(op) NUM2DBL(rb_hash_aref(op, ID2SYM(rb_intern("hscale")))) +#define FO_VSCALE(op) NUM2DBL(rb_hash_aref(op, ID2SYM(rb_intern("vscale")))) +#define FO_SHEAR(op) NUM2DBL(rb_hash_aref(op, ID2SYM(rb_intern("shear")))) +#define FO_THICKNESS(op) FIX2INT(rb_hash_aref(op, ID2SYM(rb_intern("thickness")))) +#define FO_LINE_TYPE(op) FIX2INT(rb_hash_aref(op, ID2SYM(rb_intern("line_type"))) == ID2SYM("aa") ? INT2FIX(CV_AA) : rb_hash_aref(op, ID2SYM(rb_intern("line_type")))) + + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_allocate(VALUE klass); +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); + +VALUE rb_face(VALUE self); +VALUE rb_hscale(VALUE self); +VALUE rb_vscale(VALUE self); +VALUE rb_shear(VALUE self); +VALUE rb_thickness(VALUE self); +VALUE rb_line_type(VALUE self); + +__NAMESPACE_END_CVFONT + +inline CvFont* +CVFONT(VALUE object) +{ + CvFont *ptr; + Data_Get_Struct(object, CvFont, ptr); + return ptr; +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVFONT_H diff --git a/ext/cvhaarclassifiercascade.cpp b/ext/cvhaarclassifiercascade.cpp new file mode 100644 index 00000000..27cf28a6 --- /dev/null +++ b/ext/cvhaarclassifiercascade.cpp @@ -0,0 +1,159 @@ +/************************************************************ + + cvhaarclassifercascade.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2007 Masakazu Yonekura + +************************************************************/ +#include "cvhaarclassifiercascade.h" +/* + * Document-class: OpenCV::CvHaarClassifierCascade + * + * CvHaarClassifierCascade object is "fast-object-detector". + * This detector can discover object (e.g. human's face) from image. + * + * Find face-area from picture "lena"... + * link:../images/face_detect_from_lena.jpg + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVHAARCLASSIFERCASCADE + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + + rb_klass = rb_define_class_under(opencv, "CvHaarClassifierCascade", rb_cObject); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_singleton_method(rb_klass, "load", RUBY_METHOD_FUNC(rb_load), 1); + rb_define_method(rb_klass, "detect_objects", RUBY_METHOD_FUNC(rb_detect_objects), -1); + rb_define_method(rb_klass, "detect_objects_with_pruning", RUBY_METHOD_FUNC(rb_detect_objects_with_pruning), -1); +} + +VALUE +rb_allocate(VALUE klass) +{ + return OPENCV_OBJECT(klass, 0); +} + +/* + * call-seq: + * CvHaarClassiferCascade.load(path) -> object-detector + * + * Load trained cascade of haar classifers from file. + * Object detection classifiers are stored in XML or YAML files. + * sample of object detection classifier files is included by OpenCV. + * + * You can found these at + * C:\Program Files\OpenCV\data\haarcascades\*.xml (Windows, default install path) + * + * e.g. you want to try to detect human's face. + * detector = CvHaarClassiferCascade.load("haarcascade_frontalface_alt.xml") + */ +VALUE +rb_load(VALUE klass, VALUE path) +{ + CvHaarClassifierCascade *cascade = (CvHaarClassifierCascade*)cvLoad(StringValueCStr(path), 0, 0, 0); + if(!CV_IS_HAAR_CLASSIFIER(cascade)) + rb_raise(rb_eTypeError, "invalid format haar classifier cascade file."); + return OPENCV_OBJECT(rb_klass, cascade); +} + +VALUE +rb_save(VALUE self, VALUE path) +{ + rb_raise(rb_eNotImpError, ""); +} + +/* + * call-seq: + * detect_objects(image[,scale_factor = 1.1, min_neighbor = 3, min_size = CvSize.new(0,0)]) -> cvseq(include CvAvgComp object) + * detect_objects(image[,scale_factor = 1.1, min_neighbor = 3, min_size = CvSize.new(0,0)]){|cmp| ... } -> cvseq(include CvAvgComp object) + * + * Detects objects in the image. This method finds rectangular regions in the + * given image that are likely to contain objects the cascade has been trained + * for and return those regions as a sequence of rectangles. + * + * * scale_factor (should be > 1.0) + * The factor by which the search window is scaled between the subsequent scans, for example, 1.1 mean increasing window by 10%. + * * min_neighbors + * Minimum number (minus 1) of neighbor rectangles that makes up an object. + * All the groups of a smaller number of rectangles than min_neighbors - 1 are rejected. + * If min_neighbors is 0, the function does not any grouping at all and returns all the detected + * candidate rectangles, whitch many be useful if the user wants to apply a customized grouping procedure. + * * min_size + * Minimum window size. By default, it is set to size of samples the classifier has been trained on. + */ +VALUE +rb_detect_objects(int argc, VALUE *argv, VALUE self) +{ + VALUE image, storage, scale_factor, min_neighbors, min_size, result; + rb_scan_args(argc, argv, "14", &image, &storage, &scale_factor, &min_neighbors, &min_size); + if (!rb_obj_is_kind_of(image, cCvMat::rb_class())) + rb_raise(rb_eTypeError, "argument 1(target-image) should be %s.", rb_class2name(cCvMat::rb_class())); + double scale = IF_DBL(scale_factor, 1.1); + if (!(scale > 1.0)) + rb_raise(rb_eArgError, "argument 2 (scale factor) must > 1.0."); + storage = CHECK_CVMEMSTORAGE(storage); + CvSeq *seq = cvHaarDetectObjects(CVMAT(image), CVHAARCLASSIFIERCASCADE(self), CVMEMSTORAGE(storage), + scale, IF_INT(min_neighbors, 3), 0, NIL_P(min_size) ? cvSize(0,0) : VALUE_TO_CVSIZE(min_size)); + result = cCvSeq::new_sequence(cCvSeq::rb_class(), seq, cCvAvgComp::rb_class(), storage); + if (rb_block_given_p()) { + for(int i = 0; i < seq->total; i++) + rb_yield(REFER_OBJECT(cCvAvgComp::rb_class(), cvGetSeqElem(seq, i), storage)); + } + return result; +} + +/* + * call-seq: + * detect_objects_with_pruning(image[,scale_factor = 1.1, min_neighbor = 3, min_size = CvSize.new(0,0)]) -> cvseq(include CvAvgComp object) + * detect_objects_with_pruning(image[,scale_factor = 1.1, min_neighbor = 3, min_size = CvSize.new(0,0)]){|cmp| ... } -> cvseq(include CvAvgComp object) + * + * Almost same to #detect_objects (Return detected objects). + * + * Before scanning to image, Canny edge detector to reject some image regions + * that contain too few or too much edges, and thus can not contain the searched object. + * + * note: The particular threshold values are tuned for face detection. + * And in this case the pruning speeds up the processing. + */ +VALUE +rb_detect_objects_with_pruning(int argc, VALUE *argv, VALUE self) +{ + VALUE image, storage, scale_factor, min_neighbors, min_size, result; + rb_scan_args(argc, argv, "14", &image, &storage, &scale_factor, &min_neighbors, &min_size); + if (!rb_obj_is_kind_of(image, cCvMat::rb_class())) + rb_raise(rb_eTypeError, "argument 1(target-image) should be %s.", rb_class2name(cCvMat::rb_class())); + double scale = IF_DBL(scale_factor, 1.1); + if (!(scale > 1.0)) + rb_raise(rb_eArgError, "argument 2 (scale factor) must > 1.0."); + storage = CHECK_CVMEMSTORAGE(storage); + CvSeq *seq = cvHaarDetectObjects(CVMAT(image), CVHAARCLASSIFIERCASCADE(self), CVMEMSTORAGE(storage), + scale, IF_INT(min_neighbors, 3), CV_HAAR_DO_CANNY_PRUNING, NIL_P(min_size) ? cvSize(0,0) : VALUE_TO_CVSIZE(min_size)); + result = cCvSeq::new_sequence(cCvSeq::rb_class(), seq, cCvAvgComp::rb_class(), storage); + if (rb_block_given_p()) { + for(int i = 0; i < seq->total; i++) + rb_yield(REFER_OBJECT(cCvAvgComp::rb_class(), cvGetSeqElem(seq, i), storage)); + } + return result; +} + +__NAMESPACE_END_CVHAARCLASSIFERCASCADE +__NAMESPACE_END_OPENCV diff --git a/ext/cvhaarclassifiercascade.h b/ext/cvhaarclassifiercascade.h new file mode 100644 index 00000000..c0fce6c2 --- /dev/null +++ b/ext/cvhaarclassifiercascade.h @@ -0,0 +1,41 @@ +/************************************************************ + + cvhaarclassifiercascade.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVHAARCLASSIFIERCASCADE_H +#define RUBY_OPENCV_CVHAARCLASSIFIERCASCADE_H + +#define __NAMESPACE_BEGIN_CVHAARCLASSIFERCASCADE namespace cCvHaarClassifierCascade{ +#define __NAMESPACE_END_CVHAARCLASSIFERCASCADE } + +#include"opencv.h" + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVHAARCLASSIFERCASCADE + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_allocate(VALUE klass); +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); + +VALUE rb_load(VALUE klass, VALUE path); +VALUE rb_save(VALUE self, VALUE name); +VALUE rb_detect_objects(int argc, VALUE *argv, VALUE self); +VALUE rb_detect_objects_with_pruning(int argc, VALUE *argv, VALUE self); + +__NAMESPACE_END_CVHAARCLASSIFERCASCADE +inline CvHaarClassifierCascade *CVHAARCLASSIFIERCASCADE(VALUE object){ + CvHaarClassifierCascade *ptr; + Data_Get_Struct(object, CvHaarClassifierCascade, ptr); + return ptr; +} +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVHAARCLASSIFIERCASCADE_H diff --git a/ext/cvhistogram.cpp b/ext/cvhistogram.cpp new file mode 100644 index 00000000..8738afad --- /dev/null +++ b/ext/cvhistogram.cpp @@ -0,0 +1,200 @@ +/************************************************************ + + cvhistogram.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2008 Masakazu Yonekura + +************************************************************/ +#include "cvhistogram.h" +/* + * Document-class: OpenCV::CvHistogram + * + * Muti-dimensional histogram. + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVHISTOGRAM + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + + rb_klass = rb_define_class_under(opencv, "CvHistogram", rb_cObject); + + rb_define_method(rb_klass, "is_uniform?", RUBY_METHOD_FUNC(rb_is_uniform), 0); + rb_define_method(rb_klass, "is_sparse?", RUBY_METHOD_FUNC(rb_is_sparse), 0); + rb_define_method(rb_klass, "has_range?", RUBY_METHOD_FUNC(rb_has_range), 0); + rb_define_method(rb_klass, "dims", RUBY_METHOD_FUNC(rb_dims), 0); + + rb_define_method(rb_klass, "normalize", RUBY_METHOD_FUNC(rb_normalize), 1); + rb_define_method(rb_klass, "normalize!", RUBY_METHOD_FUNC(rb_normalize_bang), 1); + rb_define_method(rb_klass, "thresh", RUBY_METHOD_FUNC(rb_thresh), 1); + rb_define_alias(rb_klass, "threshold", "thresh"); + rb_define_method(rb_klass, "thresh!", RUBY_METHOD_FUNC(rb_thresh_bang), 1); + rb_define_alias(rb_klass, "threshold!", "thresh!"); +} + +VALUE +rb_allocate(VALUE klass) +{ + // not yet + return Qnil; +} + +/* + * call-seq: + * is_uniform? -> true or false + * + */ +VALUE +rb_is_uniform(VALUE self) +{ + return CV_IS_UNIFORM_HIST(CVHISTOGRAM(self)) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * is_sparse? -> true or false + * + */ +VALUE +rb_is_sparse(VALUE self) +{ + return CV_IS_SPARSE_HIST(CVHISTOGRAM(self)) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * has_range? -> true or false + */ +VALUE +rb_has_range(VALUE self) +{ + return CV_HIST_HAS_RANGES(CVHISTOGRAM(self)) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * dims -> [int[,int...]] + */ +VALUE +rb_dims(VALUE self) +{ + int size[CV_MAX_DIM]; + int dims = cvGetDims(CVHISTOGRAM(self)->bins, size); + VALUE result = rb_ary_new2(dims); + for(int i = 0; i < dims; i++){ + rb_ary_store(result, i, INT2FIX(size[i])); + } + return result; +} + +/* + * call-seq: + * bins -> cvmatnd or cvsparsemat + */ +VALUE +rb_bins(VALUE self) +{ + CvHistogram *hist = CVHISTOGRAM(self); + return REFER_OBJECT(CV_IS_SPARSE_HIST(hist) ? cCvSparseMat::rb_class() : cCvMatND::rb_class(), hist->bins, self); +} + +/* + * call-seq: + * copy -> cvhist + * + * Clone histogram. + */ +VALUE +rb_copy(VALUE self) +{ + VALUE dest = 0; + CvHistogram *hist = CVHISTOGRAM(dest); + cvCopyHist(CVHISTOGRAM(self), &hist); + return dest; +} + +/* + * call-seq: + * clear! + * + * Sets all histogram bins to 0 in case of dense histogram and removes all histogram bins in case of sparse array. + */ +VALUE +rb_clear_bang(VALUE self) +{ + cvClearHist(CVHISTOGRAM(self)); + return self; +} + +/* + * call-seq: + * normalize(factor) -> cvhist + * + * Return normalized the histogram bins by scaling them, such that the sum of the bins becomes equal to factor. + */ +VALUE +rb_normalize(VALUE self, VALUE factor) +{ + return rb_normalize_bang(rb_copy(self), factor); +} + +/* + * call-seq: + * normalize!(factor) -> self + * + * normalizes the histogram bins by scaling them, such that the sum of the bins becomes equal to factor. + */ +VALUE +rb_normalize_bang(VALUE self, VALUE factor) +{ + cvNormalizeHist(CVHISTOGRAM(self), NUM2DBL(factor)); + return self; +} + +/* + * call-seq: + * thresh(factor) -> cvhist + * + * Return cleared histogram bins that are below the specified threshold. + */ +VALUE +rb_thresh(VALUE self, VALUE factor) +{ + return rb_thresh_bang(rb_copy(self), factor); +} + +/* + * call-seq: + * thresh!(factor) -> self + * + * Cleares histogram bins that are below the specified threshold. + */ +VALUE +rb_thresh_bang(VALUE self, VALUE factor) +{ + cvThreshHist(CVHISTOGRAM(self), NUM2DBL(factor)); + return self; +} + + +__NAMESPACE_END_CVHISTOGRAM +__NAMESPACE_END_OPENCV diff --git a/ext/cvhistogram.h b/ext/cvhistogram.h new file mode 100644 index 00000000..be486d45 --- /dev/null +++ b/ext/cvhistogram.h @@ -0,0 +1,51 @@ +/************************************************************ + + cvhistogram.h - + + $Author: lsxi $ + + Copyright (C) 2005-2008 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVHISTOGRAM_H +#define RUBY_OPENCV_CVHISTOGRAM_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVHISTOGRAM namespace cCvHistogram{ +#define __NAMESPACE_END_CVHISTOGRAM } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVHISTOGRAM + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_is_uniform(VALUE self); +VALUE rb_is_sparse(VALUE self); +VALUE rb_has_range(VALUE self); +VALUE rb_dims(VALUE self); +VALUE rb_bins(VALUE self); + +VALUE rb_clear(VALUE self); +VALUE rb_clear_bang(VALUE self); + +VALUE rb_normalize(VALUE self, VALUE factor); +VALUE rb_normalize_bang(VALUE self, VALUE factor); +VALUE rb_thresh(VALUE self, VALUE factor); +VALUE rb_thresh_bang(VALUE self, VALUE factor); + +__NAMESPACE_END_CVHISTOGRAM + +inline CvHistogram +*CVHISTOGRAM(VALUE object) +{ + CvHistogram *ptr; + Data_Get_Struct(object, CvHistogram, ptr); + return ptr; +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVHISTOGRAM_H diff --git a/ext/cvindex.cpp b/ext/cvindex.cpp new file mode 100644 index 00000000..99c91c02 --- /dev/null +++ b/ext/cvindex.cpp @@ -0,0 +1,73 @@ +/************************************************************ + + cvindex.cpp - + + $Author: lsxi $ + + Copyright (C) 2005 Masakazu Yonekura + +************************************************************/ +#include"cvindex.h" +/* + * Document-class: OpenCV::CvIndex + * + * + */ + +namespace mOpenCV{ + + namespace cCvIndex{ + VALUE rb_klass; + + VALUE rb_class(){ + return rb_klass; + } + + void define_ruby_class(){ + if(rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + rb_klass = rb_define_class_under(opencv, "CvIndex", rb_cObject); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_private_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); + rb_define_singleton_method(rb_klass, "cv_new", RUBY_METHOD_FUNC(rb_cv_new), -1); + rb_define_method(rb_klass, "value", RUBY_METHOD_FUNC(rb_value), 0); + rb_define_method(rb_klass, "to_s", RUBY_METHOD_FUNC(rb_to_s), 0); + } + + VALUE rb_allocate(VALUE klass){ + CvIndex *ptr; + return Data_Make_Struct(rb_klass, CvIndex, 0, free, ptr); + } + + VALUE rb_initialize(int argc, VALUE *argv, VALUE self){ + VALUE value; + if(rb_scan_args(argc, argv, "01", &value) > 0){ + Check_Type(value, T_FIXNUM); + CVINDEX(self)->value = FIX2INT(value); + } + return self; + } + + VALUE rb_cv_new(int argc, VALUE *argv, VALUE klass){ + VALUE object = rb_allocate(klass); + return rb_initialize(argc, argv, object); + } + + VALUE rb_value(VALUE self){ + return INT2FIX(CVINDEX(self)->value); + } + + VALUE rb_to_s(VALUE self){ + return rb_funcall(INT2FIX(CVINDEX(self)->value), rb_intern("to_s"), 0); + } + + } + + +} diff --git a/ext/cvindex.h b/ext/cvindex.h new file mode 100644 index 00000000..b415c9a1 --- /dev/null +++ b/ext/cvindex.h @@ -0,0 +1,40 @@ +/************************************************************ + + cvindex.h - + + $Author: lsxi $ + + Copyright (C) 2005 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVINDEX_H +#define RUBY_OPENCV_CVINDEX_H + +#include"opencv.h" + +namespace mOpenCV{ + + typedef struct CvIndex{ + int value; + }CvIndex; + + namespace cCvIndex{ + VALUE rb_class(); + + void define_ruby_class(); + + VALUE rb_allocate(VALUE klass); + VALUE rb_initialize(int argc, VALUE *argv, VALUE self); + VALUE rb_cv_new(int argc, VALUE *argv, VALUE klass); + VALUE rb_value(VALUE self); + VALUE rb_to_s(VALUE self); + } + + inline CvIndex *CVINDEX(VALUE object){ + CvIndex *ptr; + Data_Get_Struct(object, CvIndex, ptr); + return ptr; + } +} + +#endif // RUBY_OPENCV_CVINDEX_H diff --git a/ext/cvline.cpp b/ext/cvline.cpp new file mode 100644 index 00000000..bc592a89 --- /dev/null +++ b/ext/cvline.cpp @@ -0,0 +1,106 @@ +/************************************************************ + + cvline.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include "cvline.h" +/* + * Document-class: OpenCV::CvLine + * + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVLINE + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + + rb_klass = rb_define_class_under(opencv, "CvLine", rb_cObject); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_method(rb_klass, "rho", RUBY_METHOD_FUNC(rb_rho), 0); + rb_define_method(rb_klass, "rho=", RUBY_METHOD_FUNC(rb_set_rho), 1); + rb_define_method(rb_klass, "theta", RUBY_METHOD_FUNC(rb_theta), 0); + rb_define_method(rb_klass, "theta=", RUBY_METHOD_FUNC(rb_set_theta), 1); +} + +VALUE +rb_allocate(VALUE klass) +{ + CvLine *ptr; + return Data_Make_Struct(klass, CvLine, 0, -1, ptr); +} + +/* + * Return parameter on rho. + */ +VALUE +rb_rho(VALUE self) +{ + return rb_float_new(CVLINE(self)->rho); +} + +/* + * call-seq: + * rho = val + * + * Set rho parameter, return self. + */ +VALUE +rb_set_rho(VALUE self, VALUE rho) +{ + CVLINE(self)->rho = NUM2DBL(rho); + return self; +} + +/* + * Return parameter on theta. + */ +VALUE +rb_theta(VALUE self) +{ + return rb_float_new(CVLINE(self)->theta); +} + +/* + * call-seq: + * y = val + * + * Set theta parameter, return self. + */ +VALUE +rb_set_theta(VALUE self, VALUE theta) +{ + CVLINE(self)->theta = NUM2DBL(theta); + return self; +} + +VALUE +new_object(CvLine line) +{ + VALUE object = rb_allocate(rb_klass); + *CVLINE(object) = line; + return object; +} + +__NAMESPACE_END_CVLINE +__NAMESPACE_END_OPENCV diff --git a/ext/cvline.h b/ext/cvline.h new file mode 100644 index 00000000..6accb738 --- /dev/null +++ b/ext/cvline.h @@ -0,0 +1,52 @@ +/************************************************************ + + cvline.h - + + $Author: lsxi $ + + Copyright (C) 2007 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVLINE_H +#define RUBY_OPENCV_CVLINE_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVLINE namespace cCvLine{ +#define __NAMESPACE_END_CVLINE } + +__NAMESPACE_BEGIN_OPENCV + +typedef struct CvLine{ + float rho; + float theta; +} CvLine; + +__NAMESPACE_BEGIN_CVLINE + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_allocate(VALUE klass); +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); +VALUE rb_rho(VALUE self); +VALUE rb_set_rho(VALUE self, VALUE rho); +VALUE rb_theta(VALUE self); +VALUE rb_set_theta(VALUE self, VALUE theta); + +VALUE new_object(CvLine line); + +__NAMESPACE_END_CVLINE + +inline CvLine* +CVLINE(VALUE object) +{ + CvLine *ptr; + Data_Get_Struct(object, CvLine, ptr); + return ptr; +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVLINE_H diff --git a/ext/cvmat.cpp b/ext/cvmat.cpp new file mode 100644 index 00000000..d2a1280c --- /dev/null +++ b/ext/cvmat.cpp @@ -0,0 +1,4809 @@ +/************************************************************ + + cvmat.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2008 Masakazu Yonekura + +************************************************************/ +#include "cvmat.h" +/* + * Document-class: OpenCV::CvMat + * + * CvMat is basic 2D matrix class in OpenCV. + * + * C structure is here. + * typedef struct CvMat{ + * int type; + * int step; + * int *refcount; + * union + * { + * uchar *ptr; + * short *s; + * int *i; + * float *fl; + * double *db; + * } data; + * #ifdef __cplusplus + * union + * { + * int rows; + * int height; + * }; + * union + * { + * int cols; + * int width; + * }; + * #else + * int rows; // number of row + * int cols; // number of columns + * }CvMat; + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVMAT + +#define SUPPORT_8UC1_ONLY(value) if (cvGetElemType(CVARR(value)) != CV_8UC1) {rb_raise(rb_eNotImpError, "support single-channel 8bit unsigned image only.");} +#define SUPPORT_8U_ONLY(value) if (CV_MAT_DEPTH(cvGetElemType(CVARR(value))) != CV_8U) {rb_raise(rb_eNotImpError, "support 8bit unsigned image only.");} +#define SUPPORT_C1_ONLY(value) if (CV_MAT_CN(cvGetElemType(CVARR(value))) != 1) {rb_raise(rb_eNotImpError, "support single-channel image only.");} +#define SUPPORT_C1C3_ONLY(value) if (CV_MAT_CN(cvGetElemType(CVARR(value))) != 1 && CV_MAT_CN(cvGetElemType(CVARR(value))) != 3) {rb_raise(rb_eNotImpError, "support single-channel or 3-channnel image only.");} + +#define DRAWING_OPTION(op) NIL_P(op) ? rb_const_get(rb_class(), rb_intern("DRAWING_OPTION")) : rb_funcall(rb_const_get(rb_class(), rb_intern("DRAWING_OPTION")), rb_intern("merge"), 1, op) +#define DO_COLOR(op) VALUE_TO_CVSCALAR(rb_hash_aref(op, ID2SYM(rb_intern("color")))) +#define DO_THICKNESS(op) FIX2INT(rb_hash_aref(op, ID2SYM(rb_intern("thickness")))) +#define DO_LINE_TYPE(op) FIX2INT(rb_hash_aref(op, ID2SYM(rb_intern("line_type"))) == ID2SYM("aa") ? INT2FIX(CV_AA) : rb_hash_aref(op, ID2SYM(rb_intern("line_type")))) +#define DO_SHIFT(op) FIX2INT(rb_hash_aref(op, ID2SYM(rb_intern("shift")))) +#define DO_IS_CLOSED(op) ({VALUE _is_closed = rb_hash_aref(op, ID2SYM(rb_intern("is_closed"))); NIL_P(_is_closed) ? 0 : _is_closed == Qfalse ? 0 : 1;}) + +#define GOOD_FEATURES_TO_TRACK_OPTION(op) NIL_P(op) ? rb_const_get(rb_class(), rb_intern("GOOD_FEATURES_TO_TRACK_OPTION")) : rb_funcall(rb_const_get(rb_class(), rb_intern("GOOD_FEATURES_TO_TRACK_OPTION")), rb_intern("merge"), 1, op) +#define GF_MAX(op) FIX2INT(rb_hash_aref(op, ID2SYM(rb_intern("max")))) +#define GF_MASK(op) MASK(rb_hash_aref(op, ID2SYM(rb_intern("mask")))) +#define GF_BLOCK_SIZE(op) FIX2INT(rb_hash_aref(op, ID2SYM(rb_intern("block_size")))) +#define GF_USE_HARRIS(op) TRUE_OR_FALSE(rb_hash_aref(op, ID2SYM(rb_intern("use_harris"))), 0) +#define GF_K(op) NUM2DBL(rb_hash_aref(op, ID2SYM(rb_intern("k")))) + +#define FLOOD_FILL_OPTION(op) NIL_P(op) ? rb_const_get(rb_class(), rb_intern("FLOOD_FILL_OPTION")) : rb_funcall(rb_const_get(rb_class(), rb_intern("FLOOD_FILL_OPTION")), rb_intern("merge"), 1, op) +#define FF_CONNECTIVITY(op) NUM2INT(rb_hash_aref(op, ID2SYM(rb_intern("connectivity")))) +#define FF_FIXED_RANGE(op) TRUE_OR_FALSE(rb_hash_aref(op, ID2SYM(rb_intern("fixed_range"))), 0) +#define FF_MASK_ONLY(op) TRUE_OR_FALSE(rb_hash_aref(op, ID2SYM(rb_intern("mask_only"))), 0) + +#define FIND_CONTOURS_OPTION(op) NIL_P(op) ? rb_const_get(rb_class(), rb_intern("FIND_CONTOURS_OPTION")) : rb_funcall(rb_const_get(rb_class(), rb_intern("FIND_CONTOURS_OPTION")), rb_intern("merge"), 1, op) +#define FC_MODE(op) FIX2INT(rb_hash_aref(op, ID2SYM(rb_intern("mode")))) +#define FC_METHOD(op) FIX2INT(rb_hash_aref(op, ID2SYM(rb_intern("method")))) +#define FC_OFFSET(op)VALUE_TO_CVPOINT(rb_hash_aref(op, ID2SYM(rb_intern("offset")))) + +#define OPTICAL_FLOW_HS_OPTION(op) NIL_P(op) ? rb_const_get(rb_class(), rb_intern("OPTICAL_FLOW_HS_OPTION")) : rb_funcall(rb_const_get(rb_class(), rb_intern("OPTICAL_FLOW_HS_OPTION")), rb_intern("merge"), 1, op) +#define HS_LAMBDA(op) NUM2DBL(rb_hash_aref(op, ID2SYM(rb_intern("lambda")))) +#define HS_CRITERIA(op) VALUE_TO_CVTERMCRITERIA(rb_hash_aref(op, ID2SYM(rb_intern("criteria")))) + +#define OPTICAL_FLOW_BM_OPTION(op) NIL_P(op) ? rb_const_get(rb_class(), rb_intern("OPTICAL_FLOW_BM_OPTION")) : rb_funcall(rb_const_get(rb_class(), rb_intern("OPTICAL_FLOW_BM_OPTION")), rb_intern("merge"), 1, op) +#define BM_BLOCK_SIZE(op) VALUE_TO_CVSIZE(rb_hash_aref(op, ID2SYM(rb_intern("block_size")))) +#define BM_SHIFT_SIZE(op) VALUE_TO_CVSIZE(rb_hash_aref(op, ID2SYM(rb_intern("shift_size")))) +#define BM_MAX_RANGE(op) VALUE_TO_CVSIZE(rb_hash_aref(op, ID2SYM(rb_intern("max_range")))) + +#define FIND_FUNDAMENTAL_MAT_OPTION(op) NIL_P(op) ? rb_const_get(rb_class(), rb_intern("FIND_FUNDAMENTAL_MAT_OPTION")) : rb_funcall(rb_const_get(rb_class(), rb_intern("FIND_FUNDAMENTAL_MAT_OPTION")), rb_intern("merge"), 1, op) +#define FFM_WITH_STATUS(op) TRUE_OR_FALSE(rb_hash_aref(op, ID2SYM(rb_intern("with_status"))), 0) +#define FFM_MAXIMUM_DISTANCE(op) NUM2DBL(rb_hash_aref(op, ID2SYM(rb_intern("maximum_distance")))) +#define FFM_DESIRABLE_LEVEL(op) NUM2DBL(rb_hash_aref(op, ID2SYM(rb_intern("desirable_level")))) + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + + rb_klass = rb_define_class_under(opencv, "CvMat", rb_cObject); + rb_define_alloc_func(rb_klass, rb_allocate); + + VALUE drawing_option = rb_hash_new(); + rb_define_const(rb_klass, "DRAWING_OPTION", drawing_option); + rb_hash_aset(drawing_option, ID2SYM(rb_intern("color")), cCvScalar::new_object(cvScalarAll(0))); + rb_hash_aset(drawing_option, ID2SYM(rb_intern("thickness")), INT2FIX(1)); + rb_hash_aset(drawing_option, ID2SYM(rb_intern("line_type")), INT2FIX(8)); + rb_hash_aset(drawing_option, ID2SYM(rb_intern("shift")), INT2FIX(0)); + + VALUE good_features_to_track_option = rb_hash_new(); + rb_define_const(rb_klass, "GOOD_FEATURES_TO_TRACK_OPTION", good_features_to_track_option); + rb_hash_aset(good_features_to_track_option, ID2SYM(rb_intern("max")), INT2FIX(0xFF)); + rb_hash_aset(good_features_to_track_option, ID2SYM(rb_intern("mask")), Qnil); + rb_hash_aset(good_features_to_track_option, ID2SYM(rb_intern("block_size")), INT2FIX(3)); + rb_hash_aset(good_features_to_track_option, ID2SYM(rb_intern("use_harris")), Qfalse); + rb_hash_aset(good_features_to_track_option, ID2SYM(rb_intern("k")), rb_float_new(0.04)); + + VALUE flood_fill_option = rb_hash_new(); + rb_define_const(rb_klass, "FLOOD_FILL_OPTION", flood_fill_option); + rb_hash_aset(flood_fill_option, ID2SYM(rb_intern("connectivity")), INT2FIX(4)); + rb_hash_aset(flood_fill_option, ID2SYM(rb_intern("fixed_range")), Qfalse); + rb_hash_aset(flood_fill_option, ID2SYM(rb_intern("mask_only")), Qfalse); + + VALUE find_contours_option = rb_hash_new(); + rb_define_const(rb_klass, "FIND_CONTOURS_OPTION", find_contours_option); + rb_hash_aset(find_contours_option, ID2SYM(rb_intern("mode")), INT2FIX(CV_RETR_LIST)); + rb_hash_aset(find_contours_option, ID2SYM(rb_intern("method")), INT2FIX(CV_CHAIN_APPROX_SIMPLE)); + rb_hash_aset(find_contours_option, ID2SYM(rb_intern("offset")), cCvPoint::new_object(cvPoint(0,0))); + + VALUE optical_flow_hs_option = rb_hash_new(); + rb_define_const(rb_klass, "OPTICAL_FLOW_HS_OPTION", optical_flow_hs_option); + rb_hash_aset(optical_flow_hs_option, ID2SYM(rb_intern("lambda")), rb_float_new(0.0005)); + rb_hash_aset(optical_flow_hs_option, ID2SYM(rb_intern("criteria")), cCvTermCriteria::new_object(cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 1, 0.001))); + + VALUE optical_flow_bm_option = rb_hash_new(); + rb_define_const(rb_klass, "OPTICAL_FLOW_BM_OPTION", optical_flow_bm_option); + rb_hash_aset(optical_flow_bm_option, ID2SYM(rb_intern("block_size")), cCvSize::new_object(cvSize(4, 4))); + rb_hash_aset(optical_flow_bm_option, ID2SYM(rb_intern("shift_size")), cCvSize::new_object(cvSize(1, 1))); + rb_hash_aset(optical_flow_bm_option, ID2SYM(rb_intern("max_range")), cCvSize::new_object(cvSize(4, 4))); + + VALUE find_fundamental_matrix_option = rb_hash_new(); + rb_define_const(rb_klass, "FIND_FUNDAMENTAL_MAT_OPTION", find_fundamental_matrix_option); + rb_hash_aset(find_fundamental_matrix_option, ID2SYM(rb_intern("with_status")), Qfalse); + rb_hash_aset(find_fundamental_matrix_option, ID2SYM(rb_intern("maximum_distance")), rb_float_new(1.0)); + rb_hash_aset(find_fundamental_matrix_option, ID2SYM(rb_intern("desirable_level")), rb_float_new(0.99)); + + rb_define_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); + // Ruby/OpenCV original functions + rb_define_method(rb_klass, "method_missing", RUBY_METHOD_FUNC(rb_method_missing), -1); + rb_define_method(rb_klass, "to_s", RUBY_METHOD_FUNC(rb_to_s), 0); + rb_define_method(rb_klass, "has_parent?", RUBY_METHOD_FUNC(rb_has_parent_q), 0); + rb_define_method(rb_klass, "parent", RUBY_METHOD_FUNC(rb_parent), 0); + rb_define_method(rb_klass, "inside?", RUBY_METHOD_FUNC(rb_inside_q), 1); + rb_define_method(rb_klass, "to_IplConvKernel", RUBY_METHOD_FUNC(rb_to_IplConvKernel), 1); + rb_define_method(rb_klass, "create_mask", RUBY_METHOD_FUNC(rb_create_mask), 0); + + rb_define_method(rb_klass, "width", RUBY_METHOD_FUNC(rb_width), 0); + rb_define_alias(rb_klass, "columns", "width"); + rb_define_alias(rb_klass, "cols", "width"); + rb_define_method(rb_klass, "height", RUBY_METHOD_FUNC(rb_height), 0); + rb_define_alias(rb_klass, "rows", "height"); + rb_define_method(rb_klass, "depth", RUBY_METHOD_FUNC(rb_depth), 0); + rb_define_method(rb_klass, "channel", RUBY_METHOD_FUNC(rb_channel), 0); + rb_define_method(rb_klass, "data", RUBY_METHOD_FUNC(rb_data), 0); + + rb_define_method(rb_klass, "clone", RUBY_METHOD_FUNC(rb_clone), 0); + rb_define_method(rb_klass, "copy", RUBY_METHOD_FUNC(rb_copy), -1); + rb_define_method(rb_klass, "to_8u", RUBY_METHOD_FUNC(rb_to_8u), 0); + rb_define_method(rb_klass, "to_8s", RUBY_METHOD_FUNC(rb_to_8s), 0); + rb_define_method(rb_klass, "to_16u", RUBY_METHOD_FUNC(rb_to_16u), 0); + rb_define_method(rb_klass, "to_16s", RUBY_METHOD_FUNC(rb_to_16s), 0); + rb_define_method(rb_klass, "to_32s", RUBY_METHOD_FUNC(rb_to_32s), 0); + rb_define_method(rb_klass, "to_32f", RUBY_METHOD_FUNC(rb_to_32f), 0); + rb_define_method(rb_klass, "to_64f", RUBY_METHOD_FUNC(rb_to_64f), 0); + rb_define_method(rb_klass, "vector?", RUBY_METHOD_FUNC(rb_vector_q), 0); + rb_define_method(rb_klass, "square?", RUBY_METHOD_FUNC(rb_square_q), 0); + + rb_define_method(rb_klass, "to_CvMat", RUBY_METHOD_FUNC(rb_to_CvMat), 0); + rb_define_method(rb_klass, "sub_rect", RUBY_METHOD_FUNC(rb_sub_rect), -2); + rb_define_alias(rb_klass, "subrect", "sub_rect"); + rb_define_method(rb_klass, "slice_width", RUBY_METHOD_FUNC(rb_slice_width), 1); + rb_define_method(rb_klass, "slice_height", RUBY_METHOD_FUNC(rb_slice_height), 1); + rb_define_method(rb_klass, "row", RUBY_METHOD_FUNC(rb_row), -2); + rb_define_method(rb_klass, "col", RUBY_METHOD_FUNC(rb_col), -2); + rb_define_alias(rb_klass, "column", "col"); + rb_define_method(rb_klass, "each_row", RUBY_METHOD_FUNC(rb_each_row), 0); + rb_define_method(rb_klass, "each_col", RUBY_METHOD_FUNC(rb_each_col), 0); + rb_define_alias(rb_klass, "each_column", "each_col"); + rb_define_method(rb_klass, "diag", RUBY_METHOD_FUNC(rb_diag), -1); + rb_define_alias(rb_klass, "diagonal", "diag"); + rb_define_method(rb_klass, "size", RUBY_METHOD_FUNC(rb_size), 0); + rb_define_method(rb_klass, "dims", RUBY_METHOD_FUNC(rb_dims), 0); + rb_define_method(rb_klass, "dim_size", RUBY_METHOD_FUNC(rb_dim_size), 1); + rb_define_method(rb_klass, "[]", RUBY_METHOD_FUNC(rb_aref), -2); + rb_define_alias(rb_klass, "at", "[]"); + rb_define_method(rb_klass, "[]=", RUBY_METHOD_FUNC(rb_aset), -2); + rb_define_method(rb_klass, "fill", RUBY_METHOD_FUNC(rb_fill), -1); + rb_define_alias(rb_klass, "set", "fill"); + rb_define_method(rb_klass, "fill!", RUBY_METHOD_FUNC(rb_fill_bang), -1); + rb_define_alias(rb_klass, "set!", "fill!"); + rb_define_method(rb_klass, "clear", RUBY_METHOD_FUNC(rb_clear), 0); + rb_define_alias(rb_klass, "set_zero", "clear"); + rb_define_method(rb_klass, "clear!", RUBY_METHOD_FUNC(rb_clear_bang), 0); + rb_define_alias(rb_klass, "set_zero!", "clear!"); + rb_define_method(rb_klass, "identity", RUBY_METHOD_FUNC(rb_set_identity), -1); + rb_define_method(rb_klass, "identity!", RUBY_METHOD_FUNC(rb_set_identity_bang), -1); + rb_define_method(rb_klass, "range", RUBY_METHOD_FUNC(rb_range), -1); + rb_define_method(rb_klass, "range!", RUBY_METHOD_FUNC(rb_range_bang), -1); + + rb_define_method(rb_klass, "reshape", RUBY_METHOD_FUNC(rb_reshape), 1); + rb_define_method(rb_klass, "repeat", RUBY_METHOD_FUNC(rb_repeat), 1); + rb_define_method(rb_klass, "flip", RUBY_METHOD_FUNC(rb_flip), -1); + rb_define_method(rb_klass, "flip!", RUBY_METHOD_FUNC(rb_flip_bang), -1); + rb_define_method(rb_klass, "split", RUBY_METHOD_FUNC(rb_split), 0); + rb_define_singleton_method(rb_klass, "merge", RUBY_METHOD_FUNC(rb_merge), -2); + rb_define_method(rb_klass, "rand_shuffle", RUBY_METHOD_FUNC(rb_rand_shuffle), -1); + rb_define_method(rb_klass, "rand_shuffle!", RUBY_METHOD_FUNC(rb_rand_shuffle_bang), -1); + rb_define_method(rb_klass, "lut", RUBY_METHOD_FUNC(rb_lut), 1); + rb_define_method(rb_klass, "convert_scale", RUBY_METHOD_FUNC(rb_convert_scale), 1); + rb_define_method(rb_klass, "convert_scale_abs", RUBY_METHOD_FUNC(rb_convert_scale_abs), 1); + rb_define_method(rb_klass, "add", RUBY_METHOD_FUNC(rb_add), -1); + rb_define_alias(rb_klass, "+", "add"); + rb_define_method(rb_klass, "sub", RUBY_METHOD_FUNC(rb_sub), -1); + rb_define_alias(rb_klass, "-", "sub"); + rb_define_method(rb_klass, "mul", RUBY_METHOD_FUNC(rb_mul), -1); + rb_define_alias(rb_klass, "*", "mul"); + rb_define_method(rb_klass, "div", RUBY_METHOD_FUNC(rb_div), -1); + rb_define_alias(rb_klass, "/", "div"); + rb_define_method(rb_klass, "and", RUBY_METHOD_FUNC(rb_and), -1); + rb_define_alias(rb_klass, "&", "and"); + rb_define_method(rb_klass, "or", RUBY_METHOD_FUNC(rb_or), -1); + rb_define_alias(rb_klass, "|", "or"); + rb_define_method(rb_klass, "xor", RUBY_METHOD_FUNC(rb_xor), -1); + rb_define_alias(rb_klass, "^", "xor"); + rb_define_method(rb_klass, "not", RUBY_METHOD_FUNC(rb_not), 0); + rb_define_method(rb_klass, "not!", RUBY_METHOD_FUNC(rb_not_bang), 0); + rb_define_method(rb_klass, "eq", RUBY_METHOD_FUNC(rb_eq), 1); + rb_define_alias(rb_klass, "==", "eq"); + rb_define_method(rb_klass, "gt", RUBY_METHOD_FUNC(rb_gt), 1); + rb_define_alias(rb_klass, ">", "gt"); + rb_define_method(rb_klass, "ge", RUBY_METHOD_FUNC(rb_ge), 1); + rb_define_alias(rb_klass, ">=", "ge"); + rb_define_method(rb_klass, "lt", RUBY_METHOD_FUNC(rb_lt), 1); + rb_define_alias(rb_klass, "<", "lt"); + rb_define_method(rb_klass, "le", RUBY_METHOD_FUNC(rb_le), 1); + rb_define_alias(rb_klass, "<=", "le"); + rb_define_method(rb_klass, "ne", RUBY_METHOD_FUNC(rb_ne), 1); + rb_define_alias(rb_klass, "!=", "ne"); + rb_define_method(rb_klass, "in_range", RUBY_METHOD_FUNC(rb_in_range), 2); + rb_define_method(rb_klass, "abs_diff", RUBY_METHOD_FUNC(rb_abs_diff), 1); + rb_define_method(rb_klass, "count_non_zero", RUBY_METHOD_FUNC(rb_count_non_zero), 0); + rb_define_method(rb_klass, "sum", RUBY_METHOD_FUNC(rb_sum), 0); + rb_define_method(rb_klass, "avg", RUBY_METHOD_FUNC(rb_avg), -1); + rb_define_method(rb_klass, "avg_sdv", RUBY_METHOD_FUNC(rb_avg_sdv), -1); + rb_define_method(rb_klass, "sdv", RUBY_METHOD_FUNC(rb_sdv), -1); + rb_define_method(rb_klass, "min_max_loc", RUBY_METHOD_FUNC(rb_min_max_loc), -1); + rb_define_method(rb_klass, "dot_product", RUBY_METHOD_FUNC(rb_dot_product), 1); + rb_define_method(rb_klass, "cross_product", RUBY_METHOD_FUNC(rb_cross_product), 1); + rb_define_method(rb_klass, "transform", RUBY_METHOD_FUNC(rb_transform), -1); + rb_define_method(rb_klass, "perspective_transform", RUBY_METHOD_FUNC(rb_perspective_transform), 1); + rb_define_method(rb_klass, "mul_transposed", RUBY_METHOD_FUNC(rb_mul_transposed), -2); + rb_define_method(rb_klass, "trace", RUBY_METHOD_FUNC(rb_trace), 0); + rb_define_method(rb_klass, "transpose", RUBY_METHOD_FUNC(rb_transpose), 0); + rb_define_alias(rb_klass, "t", "transpose"); + rb_define_method(rb_klass, "transpose!", RUBY_METHOD_FUNC(rb_transpose_bang), 0); + rb_define_alias(rb_klass, "t!", "transpose!"); + rb_define_method(rb_klass, "det", RUBY_METHOD_FUNC(rb_det), 0); + rb_define_alias(rb_klass, "determinant", "det"); + rb_define_method(rb_klass, "invert", RUBY_METHOD_FUNC(rb_invert), -1); + rb_define_method(rb_klass, "solve", RUBY_METHOD_FUNC(rb_solve), -1); + rb_define_method(rb_klass, "svd", RUBY_METHOD_FUNC(rb_svd), -1); + rb_define_method(rb_klass, "svbksb", RUBY_METHOD_FUNC(rb_svbksb), -1); + rb_define_method(rb_klass, "eigenvv", RUBY_METHOD_FUNC(rb_eigenvv), -1); + rb_define_method(rb_klass, "eigenvv!", RUBY_METHOD_FUNC(rb_eigenvv_bang), -1); + rb_define_method(rb_klass, "calc_covar_matrix", RUBY_METHOD_FUNC(rb_calc_covar_matrix), -1); + rb_define_method(rb_klass, "mahalonobis", RUBY_METHOD_FUNC(rb_mahalonobis), -1); + + /* drawing function */ + rb_define_method(rb_klass, "line", RUBY_METHOD_FUNC(rb_line), -1); + rb_define_method(rb_klass, "line!", RUBY_METHOD_FUNC(rb_line_bang), -1); + rb_define_method(rb_klass, "rectangle", RUBY_METHOD_FUNC(rb_rectangle), -1); + rb_define_method(rb_klass, "rectangle!", RUBY_METHOD_FUNC(rb_rectangle_bang), -1); + rb_define_method(rb_klass, "circle", RUBY_METHOD_FUNC(rb_circle), -1); + rb_define_method(rb_klass, "circle!", RUBY_METHOD_FUNC(rb_circle_bang), -1); + rb_define_method(rb_klass, "ellipse", RUBY_METHOD_FUNC(rb_ellipse), -1); + rb_define_method(rb_klass, "ellipse!", RUBY_METHOD_FUNC(rb_ellipse_bang), -1); + rb_define_method(rb_klass, "ellipse_box", RUBY_METHOD_FUNC(rb_ellipse_box), -1); + rb_define_method(rb_klass, "ellipse_box!", RUBY_METHOD_FUNC(rb_ellipse_box_bang), -1); + rb_define_method(rb_klass, "fill_poly", RUBY_METHOD_FUNC(rb_fill_poly), -1); + rb_define_method(rb_klass, "fill_poly!", RUBY_METHOD_FUNC(rb_fill_poly_bang), -1); + rb_define_method(rb_klass, "fill_convex_poly", RUBY_METHOD_FUNC(rb_fill_convex_poly), -1); + rb_define_method(rb_klass, "fill_convex_poly!", RUBY_METHOD_FUNC(rb_fill_convex_poly_bang), -1); + rb_define_method(rb_klass, "poly_line", RUBY_METHOD_FUNC(rb_poly_line), -1); + rb_define_method(rb_klass, "poly_line!", RUBY_METHOD_FUNC(rb_poly_line_bang), -1); + rb_define_method(rb_klass, "put_text", RUBY_METHOD_FUNC(rb_put_text), -1); + rb_define_method(rb_klass, "put_text!", RUBY_METHOD_FUNC(rb_put_text_bang), -1); + + rb_define_method(rb_klass, "dft", RUBY_METHOD_FUNC(rb_dft), -1); + rb_define_method(rb_klass, "dct", RUBY_METHOD_FUNC(rb_dct), -1); + + rb_define_method(rb_klass, "sobel", RUBY_METHOD_FUNC(rb_sobel), -1); + rb_define_method(rb_klass, "laplace", RUBY_METHOD_FUNC(rb_laplace), -1); + rb_define_method(rb_klass, "canny", RUBY_METHOD_FUNC(rb_canny), -1); + rb_define_method(rb_klass, "pre_corner_detect", RUBY_METHOD_FUNC(rb_pre_corner_detect), -1); + rb_define_method(rb_klass, "corner_eigenvv", RUBY_METHOD_FUNC(rb_corner_eigenvv), -1); + rb_define_method(rb_klass, "corner_min_eigen_val", RUBY_METHOD_FUNC(rb_corner_min_eigen_val), -1); + rb_define_method(rb_klass, "corner_harris", RUBY_METHOD_FUNC(rb_corner_harris), -1); + rb_define_private_method(rb_klass, "__find_corner_sub_pix", RUBY_METHOD_FUNC(rbi_find_corner_sub_pix), -1); + rb_define_method(rb_klass, "good_features_to_track", RUBY_METHOD_FUNC(rb_good_features_to_track), -1); + + rb_define_method(rb_klass, "sample_line", RUBY_METHOD_FUNC(rb_sample_line), 2); + rb_define_method(rb_klass, "rect_sub_pix", RUBY_METHOD_FUNC(rb_rect_sub_pix), 2); + rb_define_method(rb_klass, "quadrangle_sub_pix", RUBY_METHOD_FUNC(rb_quadrangle_sub_pix), 2); + rb_define_method(rb_klass, "resize", RUBY_METHOD_FUNC(rb_resize), -1); + rb_define_method(rb_klass, "warp_affine", RUBY_METHOD_FUNC(rb_warp_affine), -1); + rb_define_singleton_method(rb_klass, "rotation", RUBY_METHOD_FUNC(rb_rotation), 3); + rb_define_method(rb_klass, "warp_perspective", RUBY_METHOD_FUNC(rb_warp_perspective), -1); + //rb_define_method(rb_klass, "get_perspective_transform", RUBY_METHOD_FUNC(rb_get_perspective_transform), -1); + //rb_define_alias(rb_klass, "warp_perspective_q_matrix", "get_perspective_transform"); + rb_define_method(rb_klass, "remap", RUBY_METHOD_FUNC(rb_remap), -1); + //rb_define_method(rb_klass, "log_polar", RUBY_METHOD_FUNC(rb_log_polar), -1); + + rb_define_method(rb_klass, "erode", RUBY_METHOD_FUNC(rb_erode), -1); + rb_define_method(rb_klass, "erode!", RUBY_METHOD_FUNC(rb_erode_bang), -1); + rb_define_method(rb_klass, "dilate", RUBY_METHOD_FUNC(rb_dilate), -1); + rb_define_method(rb_klass, "dilate!", RUBY_METHOD_FUNC(rb_dilate_bang), -1); + rb_define_method(rb_klass, "morphology_open", RUBY_METHOD_FUNC(rb_morphology_open), -1); + rb_define_method(rb_klass, "morphology_close", RUBY_METHOD_FUNC(rb_morphology_close), -1); + rb_define_method(rb_klass, "morphology_gradient", RUBY_METHOD_FUNC(rb_morphology_gradient), -1); + rb_define_method(rb_klass, "morphology_tophat", RUBY_METHOD_FUNC(rb_morphology_tophat), -1); + rb_define_method(rb_klass, "morphology_blackhat", RUBY_METHOD_FUNC(rb_morphology_blackhat), -1); + + rb_define_method(rb_klass, "smooth_blur_no_scale", RUBY_METHOD_FUNC(rb_smooth_blur_no_scale), -1); + rb_define_method(rb_klass, "smooth_blur", RUBY_METHOD_FUNC(rb_smooth_blur), -1); + rb_define_method(rb_klass, "smooth_gaussian", RUBY_METHOD_FUNC(rb_smooth_gaussian), -1); + rb_define_method(rb_klass, "smooth_median", RUBY_METHOD_FUNC(rb_smooth_median), -1); + rb_define_method(rb_klass, "smooth_bilateral", RUBY_METHOD_FUNC(rb_smooth_bilateral), -1); + rb_define_method(rb_klass, "filter2d", RUBY_METHOD_FUNC(rb_filter2d), -1); + rb_define_method(rb_klass, "copy_make_border_constant", RUBY_METHOD_FUNC(rb_copy_make_border_constant), -1); + rb_define_method(rb_klass, "copy_make_border_replicate", RUBY_METHOD_FUNC(rb_copy_make_border_replicate), -1); + rb_define_method(rb_klass, "integral", RUBY_METHOD_FUNC(rb_integral), -1); + rb_define_method(rb_klass, "threshold_binary", RUBY_METHOD_FUNC(rb_threshold_binary), -1); + rb_define_method(rb_klass, "threshold_binary_inverse", RUBY_METHOD_FUNC(rb_threshold_binary_inverse), -1); + rb_define_method(rb_klass, "threshold_trunc", RUBY_METHOD_FUNC(rb_threshold_trunc), -1); + rb_define_method(rb_klass, "threshold_to_zero", RUBY_METHOD_FUNC(rb_threshold_to_zero), -1); + rb_define_method(rb_klass, "threshold_to_zero_inverse", RUBY_METHOD_FUNC(rb_threshold_to_zero_inverse), -1); + + rb_define_method(rb_klass, "pyr_down", RUBY_METHOD_FUNC(rb_pyr_down), -1); + rb_define_method(rb_klass, "pyr_up", RUBY_METHOD_FUNC(rb_pyr_up), -1); + + rb_define_method(rb_klass, "flood_fill", RUBY_METHOD_FUNC(rb_flood_fill), -1); + rb_define_method(rb_klass, "flood_fill!", RUBY_METHOD_FUNC(rb_flood_fill_bang), -1); + rb_define_method(rb_klass, "find_contours", RUBY_METHOD_FUNC(rb_find_contours), -1); + rb_define_method(rb_klass, "find_contours!", RUBY_METHOD_FUNC(rb_find_contours_bang), -1); + rb_define_method(rb_klass, "pyr_segmentation", RUBY_METHOD_FUNC(rb_pyr_segmentation), -1); + rb_define_method(rb_klass, "pyr_mean_shift_filtering", RUBY_METHOD_FUNC(rb_pyr_mean_shift_filtering), -1); + rb_define_method(rb_klass, "watershed", RUBY_METHOD_FUNC(rb_watershed), 0); + + rb_define_method(rb_klass, "moments", RUBY_METHOD_FUNC(rb_moments), -1); + + rb_define_method(rb_klass, "hough_lines_standard", RUBY_METHOD_FUNC(rb_hough_lines_standard), -1); + rb_define_method(rb_klass, "hough_lines_probabilistic", RUBY_METHOD_FUNC(rb_hough_lines_probabilistic), -1); + rb_define_method(rb_klass, "hough_lines_multi_scale", RUBY_METHOD_FUNC(rb_hough_lines_multi_scale), -1); + rb_define_method(rb_klass, "hough_circles_gradient", RUBY_METHOD_FUNC(rb_hough_circles_gradient), -1); + //rb_define_method(rb_klass, "dist_transform", RUBY_METHOD_FUNC(rb_dist_transform), -1); + + rb_define_method(rb_klass, "inpaint_ns", RUBY_METHOD_FUNC(rb_inpaint_ns), 2); + rb_define_method(rb_klass, "inpaint_telea", RUBY_METHOD_FUNC(rb_inpaint_telea), 2); + + 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_i1", RUBY_METHOD_FUNC(rb_match_shapes_i1), -1); + rb_define_method(rb_klass, "match_shapes_i2", RUBY_METHOD_FUNC(rb_match_shapes_i2), -1); + rb_define_method(rb_klass, "match_shapes_i3", RUBY_METHOD_FUNC(rb_match_shapes_i3), -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); + rb_define_method(rb_klass, "snake_image", RUBY_METHOD_FUNC(rb_snake_image), -1); + + rb_define_method(rb_klass, "optical_flow_hs", RUBY_METHOD_FUNC(rb_optical_flow_hs), -1); + rb_define_method(rb_klass, "optical_flow_lk", RUBY_METHOD_FUNC(rb_optical_flow_lk), -1); + rb_define_method(rb_klass, "optical_flow_bm", RUBY_METHOD_FUNC(rb_optical_flow_bm), -1); + + rb_define_singleton_method(rb_klass, "find_fundamental_mat_7point", RUBY_METHOD_FUNC(rb_find_fundamental_mat_7point), -1); + rb_define_singleton_method(rb_klass, "find_fundamental_mat_8point", RUBY_METHOD_FUNC(rb_find_fundamental_mat_8point), -1); + rb_define_singleton_method(rb_klass, "find_fundamental_mat_ransac", RUBY_METHOD_FUNC(rb_find_fundamental_mat_ransac), -1); + rb_define_singleton_method(rb_klass, "find_fundamental_mat_lmeds", RUBY_METHOD_FUNC(rb_find_fundamental_mat_lmeds), -1); + rb_define_singleton_method(rb_klass, "compute_correspond_epilines", RUBY_METHOD_FUNC(rb_compute_correspond_epilines), 3); + + rb_define_method(rb_klass, "save_image", RUBY_METHOD_FUNC(rb_save_image), 1); +} + +VALUE +rb_allocate(VALUE klass) +{ + return OPENCV_OBJECT(klass, 0); +} + +/* + * call-seq: + * CvMat.new(row, col[, depth = CV_8U][, channel = 3]) -> cvmat + * + * Create col * row matrix. Each element set 0. + * + * Each element possigle range is set by depth. Default is unsigned 8bit. + * + * Number of channel is set by channel. channel should be 1..4. + * + */ +VALUE +rb_initialize(int argc, VALUE *argv, VALUE self) +{ + VALUE row, column, depth, channel; + rb_scan_args(argc, argv, "22", &row, &column, &depth, &channel); + DATA_PTR(self) = cvCreateMat(FIX2INT(row), FIX2INT(column), + CV_MAKETYPE(CVMETHOD("DEPTH", depth, CV_8U), argc < 4 ? 3 : FIX2INT(channel))); + return self; +} + +/* + * nodoc + */ +VALUE +rb_method_missing(int argc, VALUE *argv, VALUE self) +{ + /* + const char *to_str = "\\Ato_(\\w+)"; + VALUE name, args, str[3], method; + rb_scan_args(argc, argv, "1*", &name, &args); + if (RARRAY(args)->len != 0) + return rb_call_super(argc, argv); + if(rb_reg_match(rb_reg_new(to_str, strlen(to_str), 0), rb_funcall(name, rb_intern("to_s"), 0)) == Qnil) + return rb_call_super(argc, argv); + str[0] = rb_str_new2("%s2%s"); + str[1] = rb_color_model(self); + str[2] = rb_reg_nth_match(1, rb_backref_get()); + method = rb_f_sprintf(3, str); + if (rb_respond_to(rb_module_opencv(), rb_intern(StringValuePtr(method)))) + return rb_funcall(rb_module_opencv(), rb_intern(StringValuePtr(method)), 1, self); + return rb_call_super(argc, argv); + */ + VALUE name, args, method; + rb_scan_args(argc, argv, "1*", &name, &args); + method = rb_funcall(name, rb_intern("to_s"), 0); + if (RARRAY(args)->len != 0 || !rb_respond_to(rb_module_opencv(), rb_intern(StringValuePtr(method)))) + return rb_call_super(argc, argv); + return rb_funcall(rb_module_opencv(), rb_intern(StringValuePtr(method)), 1, self); +} + +/* + * call-seq: + * to_s -> string + * + * Return following string. + * m = CvMat.new(100, 100, :cv8u, 3) + * m.to_s # => + */ +VALUE +rb_to_s(VALUE self) +{ + const int i = 6; + VALUE str[i]; + str[0] = rb_str_new2("<%s:%dx%d,depth=%s,channel=%d>"); + str[1] = rb_str_new2(rb_class2name(CLASS_OF(self))); + str[2] = rb_width(self); + str[3] = rb_height(self); + str[4] = rb_depth(self); + str[5] = rb_channel(self); + return rb_f_sprintf(i, str); +} + +/* + * call-seq: + * has_parent? -> true or false + * + * Return true if this matrix has parent object, otherwise false. + */ +VALUE +rb_has_parent_q(VALUE self) +{ + return lookup_root_object(CVMAT(self)) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * parent -> obj or nil + * + * Return root object that refer this object. + */ +VALUE +rb_parent(VALUE self) +{ + VALUE root = lookup_root_object(CVMAT(self)); + return root ? root : Qnil; +} + +/* + * call-seq: + * inside?(obj) -> true or false + * + * + */ +VALUE +rb_inside_q(VALUE self, VALUE object) +{ + if (cCvPoint::rb_compatible_q(cCvPoint::rb_class(), object)) { + CvMat *mat = CVMAT(self); + int x = NUM2INT(rb_funcall(object, rb_intern("x"), 0)); + int y = NUM2INT(rb_funcall(object, rb_intern("y"), 0)); + if (cCvRect::rb_compatible_q(cCvRect::rb_class(), object)) { + int width = NUM2INT(rb_funcall(object, rb_intern("width"), 0)); + int height = NUM2INT(rb_funcall(object, rb_intern("height"), 0)); + return x >= 0 && y >= 0 && x < mat->width && x + width < mat->width && y < mat->height && y + height < mat->height ? Qtrue : Qfalse; + } else { + return x >= 0 && y >= 0 && x < mat->width && y < mat->height ? Qtrue : Qfalse; + } + } + rb_raise(rb_eArgError, "argument 1 should have method \"x\", \"y\""); +} + +/* + * call-seq: + * to_IplConvKernel -> iplconvkernel + * + * Create IplConvKernel from this matrix. + */ +VALUE +rb_to_IplConvKernel(VALUE self, VALUE anchor) +{ + CvMat *src = CVMAT(self); + CvPoint p = VALUE_TO_CVPOINT(anchor); + IplConvKernel *kernel = cvCreateStructuringElementEx(src->cols, src->rows, p.x, p.y, CV_SHAPE_CUSTOM, src->data.i); + return DEPEND_OBJECT(cIplConvKernel::rb_class(), kernel, self); +} + +/* + * call-seq: + * create_mask -> cvmat(single-channel 8bit unsinged image) + * + * Create single-channel 8bit unsinged image that filled 0. + */ +VALUE +rb_create_mask(VALUE self) +{ + VALUE mask = cCvMat::new_object(cvGetSize(CVARR(self)), CV_8UC1); + cvZero(CVARR(self)); + return mask; +} + +/* + * call-seq: + * width -> int + * + * Return number of columns. + */ +VALUE +rb_width(VALUE self) +{ + return INT2FIX(CVMAT(self)->width); +} + +/* + * call-seq: + * height -> int + * + * Return number of rows. + */ +VALUE +rb_height(VALUE self) +{ + return INT2FIX(CVMAT(self)->height); +} + +/* + * call-seq: + * depth -> symbol + * + * Return depth symbol. (see OpenCV::DEPTH) + */ +VALUE +rb_depth(VALUE self) +{ + return rb_hash_aref(rb_funcall(rb_const_get(rb_module_opencv(), rb_intern("DEPTH")), rb_intern("invert"), 0), INT2FIX(CV_MAT_DEPTH(CVMAT(self)->type))); +} + +/* + * call-seq: + * channel -> int (1 < channel < 4) + * + * Return number of channel. + */ +VALUE +rb_channel(VALUE self) +{ + return INT2FIX(CV_MAT_CN(CVMAT(self)->type)); +} + +/* + * call-seq: + * data -> binary (by String class) + * + * Return raw data of matrix. + */ +VALUE +rb_data(VALUE self) +{ + IplImage *image = IPLIMAGE(self); + return rb_str_new((char *)image->imageData, image->imageSize); +} + +/* + * call-seq: + * clone -> cvmat + * + * Clone matrix. The parent and child relation is not succeeded. + * Instance-specific method is succeeded. + * + * module M + * def example + * true + * end + * end + * + * mat.extend M + * mat.example #=> true + * clone = mat.clone + * clone.example #=> true + * copy = mat.copy + * copy.example #=> raise NoMethodError + */ +VALUE +rb_clone(VALUE self) +{ + VALUE clone = rb_obj_clone(self); + DATA_PTR(clone) = cvClone(CVARR(self)); + return clone; +} + +/* + * call-seq: + * copy() -> cvmat + * copy(mat) -> mat + * copy(val) -> array(include cvmat) + * + * Copy matrix. The parent and child relation is not succeeded. + * Instance-specific method is *NOT* succeeded. see also #clone. + * + * There are 3 kind behavior depending on the argument. + * + * copy() + * Return one copied matrix. + * copy(mat) + * Copy own elements to target matrix. Return nil. + * Size (or ROI) and channel and depth should be match. + * If own width or height does not match target matrix, raise CvUnmatchedSizes + * If own channel or depth does not match target matrix, raise CvUnmatchedFormats + * copy(val) + * The amounts of the specified number are copied. Return Array with copies. + * If you give the 0 or negative value. Return nil. + * mat.copy(3) #=> [mat1, mat2, mat3] + * mat.copy(-1) #=> nil + * + * When not apply to any, raise ArgumentError + */ +VALUE +rb_copy(int argc, VALUE *argv, VALUE self) +{ + VALUE value, copied; + CvMat *src = CVMAT(self); + rb_scan_args(argc, argv, "01", &value); + if (argc == 0) { + CvSize size = cvGetSize(src); + copied = new_object(cvGetSize(src), cvGetElemType(src)); + cvCopy(src, CVMAT(copied)); + return copied; + }else{ + if (rb_obj_is_kind_of(value, rb_klass)) { + cvCopy(src, CVMAT(value)); + return Qnil; + }else if (rb_obj_is_kind_of(value, rb_cFixnum)) { + int n = FIX2INT(value); + if (n > 0) { + copied = rb_ary_new2(n); + for (int i = 0; i < n; i++) { + rb_ary_store(copied, i, new_object(src->rows, src->cols, cvGetElemType(src))); + } + return copied; + }else{ + return Qnil; + } + }else + rb_raise(rb_eArgError, ""); + } +} + +VALUE +copy(VALUE mat) +{ + CvMat *src = CVMAT(mat); + VALUE copied = new_object(cvGetSize(src), cvGetElemType(src)); + cvCopy(src, CVMAT(copied)); + return copied; +} + + +/* + * call-seq: + * to_8u -> cvmat(depth = CV_8U) + * + * Return the new matrix that elements is converted to unsigned 8bit. + */ +VALUE +rb_to_8u(VALUE self) +{ + CvMat *src = CVMAT(self); + VALUE dest = new_object(src->rows, src->cols, CV_MAKETYPE(CV_8U, CV_MAT_CN(src->type))); + cvConvert(src, CVMAT(dest)); + return dest; +} + +/* + * call-seq: + * to_8s -> cvmat(depth = CV_8S) + * + * Return the new matrix that elements is converted to signed 8bit. + */ +VALUE +rb_to_8s(VALUE self) +{ + CvMat *src = CVMAT(self); + VALUE dest = new_object(src->rows, src->cols, CV_MAKETYPE(CV_8S, CV_MAT_CN(src->type))); + cvConvert(src, CVMAT(dest)); + return dest; +} + +/* + * call-seq: + * to_16u -> cvmat(depth = CV_16U) + * + * Return the new matrix that elements is converted to unsigned 16bit. + */ +VALUE rb_to_16u(VALUE self) +{ + CvMat *src = CVMAT(self); + VALUE dest = new_object(src->rows, src->cols, CV_MAKETYPE(CV_16U, CV_MAT_CN(src->type))); + cvConvert(src, CVMAT(dest)); + return dest; +} + +/* + * call-seq: + * to_16s -> cvmat(depth = CV_16s) + * + * Return the new matrix that elements is converted to signed 16bit. + */ +VALUE +rb_to_16s(VALUE self) +{ + CvMat *src = CVMAT(self); + VALUE dest = new_object(src->rows, src->cols, CV_MAKETYPE(CV_16U, CV_MAT_CN(src->type))); + cvConvert(src, CVMAT(dest)); + return dest; +} + +/* + * call-seq: + * to_32s -> cvmat(depth = CV_32S) + * + * Return the new matrix that elements is converted to signed 32bit. + */ +VALUE +rb_to_32s(VALUE self) +{ + CvMat *src = CVMAT(self); + VALUE dest = new_object(src->rows, src->cols, CV_MAKETYPE(CV_32S, CV_MAT_CN(src->type))); + cvConvert(src, CVMAT(dest)); + return dest; +} + +/* + * call-seq: + * to_32f -> cvmat(depth = CV_32F) + * + * Return the new matrix that elements is converted to 32bit floating-point. + */ +VALUE +rb_to_32f(VALUE self) +{ + CvMat *src = CVMAT(self); + VALUE dest = new_object(src->rows, src->cols, CV_MAKETYPE(CV_32F, CV_MAT_CN(src->type))); + cvConvert(src, CVMAT(dest)); + return dest; +} + +/* + * call-seq: + * to_64F -> cvmat(depth = CV_64F) + * + * Return the new matrix that elements is converted to 64bit floating-point. + */ +VALUE +rb_to_64f(VALUE self) +{ + CvMat *src = CVMAT(self); + VALUE dest = new_object(src->rows, src->cols, CV_MAKETYPE(CV_64F, CV_MAT_CN(src->type))); + cvConvert(src, CVMAT(dest)); + return dest; +} + +/* + * call-seq: + * vector? -> true or false + * + * If #width or #height is 1, return true. Otherwise return false. + */ +VALUE +rb_vector_q(VALUE self) +{ + CvMat *mat = CVMAT(self); + return (mat->width == 1|| mat->height == 1) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * square? -> true or false + * + * If #width == #height return true. Otherwise return false. + */ +VALUE +rb_square_q(VALUE self) +{ + CvMat *mat = CVMAT(self); + return mat->width == mat->height ? Qtrue : Qfalse; +} + +/************************************************************ + cxcore function +************************************************************/ +/* + * Return CvMat object with reference to caller-object. + * + * src = CvMat.new(10, 10) + * src.has_parent? #=> false + * src.parent #=> nil + * mat = src.to_CvMat + * mat.has_parent? #=> true + * mat.parent #=> CvMat object "src" + * + * This case, 'src' is root-object. and 'mat' is child-object refer to 'src'. + * src <=refer= mat + * In C, 'src->data' and 'mat->data' is common. Therefore, they cause the change each other. + * object 'src' don't GC. + */ +VALUE +rb_to_CvMat(VALUE self) +{ + return DEPEND_OBJECT(rb_klass, cvGetMat(CVARR(self), CVALLOC(CvMat)), self); +} + +/* + * call-seq: + * sub_rect(rect) -> cvmat + * sub_rect(topleft, size) -> cvmat + * sub_rect(x, y, width, height) -> cvmat + * + * Return parts of self as CvMat. + * + * p or x,y mean top-left coordinate. + * size or width,height is size. + * + * link:../images/CvMat_sub_rect.png + */ +VALUE +rb_sub_rect(VALUE self, VALUE args) +{ + CvRect area; + CvPoint topleft; + CvSize size; + switch(RARRAY(args)->len) { + case 1: + area = VALUE_TO_CVRECT(RARRAY(args)->ptr[0]); + break; + case 2: + topleft = VALUE_TO_CVPOINT(RARRAY(args)->ptr[0]); + size = VALUE_TO_CVSIZE(RARRAY(args)->ptr[1]); + area.x = topleft.x; + area.y = topleft.y; + area.width = size.width; + area.height = size.height; + break; + case 4: + area.x = NUM2INT(RARRAY(args)->ptr[0]); + area.y = NUM2INT(RARRAY(args)->ptr[1]); + area.width = NUM2INT(RARRAY(args)->ptr[2]); + area.height = NUM2INT(RARRAY(args)->ptr[3]); + break; + default: + rb_raise(rb_eArgError, "wrong number of arguments (%d of 1 or 2 or 4)", RARRAY(args)->len); + } + return DEPEND_OBJECT(rb_klass, + cvGetSubRect(CVARR(self), CVALLOC(CvMat), area), + self); +} + +/* + * call-seq: + * slice_width(n) + * + * The matrix is divided into n piece by the width. + * If it cannot be just divided, warning is displayed. + * + * e.g. + * m = OpenCV::CvMat.new(10, 10) #=> size 10x10 matrix + * ml, mr = m.slice_width(2) #=> 5x10 and 5x10 matrix + * + * ml, mm, mr = m.sclice_width(3)#=> 3x10 3x10 3x10 matrix + * warning : width does not div correctly. + */ +VALUE +rb_slice_width(VALUE self, VALUE num) +{ + int n = NUM2INT(num); + if (n < 1) {rb_raise(rb_eArgError, "number of piece should be > 0");} + CvSize size = cvGetSize(CVARR(self)); + if (size.width % n != 0) {rb_warn("width does not div correctly.");} + int div_x = size.width / n; + VALUE ary = rb_ary_new2(n); + for (int i = 0; i < n; i++) { + CvRect rect = {div_x * i, 0, div_x, size.height}; + rb_ary_push(ary, DEPEND_OBJECT(rb_klass, cvGetSubRect(CVARR(self), CVALLOC(CvMat), rect), self)); + } + return ary; +} + +/* + * call-seq: + * slice_height(n) + * + * The matrix is divided into n piece by the height. + * If it cannot be just divided, warning is displayed. + * + * see also #slice_width. + */ +VALUE +rb_slice_height(VALUE self, VALUE num) +{ + int n = NUM2INT(num); + if (n < 1) {rb_raise(rb_eArgError, "number of piece should be > 0");} + CvSize size = cvGetSize(CVARR(self)); + if (size.height % n != 0) {rb_warn("height does not div correctly.");} + int div_y = size.height / n; + VALUE ary = rb_ary_new2(n); + for (int i = 0; i < n; i++) { + CvRect rect = {0, div_y * i, size.width, div_y}; + rb_ary_push(ary, DEPEND_OBJECT(rb_klass, cvGetSubRect(CVARR(self), CVALLOC(CvMat), rect), self)); + } + return ary; +} + +/* + * call-seq: + * row(n) -> Return row + * row(n1, n2, ...) -> Return Array of row + * + * Return row(or rows) of matrix. + * argument should be Fixnum or CvSlice compatible object. + */ +VALUE +rb_row(VALUE self, VALUE args) +{ + int len = RARRAY(args)->len; + if (len < 1) {rb_raise(rb_eArgError, "wrong number of argument.(more than 1)");} + VALUE ary = rb_ary_new2(len); + for (int i = 0; i < len; i++) { + VALUE value = rb_ary_entry(args, i); + if (FIXNUM_P(value)) { + rb_ary_store(ary, i, DEPEND_OBJECT(rb_klass, cvGetRow(CVARR(self), CVALLOC(CvMat), FIX2INT(value)), self)); + }else{ + CvSlice slice = VALUE_TO_CVSLICE(value); + rb_ary_store(ary, i, DEPEND_OBJECT(rb_klass, cvGetRows(CVARR(self), CVALLOC(CvMat), slice.start_index, slice.end_index), self)); + } + } + return RARRAY(ary)->len > 1 ? ary : rb_ary_entry(ary, 0); +} + +/* + * call-seq: + * col(n) -> Return column + * col(n1, n2, ...) -> Return Array of columns + * + * Return column(or columns) of matrix. + * argument should be Fixnum or CvSlice compatible object. + */ +VALUE +rb_col(VALUE self, VALUE args) +{ + int len = RARRAY(args)->len; + if (len < 1) {rb_raise(rb_eArgError, "wrong number of argument.(more than 1)");} + VALUE ary = rb_ary_new2(len); + for (int i = 0; i < len; i++) { + VALUE value = rb_ary_entry(args, i); + if (FIXNUM_P(value)) { + rb_ary_store(ary, i, DEPEND_OBJECT(rb_klass, cvGetCol(CVARR(self), CVALLOC(CvMat), FIX2INT(value)), self)); + }else{ + CvSlice slice = VALUE_TO_CVSLICE(value); + rb_ary_store(ary, i, DEPEND_OBJECT(rb_klass, cvGetCols(CVARR(self), CVALLOC(CvMat), slice.start_index, slice.end_index), self)); + } + } + return RARRAY(ary)->len > 1 ? ary : rb_ary_entry(ary, 0); +} + +/* + * call-seq: + * each_row{|row| ... } -> self + * + * Calls block once for each row in self, passing that element as a parameter. + * + * see also CvMat#each_col + */ +VALUE +rb_each_row(VALUE self) +{ + int rows = CVMAT(self)->rows; + for (int i = 0; i < rows; i++) { + rb_yield(DEPEND_OBJECT(rb_klass, cvGetRow(CVARR(self), CVALLOC(CvMat), i), self)); + } + return self; +} + +/* + * call-seq: + * each_col{|col| ... } -> self + * + * Calls block once for each column in self, passing that element as a parameter. + * + * see also CvMat#each_row + */ +VALUE +rb_each_col(VALUE self) +{ + int cols = CVMAT(self)->cols; + for (int i = 0; i < cols; i++) { + rb_yield(DEPEND_OBJECT(rb_klass, cvGetCol(CVARR(self), CVALLOC(CvMat), i), self)); + } + return self; +} + +/* + * call-seq: + * diag([val = 0]) -> cvmat + * + * Return one of array diagonals. + * val is zeo corresponds to the main diagonal, -1 corresponds to the diagonal above the main etc, 1 corresponds to the diagonal below the main etc. + * + */ +VALUE +rb_diag(int argc, VALUE *argv, VALUE self) +{ + VALUE val; + if (rb_scan_args(argc, argv, "01", &val) < 1) { + val = INT2FIX(0); + } + return DEPEND_OBJECT(rb_klass, cvGetDiag(CVARR(self), CVALLOC(CvMat), NUM2INT(val)), self); +} + +/* + * call-seq: + * size -> cvsize + * + * Return size by CvSize + */ +VALUE +rb_size(VALUE self) +{ + return cCvSize::new_object(cvGetSize(CVARR(self))); +} + +/* + VALUE rb_elem_type(VALUE self) { + return INT2FIX(cvGetElemType(CVARR(self))); + } +*/ + +/* + * call-seq: + * dims -> array(int, int, ...) + * + * Return number of array dimensions and their sizes or the size of particular dimension. + * In case of CvMat it always returns 2 regardless of number of matrix rows. + */ +VALUE +rb_dims(VALUE self) +{ + int size[CV_MAX_DIM]; + int dims = cvGetDims(CVARR(self), size); + VALUE ary = rb_ary_new2(dims); + for (int i = 0; i < dims; i++) { + rb_ary_store(ary, i, INT2FIX(size[i])); + } + return ary; +} + +/* + * call-seq: + * dim_size(index) -> int + * + * Return number of dimension. + * almost same as CvMat#dims[index]. + * If the dimension specified with index doesn't exist, CvStatusOutOfRange raise. + */ +VALUE +rb_dim_size(VALUE self, VALUE index) +{ + return INT2FIX(cvGetDimSize(CVARR(self), FIX2INT(index))); +} + +/* + * call-seq: + * [idx1[,idx2]...] + * + * Return value of the particular array element as CvScalar. + */ +VALUE +rb_aref(VALUE self, VALUE args) +{ + int index[CV_MAX_DIM]; + for (int i = 0; i < RARRAY(args)->len; i++) { + index[i] = NUM2INT(rb_ary_entry(args, i)); + } + CvScalar scalar = cvScalarAll(0); + switch(RARRAY(args)->len) { + case 1: + scalar = cvGet1D(CVARR(self), index[0]); + break; + case 2: + scalar = cvGet2D(CVARR(self), index[1], index[0]); + break; + case 3: + scalar = cvGet3D(CVARR(self), index[2], index[1], index[0]); + break; + default: + scalar = cvGetND(CVARR(self), index); + } + return cCvScalar::new_object(scalar); +} + +/* + * call-seq: + * [idx1[,idx2]...] = value + * + * Set value of the particular array element to value. + * value should be CvScalar. + */ +VALUE +rb_aset(VALUE self, VALUE args) +{ + CvScalar scalar = VALUE_TO_CVSCALAR(rb_ary_pop(args)); + int index[CV_MAX_DIM]; + for (int i = 0; i < RARRAY(args)->len; i++) { + index[i] = NUM2INT(rb_ary_entry(args, i)); + } + switch(RARRAY(args)->len) { + case 1: + cvSet1D(CVARR(self), index[0], scalar); + break; + case 2: + cvSet2D(CVARR(self), index[1], index[0], scalar); + break; + case 3: + cvSet3D(CVARR(self), index[2], index[1], index[0], scalar); + break; + default: + cvSetND(CVARR(self), index, scalar); + } + return self; +} + +/* + * call-seq: + * fill(value[, mask]) -> cvmat + * + * Return CvMat copied value to every selected element. value should be CvScalar or compatible object. + * self[I] = value if mask(I)!=0 + * + * note: This method support ROI on IplImage class. but COI not support. COI should not be set. + * image = IplImage.new(10, 20) #=> create 3 channel image. + * image.coi = 1 #=> set COI + * image.fill(CvScalar.new(10, 20, 30)) #=> raise CvBadCOI error. + */ +VALUE +rb_fill(int argc, VALUE *argv, VALUE self) +{ + return rb_fill_bang(argc, argv, copy(self)); +} + +/* + * call-seq: + * fill!(value[, mask]) -> self + * + * Copie value to every selected element. + * self[I] = value if mask(I)!=0 + * + * see also #fill. + */ +VALUE +rb_fill_bang(int argc, VALUE *argv, VALUE self) +{ + VALUE value, mask; + rb_scan_args(argc, argv, "11", &value, &mask); + cvSet(CVARR(self), VALUE_TO_CVSCALAR(value), MASK(mask)); + return self; +} + +/* + * call-seq: + * save_image(filename) -> self + * + * Saves an image to file. The image format is chosen depending on the filename extension. + * Only 8bit single-channel or 3-channel(with 'BGR' channel order) image can be saved. + * + * e.g. + * image = OpenCV::CvMat.new(10, 10, CV_8U, 3) + * image.save_image("image.jpg") #=> save as JPEG format + * image.save_image("image.png") #=> save as PNG format + */ +VALUE +rb_save_image(VALUE self, VALUE filename) +{ + Check_Type(filename, T_STRING); + cvSaveImage(StringValueCStr(filename), CVARR(self)); + return self; +} + +/* + * call-seq: + * clear -> cvmat + * + * Return new matrix all element-value cleared. + */ +VALUE +rb_clear(VALUE self) +{ + return rb_clear_bang(copy(self)); +} + +/* + * call-seq: + * clear! -> self + * + * Clear all element-value. Return self. + */ +VALUE +rb_clear_bang(VALUE self) +{ + cvSetZero(CVARR(self)); + return self; +} + +/* + * call-seq: + * identity([val = [1]]) -> cvmat + * + * Return initializes scaled identity matrix. + * val should be CvScalar. + * + * arr(i, j) = val if i = j, 0 otherwise + */ +VALUE +rb_set_identity(int argc, VALUE *argv, VALUE self) +{ + return rb_set_identity_bang(argc, argv, copy(self)); +} + +/* + * call-seq: + * identity!([val = [1]]) -> self + * + * Initialize scaled identity matrix. + * val should be CvScalar. + * + * arr(i, j) = val if i = j, 0 otherwise + */ +VALUE +rb_set_identity_bang(int argc, VALUE *argv, VALUE self) +{ + VALUE val; + CvScalar value; + if (rb_scan_args(argc, argv, "01", &val) < 1) { + value = cvRealScalar(1); + }else{ + value = VALUE_TO_CVSCALAR(val); + } + cvSetIdentity(CVARR(self), value); + return self; +} + +/* + * call-seq: + * range(start, end) -> cvmat + * + * Create and return filled matrix with given range of numbers. + * + * see range! + */ +VALUE +rb_range(int argc, VALUE *argv, VALUE self) +{ + return rb_range_bang(argc, argv, copy(self)); +} + +/* + * call-seq: + * range!(start, end) -> self + * + * Fills matrix with given range of numbers. + * + * initializes the matrix as following: + * arr(i,j)=(end-start)*(i*cols(arr)+j)/(cols(arr)*rows(arr)) + * For example, the following code will initilize 1D vector with subsequent integer numbers. + * m = CvMat.new(1, 10, :cv32s) + * m.range!(0, m.cols); // m will be initialized as [0,1,2,3,4,5,6,7,8,9] + */ +VALUE +rb_range_bang(int argc, VALUE *argv, VALUE self) +{ + VALUE start, end; + rb_scan_args(argc, argv, "20", &start, &end); + cvRange(CVARR(self), NUM2DBL(start), NUM2DBL(end)); + return self; +} + + + + +/* + * call-seq: + * reshape([:rows => num][, :channel => cn]) -> cvmat(refer self) + * + * Change shape of matrix/image without copying data. + * + * e.g. + * mat = CvMat.new(3, 3, CV_8U, 3) #=> 3x3 3-channel matrix + * vec = mat.reshape(:rows => 1) #=> 1x9 3-channel matrix + * ch1 = mat.reshape(:channel => 1) #=> 9x9 1-channel matrix + */ +VALUE +rb_reshape(VALUE self, VALUE hash) +{ + if (TYPE(hash) != T_HASH) + rb_raise(rb_eTypeError, "argument should be Hash that contaion key (:row, :channel)."); + VALUE channel = rb_hash_aref(hash, ID2SYM(rb_intern("channel"))); + VALUE rows = rb_hash_aref(hash, ID2SYM(rb_intern("rows"))); + return DEPEND_OBJECT(rb_klass, cvReshape(CVARR(self), CVALLOC(CvMat), NIL_P(rows) ? 0 : FIX2INT(rows), NIL_P(channel) ? 0 : FIX2INT(channel)), self); +} + +/* + * call-seq: + * repeat(mat) -> cvmat + * + * Tiled mat by self. + */ +VALUE +rb_repeat(VALUE self, VALUE object) +{ + if (rb_obj_is_kind_of(object, rb_class())) + rb_raise(rb_eTypeError, "argument should be CvMat subclass."); + cvRepeat(CVARR(self), CVARR(object)); + return object; +} + +/* + * call-seq: + * flip(:x) -> cvmat + * flip(:y) -> cvmat + * flip -> -> cvmat + * + * Return new flipped 2D array. + * * flip(:x) - flip around horizontal + * * flip(:y) - flip around vertical + * * flip - flip around both axises + */ +VALUE +rb_flip(int argc, VALUE *argv, VALUE self) +{ + return rb_flip_bang(argc, argv, copy(self)); +} + +/* + * call-seq: + * flip!(:x) -> self + * flip!(:y) -> self + * flip! -> self + * + * Flip 2D array. Return self. + * + * see also CvMat#flip + */ +VALUE +rb_flip_bang(int argc, VALUE *argv, VALUE self) +{ + VALUE format; + int mode = -1; + if (rb_scan_args(argc, argv, "01", &format) > 0) { + if (rb_to_id(format) == rb_intern("x")) + mode = 1; + else if (rb_to_id(format) == rb_intern("y")) + mode = 0; + else + rb_warn("argument may be :x or :y"); + } + cvFlip(CVARR(self), NULL, mode); + return self; +} + +/* + * call-seq: + * split -> array(include cvmat) + * + * Divides multi-channel array into several single-chanel arrays. + * + * e.g. + * image = CvMat.new 640, 480, CV_8U, 3 #=> 3-channel image + * image.split #=> [image1, image2, image3] : each image have single-channel + * + * e.g. switch red <-> blue channel. + * image = IplImage.load "sample.bmp" + * i = image.split + * new_image = CvMat.merge i[2], i[1], i[0] + */ +VALUE +rb_split(VALUE self) +{ + int type = CVMAT(self)->type, depth = CV_MAT_DEPTH(type), channel = CV_MAT_CN(type); + CvSize size = cvGetSize(CVARR(self)); + CvMat *dest[] = {NULL, NULL, NULL, NULL}; + for (int i = 0; i < channel; i++) + dest[i] = cvCreateMat(size.height, size.width, CV_MAKETYPE(depth, 1)); + cvSplit(CVARR(self), dest[0], dest[1], dest[2], dest[3]); + VALUE ary = rb_ary_new2(channel); + for (int i = 0; i < channel; i++) + rb_ary_store(ary, i, OPENCV_OBJECT(rb_klass, dest[i])); + return ary; +} + +/* + * call-seq: + * CvMat.merge(mat1[,mat2][,mat3][,mat4]) -> cvmat + * + * Composes multi-channel array from several single-channel arrays. + * Each argument should be single-channel image(CvMat or subclass). + * All image should be same size and same depth. + * + * see also CvMat#split + */ +VALUE +rb_merge(VALUE klass, VALUE args) +{ + VALUE object, dest; + int len = RARRAY(args)->len; + if (!(len > 0) || len > CV_CN_MAX) { + rb_raise(rb_eArgError, "wrong number of argument (%d for 1..4)", len); + } + CvMat *src[] = {NULL, NULL, NULL, NULL}, *tmp = 0; + for (int i = 0; i < len; i++) { + if (rb_obj_is_kind_of((object = rb_ary_entry(args, i)), rb_klass)) { + src[i] = CVMAT(object); + if (CV_MAT_CN(src[i]->type) != 1) { + rb_raise(rb_eStandardError, "image should be single-channel CvMat."); + } + if (!tmp) + tmp = src[i]; + else{ + if (!CV_ARE_SIZES_EQ(tmp, src[i])) + rb_raise(rb_eStandardError, "image size should be same."); + if (!CV_ARE_DEPTHS_EQ(tmp, src[i])) + rb_raise(rb_eStandardError, "image depth should be same."); + } + }else if (NIL_P(object)) { + src[i] = NULL; + }else + rb_raise(rb_eTypeError, "argument should be CvMat or subclass of it."); + } + dest = new_object(cvGetSize(tmp), CV_MAKETYPE(CV_MAT_DEPTH(tmp->type), len)); + cvMerge(src[0], src[1], src[2], src[3], CVARR(dest)); + return dest; +} + +/* + * call-seq: + * CvMat.mix_channels(srcs,dests,from_to = {1 => 1, 2 => 2, 3 => 3, 4 => 4}) -> dests + */ +VALUE +rb_mix_channels(int argc, VALUE *argv, VALUE self) +{ + VALUE srcs, dests, from_to; + rb_scan_args(argc, argv, "21", &srcs, &dests, &from_to); + /* not yet */ + return Qnil; +} + +/* + * call-seq: + * rand_shuffle([seed = nil][,iter = 1]) + * + * Return filled the destination array with values from the look-up table. + * + * see rand_shuffle! + */ +VALUE +rb_rand_shuffle(int argc, VALUE *argv, VALUE self) +{ + return rb_rand_shuffle_bang(argc, argv, copy(self)); +} + +/* + * call-seq: + * rand_shuffle!([seed = nil][,iter = 1]) + * + * fills the destination array with values from the look-up table. + * Indices of the entries are taken from the source array. That is, the function processes each element of src as following: + * dst(I)=lut[src(I)+DELTA] + * where DELTA=0 if src has depth :cv8u, and DELTA=128 if src has depth :cv8s. + */ +VALUE +rb_rand_shuffle_bang(int argc, VALUE *argv, VALUE self) +{ + VALUE seed, iter; + CvRNG rng; + rb_scan_args(argc, argv, "02", &seed, &iter); + if(NIL_P(seed)) + cvRandShuffle(CVARR(self), NULL, IF_INT(iter, 1)); + else{ + rng = cvRNG(rb_num2ll(seed)); + cvRandShuffle(CVARR(self), &rng, IF_INT(iter, 1)); + } + return self; +} + +/* + * call-seq: + * lut(lookup_table) -> cvmat + * + * Return new matrix performed lookup-table transforme. + * + * lookup_table should be CvMat that have 256 element (e.g. 1x256 matrix). + * Otherwise, raise CvStatusBadArgument error. + * + * And lookup_table should either have a single-channel, or the same number of channels. + * When single-channel lookup-table given, same table is used for all channels. + */ +VALUE +rb_lut(VALUE self, VALUE lut) +{ + VALUE dest = copy(self); + cvLUT(CVARR(self), CVARR(dest), CVARR(lut)); + return dest; +} + +/* + * call-seq: + * convert_scale(:depth => nil, :scale => 1.0, :shift => 0.0) + * + * Return new array with optional linear transformation. + * mat(I) = src(I) * scale + (shift, shift, ...) + */ +VALUE +rb_convert_scale(VALUE self, VALUE hash) +{ + if (TYPE(hash) != T_HASH) + rb_raise(rb_eTypeError, "argument should be Hash that contaion key [:depth, :scale, :shift]."); + VALUE depth = rb_hash_aref(hash, ID2SYM(rb_intern("depth"))), + scale = rb_hash_aref(hash, ID2SYM(rb_intern("scale"))), + shift = rb_hash_aref(hash, ID2SYM(rb_intern("shift"))), + dest = new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(IF_DEPTH(depth, CV_MAT_DEPTH(CVMAT(self)->type)), CV_MAT_CN(CVMAT(self)->type))); + cvConvertScale(CVARR(self), CVARR(dest), IF_DBL(scale, 1.0), IF_DBL(shift, 0.0)); + return dest; +} + +/* + * call-seq: + * convert_scale_abs(:scale => 1.0, :shift => 0.0) + * + * Return new array with optional linear transformation. + * It is similar to CvMat#convert_scale, but it stores absolute values of the conversion result + * mat(I) = (src(I) * scale + (shift, shift, ...)).abs + */ +VALUE +rb_convert_scale_abs(VALUE self, VALUE hash) +{ + if (TYPE(hash) != T_HASH) + rb_raise(rb_eTypeError, "argument should be Hash that contaion key [:depth, :scale, :shift]."); + VALUE + scale = rb_hash_aref(hash, ID2SYM(rb_intern("scale"))), + shift = rb_hash_aref(hash, ID2SYM(rb_intern("shift"))), + dest = new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_8U, CV_MAT_CN(CVMAT(self)->type))); + cvConvertScale(CVARR(self), CVARR(dest), IF_DBL(scale, 1.0), IF_DBL(shift, 0.0)); + return dest; +} + +/* + * call-seq: + * add(val[,mask]) -> cvmat + * + * Return new matrix computed per-element sum. + * val should be CvMat or CvScalar. + * If val is CvMat, it must have same type (depth and channel). + * mask should be CvMat(8bit single-channel). + * For each element (I) + * dst(I) = src1(I) + src2(I) if mask(I) != 0 + */ +VALUE +rb_add(int argc, VALUE *argv, VALUE self) +{ + VALUE val, mask, dest; + rb_scan_args(argc, argv, "11", &val, &mask); + dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + if (rb_obj_is_kind_of(val, rb_klass)) + cvAdd(CVARR(self), CVARR(val), CVARR(dest), MASK(mask)); + else + cvAddS(CVARR(self), VALUE_TO_CVSCALAR(val), CVARR(dest), MASK(mask)); + return dest; +} + +/* + * call-seq: + * sub(val[,mask]) -> cvmat + * + * Return new matrix computed per-element difference. + * val should be CvMat or CvScalar. + * If val is CvMat, it must have same type (depth and channel). + * mask should be CvMat(8bit single-channel). + * For each element (I) + * dst(I) = src1(I) - src2(I) if mask(I) != 0 + */ +VALUE +rb_sub(int argc, VALUE *argv, VALUE self) +{ + VALUE val, mask, dest; + rb_scan_args(argc, argv, "11", &val, &mask); + dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + if (rb_obj_is_kind_of(val, rb_klass)) + cvSub(CVARR(self), CVARR(val), CVARR(dest), MASK(mask)); + else + cvSubS(CVARR(self), VALUE_TO_CVSCALAR(val), CVARR(dest), MASK(mask)); + return dest; +} + +/* + * call-seq: + * mul(val[,scale = 1.0]) -> cvmat + * + * Return new matrix computed per-element product. + * val should be CvMat or CvScalar. + * If val is CvMat, it must have same type (depth and channel). + * For each element (I) + * dst(I) = scale * src1(I) * src2(I) + */ +VALUE +rb_mul(int argc, VALUE *argv, VALUE self) +{ + VALUE val, scale, dest; + if (rb_scan_args(argc, argv, "11", &val, &scale) < 2) + scale = rb_float_new(1.0); + dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + if (rb_obj_is_kind_of(val, rb_klass)) { + cvMul(CVARR(self), CVARR(val), CVARR(dest), NUM2DBL(scale)); + }else{ + CvScalar scl = VALUE_TO_CVSCALAR(val); + VALUE mat = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvSet(CVARR(mat), scl); + cvMul(CVARR(self), CVARR(mat), CVARR(dest), NUM2DBL(scale)); + } + return dest; +} + +/* + * call-seq: + * div(val[,scale = 1.0]) -> cvmat + * + * Return new matrix computed per-element division. + * val should be CvMat or CvScalar. + * If val is CvMat, it must have same type (depth and channel). + * For each element (I) + * dst(I) = scale * src1(I) / src2(I) + */ +VALUE +rb_div(int argc, VALUE *argv, VALUE self) +{ + VALUE val, scale, dest; + if (rb_scan_args(argc, argv, "11", &val, &scale) < 2) + scale = rb_float_new(1.0); + dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + if (rb_obj_is_kind_of(val, rb_klass)) { + cvDiv(CVARR(self), CVARR(val), CVARR(dest), NUM2DBL(scale)); + }else{ + CvScalar scl = VALUE_TO_CVSCALAR(val); + VALUE mat = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvSet(CVARR(mat), scl); + cvDiv(CVARR(self), CVARR(mat), CVARR(dest), NUM2DBL(scale)); + } + return dest; +} + +/* + * call-seq: + * and(val[,mask]) -> cvmat + * + * Return new matrix computed per-element bit-wise conjunction. + * val should be CvMat or CvScalar. + * If val is CvMat, it must have same type (depth and channel). + * For each element (I) + * dst(I) = src1(I) & src2(I) if mask(I) != 0 + */ +VALUE +rb_and(int argc, VALUE *argv, VALUE self) +{ + VALUE val, mask, dest; + rb_scan_args(argc, argv, "11", &val, &mask); + dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + if (rb_obj_is_kind_of(val, rb_klass)) + cvAnd(CVARR(self), CVARR(val), CVARR(dest), MASK(mask)); + else + cvAndS(CVARR(self), VALUE_TO_CVSCALAR(val), CVARR(dest), MASK(mask)); + return dest; +} + +/* + * call-seq: + * or(val[,mask]) -> cvmat + * + * Return new matrix computed per-element bit-wise disjunction. + * val should be CvMat or CvScalar. + * If val is CvMat, it must have same type (depth and channel). + * For each element (I) + * dst(I) = src1(I) | src2(I) if mask(I) != 0 + */ +VALUE +rb_or(int argc, VALUE *argv, VALUE self) +{ + VALUE val, mask, dest; + rb_scan_args(argc, argv, "11", &val, &mask); + dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + if (rb_obj_is_kind_of(val, rb_klass)) + cvOr(CVARR(self), CVARR(val), CVARR(dest), MASK(mask)); + else + cvOrS(CVARR(self), VALUE_TO_CVSCALAR(val), CVARR(dest), MASK(mask)); + return dest; +} + +/* + * call-seq: + * xor(val[,mask]) -> cvmat + * + * Return new matrix computed per-element bit-wise "exclusive or" operation. + * val should be CvMat or CvScalar. + * If val is CvMat, it must have same type (depth and channel). + * For each element (I) + * dst(I) = src1(I) ^ src2(I) if mask(I) != 0 + */ +VALUE +rb_xor(int argc, VALUE *argv, VALUE self) +{ + VALUE val, mask, dest; + rb_scan_args(argc, argv, "11", &val, &mask); + dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + if (rb_obj_is_kind_of(val, rb_klass)) + cvXor(CVARR(self), CVARR(val), CVARR(dest), MASK(mask)); + else + cvXorS(CVARR(self), VALUE_TO_CVSCALAR(val), CVARR(dest), MASK(mask)); + return dest; +} + +/* + * call-seq: + * not -> cvmat + * + * Return new matrix performed per-element bit-wise inversion. + * dst(I) =~ src(I) + */ +VALUE +rb_not(VALUE self) +{ + VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvNot(CVARR(self), CVARR(dest)); + return dest; +} + +/* + * call-seq: + * not! -> self + * + * Performe per-element bit-wise inversion. + */ +VALUE +rb_not_bang(VALUE self) +{ + cvNot(CVARR(self), CVARR(self)); + return self; +} + +VALUE +rb_cmp_internal(VALUE self, VALUE val, int operand) +{ + VALUE dest = new_object(cvGetSize(CVARR(self)), CV_8U); + if (rb_obj_is_kind_of(val, rb_klass)) + cvCmp(CVARR(self), CVARR(val), CVARR(dest), operand); + else if (CV_MAT_CN(cvGetElemType(CVARR(self))) == 1 && rb_obj_is_kind_of(val, rb_cNumeric)) { + cvCmpS(CVARR(self), NUM2DBL(val), CVARR(dest), operand); + }else{ + VALUE mat = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvSet(CVARR(mat), VALUE_TO_CVSCALAR(val)); + cvCmp(CVARR(self), CVARR(mat), CVARR(dest), operand); + } + return dest; +} + +/* + * call-seq: + * eq(val) -> cvmat + * + * Return new matrix performed per-element comparision "equal". + * dst(I) = (self(I) == val(I) ? 0xFF : 0) + */ +VALUE +rb_eq(VALUE self, VALUE val) +{ + return rb_cmp_internal(self, val, CV_CMP_EQ); +} + +/* + * call-seq: + * gt(val) -> cvmat + * + * Return new matrix performed per-element comparision "greater than". + * dst(I) = (self(I) > val(I) ? 0xFF : 0) + */ +VALUE +rb_gt(VALUE self, VALUE val) +{ + return rb_cmp_internal(self, val, CV_CMP_GT); +} + +/* + * call-seq: + * ge(val) -> cvmat + * + * Return new matrix performed per-element comparision "greater or equal". + * dst(I) = (self(I) >= val(I) ? 0xFF : 0) + */ +VALUE +rb_ge(VALUE self, VALUE val) +{ + return rb_cmp_internal(self, val, CV_CMP_GE); +} + +/* + * call-seq: + * lt(val) -> cvmat + * + * Return new matrix performed per-element comparision "less than". + * dst(I) = (self(I) < val(I) ? 0xFF : 0) + */ +VALUE +rb_lt(VALUE self, VALUE val) +{ + return rb_cmp_internal(self, val, CV_CMP_LT); +} + +/* + * call-seq: + * le(val) -> cvmat + * + * Return new matrix performed per-element comparision "less or equal". + * dst(I) = (self(I) <= val(I) ? 0xFF : 0) + */ +VALUE +rb_le(VALUE self, VALUE val) +{ + return rb_cmp_internal(self, val, CV_CMP_LE); +} + +/* + * call-seq: + * ne(val) -> cvmat + * + * Return new matrix performed per-element comparision "not equal". + * dst(I) = (self(I) != val(I) ? 0xFF : 0) + */ +VALUE +rb_ne(VALUE self, VALUE val) +{ + return rb_cmp_internal(self, val, CV_CMP_NE); +} + +/* + * call-seq: + * in_range(min, max) -> cvmat + * + * Check that element lie between two object. + * min and max should be CvMat that have same size and type, or CvScalar. + * Return new matrix performed per-element, + * dst(I) = within the range ? 0xFF : 0 + */ +VALUE +rb_in_range(VALUE self, VALUE min, VALUE max) +{ + VALUE dest = dest = new_object(cvGetSize(CVARR(self)), CV_8UC1), tmp; + if (rb_obj_is_kind_of(min, rb_klass) && rb_obj_is_kind_of(max, rb_klass)) { + cvInRange(CVARR(self), CVARR(min), CVARR(max), CVARR(dest)); + }else if (rb_obj_is_kind_of(min, rb_klass)) { + tmp = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvSet(CVARR(tmp), VALUE_TO_CVSCALAR(max)); + cvInRange(CVARR(self), CVARR(min), CVARR(tmp), CVARR(dest)); + }else if (rb_obj_is_kind_of(max, rb_klass)) { + tmp = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvSet(CVARR(tmp), VALUE_TO_CVSCALAR(min)); + cvInRange(CVARR(self), CVARR(tmp), CVARR(max), CVARR(dest)); + }else + cvInRangeS(CVARR(self), VALUE_TO_CVSCALAR(min), VALUE_TO_CVSCALAR(max), CVARR(dest)); + return dest; +} + +/* + * call-seq: + * abs_diff(val) -> cvmat + * + * Calculate absolute difference between two. + * val should be CvMat that have same size and same type, or CvScalar. + * dst(I) = (src(I) - val(I)).abs + */ +VALUE +rb_abs_diff(VALUE self, VALUE val) +{ + VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + if (rb_obj_is_kind_of(val, rb_klass)) { + cvAbsDiff(CVARR(self), CVARR(val), CVARR(dest)); + }else{ + cvAbsDiffS(CVARR(self), CVARR(dest), VALUE_TO_CVSCALAR(val)); + } + return dest; +} + +/* + * call-seq: + * count_non_zero -> int + * + * Returns the number of non-zero elements. + * result = sumI arr(I)!=0 + * + * In case of IplImage both ROI and COI are supported. + */ +VALUE +rb_count_non_zero(VALUE self) +{ + return INT2FIX(cvCountNonZero(CVARR(self))); +} + +/* + * call-seq: + * sum -> scalar + * + * Return summerizes elements as CvScalar. Independently for each channel. + * + * note: If COI is setted in IplImage, the method processes the selected channel only and store the sum to the first component scalar[0]. + */ +VALUE +rb_sum(VALUE self) +{ + return cCvScalar::new_object(cvSum(CVARR(self))); +} + +/* + * call-seq: + * avg([mask]) -> mean(as scalar) + * + * Return the average(mean) of elements as CvScalar. Independently for each channel. + */ +VALUE +rb_avg(int argc, VALUE *argv, VALUE self) +{ + VALUE mask, mean; + rb_scan_args(argc, argv, "01", &mask); + + return cCvScalar::new_object(cvAvg(CVARR(self), MASK(mask))); +} + +/* + * call-seq: + * avg_sdv(mask) -> [mean(as scalar), std_dev(as scalar)] + * + * Calculates the average value and standard deviation of array elements, independently for each channel. + * + * note: same as [CvMat#avg, CvMat#sdv] + */ +VALUE +rb_avg_sdv(int argc, VALUE *argv, VALUE self) +{ + VALUE mask, mean, std_dev; + rb_scan_args(argc, argv, "01", &mask); + mean = cCvScalar::new_object(); + std_dev = cCvScalar::new_object(); + cvAvgSdv(CVARR(self), CVSCALAR(mean), CVSCALAR(std_dev), MASK(mask)); + return rb_ary_new3(2, mean, std_dev); +} + +/* + * call-seq: + * sdv([mask]) -> std_dev(as scalar) + * + * Return the standard deviation of elements as CvScalar. Independently for each channel. + */ +VALUE +rb_sdv(int argc, VALUE *argv, VALUE self) +{ + VALUE mask, std_dev; + rb_scan_args(argc, argv, "01", &mask); + std_dev = cCvScalar::new_object(); + cvAvgSdv(CVARR(self), NULL, CVSCALAR(std_dev), MASK(mask)); + return std_dev; +} + +/* + * call-seq: + * min_max_loc([mask]) -> [min_val, max_val, min_loc(as point), max_loc(as point)] + * + * Finds minimum and maximum element values and their positions. + * The extremums are searched over the whole array, selected ROI(in case of IplImage) or, if mask is not NULL, in the specified array region. + * If the array has more than one channel, it must be IplImage with COI set. + * In case if multi-dimensional arrays min_loc.x and max_loc.x will contain raw (linear) positions of the extremums. + */ +VALUE +rb_min_max_loc(int argc, VALUE *argv, VALUE self) +{ + VALUE mask, min_loc, max_loc; + double min_val = 0.0, max_val = 0.0; + rb_scan_args(argc, argv, "01", &mask); + min_loc = cCvPoint::new_object(); + max_loc = cCvPoint::new_object(); + cvMinMaxLoc(CVARR(self), &min_val, &max_val, CVPOINT(min_loc), CVPOINT(max_loc), MASK(mask)); + return rb_ary_new3(4, + rb_float_new(min_val), + rb_float_new(max_val), + min_loc, + max_loc); +} + +/* + * call-seq: + * dot_product(mat) -> float + * + * Calculates dot product of two arrays in Euclidian metrics. + * mat should be CvMat have same size and same type. + * + * src1.src2 = sum(src1(I) * src2(I)) + */ +VALUE +rb_dot_product(VALUE self, VALUE mat) +{ + if (!rb_obj_is_kind_of(mat, rb_klass)) + rb_raise(rb_eTypeError, "argument should be CvMat."); + return rb_float_new(cvDotProduct(CVARR(self), CVARR(mat))); +} + +/* + * call-seq: + * cross_product(mat) -> cvmat + * + * Calculate cross product of two 3D vectors. + * mat should be CvMat have same size and same type. + */ +VALUE +rb_cross_product(VALUE self, VALUE mat) +{ + if (!rb_obj_is_kind_of(mat, rb_klass)) + rb_raise(rb_eTypeError, "argument should be CvMat."); + VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvCrossProduct(CVARR(self), CVARR(mat), CVARR(dest)); + return dest; +} + +/* + * call-seq: + * transform(transmat[,shiftvec]) -> cvmat + * + * performs matrix transform of every element. + * dst(I) = transmat * src(I) + shiftvec + */ +VALUE +rb_transform(int argc, VALUE *argv, VALUE self) +{ + VALUE transmat, shiftvec; + rb_scan_args(argc, argv, "11", &transmat, &shiftvec); + VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvTransform(CVARR(self), CVARR(dest), CVMAT(transmat), MASK(shiftvec)); + return dest; +} + +/* + * call-seq: + * perspective_transform(mat) -> cvmat + * + * Return performed perspective matrix transform of vector array. + * mat should be 3x3 or 4x4 transform matrix (CvMat). + * Every element (by treating it as 2D or 3D vector) in the following way: + * (x, y, z) -> (x'/w, y'/w, z'/w) or + * (x, y) -> (x'/w, y'/w) + * where + * (x', y', z', w') = mat4x4*(x, y, z, 1) or + * (x', y', w') = mat3x3*(x, y, 1) + * and + * w = w' if w'!=0, inf otherwise. + */ +VALUE +rb_perspective_transform(VALUE self, VALUE mat) +{ + VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvPerspectiveTransform(CVARR(self), CVARR(dest), CVMAT(mat)); + return dest; +} + +/* + * call-seq: + * mul_transposed(:order => :default or :inverse, :delta => nil or cvmat) + * + * Calculates the product of self and its transposition. + * + * options + * * :order -> should be :default or :inverse (default is :default) + * see below. + * * :delta -> should be nil or CvMat (default is nil) + * An optional array, subtracted from source before multiplication. + * + * mul_transposed evaluates: + * :order => :default + * dst = (self - delta) * (self - delta)T + * :order => :inverse + * dst = (self - delta)T * (self - delta) + * + */ +VALUE +rb_mul_transposed(VALUE self, VALUE args) +{ + //VALUE options = extract_options_from_args_bang(args); + //assert_valid_keys(options, 2, "order", "delta"); + //VALUE order; + //OPTIONS(order, options, "order", ID2SYM(rb_intern("default"))); + //ID2SYM(rb_intern("order")), rb_intern("") + return Qnil; +} + + +/* + * call-seq: + * trace -> scalar + * + * Returns trace of matrix. "trace" is sum of diagonal elements of the matrix. + */ +VALUE +rb_trace(VALUE self) +{ + return cCvScalar::new_object(cvTrace(CVARR(self))); +} + +/* + * call-seq: + * transpose -> cvmat + * + * Return transposed matrix. + */ +VALUE +rb_transpose(VALUE self) +{ + CvSize size = cvGetSize(CVARR(self)); + VALUE dest = new_object(size.width, size.height, cvGetElemType(CVARR(self))); + cvTranspose(CVARR(self), CVARR(dest)); + return dest; +} + +/* + * call-seq: + * transpose! -> self + * + * Transposed matrix. + * + * rectangular matrix only (CvMat#square? = true). + */ +VALUE +rb_transpose_bang(VALUE self) +{ + cvTranspose(CVARR(self), CVARR(self)); + return self; +} + +/* + * call-seq: + * det -> float + * + * Return determinant of matrix. + * self should be single-channel and floating-point depth. + */ +VALUE +rb_det(VALUE self) +{ + return rb_float_new(cvDet(CVARR(self))); +} + +/* + * call-seq: + * invert(inversion_method=:lu[,delta]) -> float + * + * Finds inverse or pseudo-inverse of matrix. + * inversion_method should be following symbol. + * * :lu + * Gaussian elimincation with optimal pivot element chose. + * Return self determinant (self must be square). + * * :svd + * Singular value decomposition(SVD) method. + * Return the inversed condition number of self(ratio of the smallest singular value to the largest singular value) + * and 0 if self is all zeros. The SVD method calculate a pseudo-inverse matrix if self is singular. + * * :svd_sym or :svd_symmetric + * SVD method for a symmetric positively-defined matrix. + * + * self type should be single-channel and floating-point matrix. + */ +VALUE +rb_invert(int argc, VALUE *argv, VALUE self) +{ + VALUE symbol; + rb_scan_args(argc, argv, "01", &symbol); + int method = CVMETHOD("INVERSION_METHOD", symbol, CV_LU); + VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvInvert(CVARR(self), CVARR(dest), method); + return dest; +} + +/* + * call-seq: + * solve(mat, inversion_method=:lu) + * + * Solves linear system or least-squares problem (the latter is possible with SVD method). + * + * inversion_method should be following symbol. + * * :lu + * Gaussian elimincation with optimal pivot element chose. + * Return self determinant (self must be square). + * * :svd + * Singular value decomposition(SVD) method. + * Return the inversed condition number of self(ratio of the smallest singular value to the largest singular value) + * and 0 if self is all zeros. The SVD method calculate a pseudo-inverse matrix if self is singular. + * * :svd_sym or :svd_symmetric + * SVD method for a symmetric positively-defined matrix. + */ +VALUE +rb_solve(int argc, VALUE *argv, VALUE self) +{ + VALUE mat, symbol; + rb_scan_args(argc, argv, "11", &mat, &symbol); + if (!rb_obj_is_kind_of(mat, rb_klass)) + rb_raise(rb_eTypeError, "argument 1 (right-hand part of the linear system) should be %s.)", rb_class2name(rb_klass)); + VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvSolve(CVARR(self), CVARR(mat), CVARR(dest), CVMETHOD("INVERSION_METHOD", symbol, CV_LU)); + return dest; +} + +/* + * call-seq: + * svd(u = nil, v = nil) + * + * not implementated. + * Performs singular value decomposition of real floating-point matrix. + */ +VALUE +rb_svd(int argc, VALUE *argv, VALUE self) +{ + rb_raise(rb_eNotImpError, ""); + /* + VALUE u = Qnil, v = Qnil; + rb_scan_args(argc, argv, "02", &u, &v); + CvMat + *matU = NIL_P(u) ? NULL : CVARR(u), + *matV = NIL_P(v) ? NULL : CVARR(v); + cvSVD(CVARR(self), matU, matV); + return dest; + */ +} + +/* + * call-seq: + * svbksb + * + * not yet. + */ +VALUE +rb_svbksb(int argc, VALUE *argv, VALUE self) +{ + rb_raise(rb_eNotImpError, ""); +} + +/* + * call-seq: + * eigenvv([eps = 0.0]) -> [eigen_vectors(cvmat), eigen_values(cvmat)] + * + * Computes eigenvalues and eigenvectors of symmetric matrix. + * self should be symmetric square matrix. + * + * see #eigenvv! + */ +VALUE +rb_eigenvv(int argc, VALUE *argv, VALUE self) +{ + return rb_eigenvv_bang(argc, argv, copy(self)); +} + +/* + * call-seq: + * eigenvv!([eps = 0.0]) -> [eigen_vectors(cvmat), eigen_values(cvmat)] + * + * Computes eigenvalues and eigenvectors of symmetric matrix. + * self should be symmetric square matrix. self is modified during the processing. + * + * self * eigen_vectors(i,:)' = eigen_values(i) * eigen_vectors(i,:)' + * + * The contents of self is destroyed by this method. + * + * Currently the function is slower than #svd yet less accurate, so if self is known to be positively-defined + * (e.g., it is a convariation matrix), it is recommanded to use #svd to find eigenvalues and eigenvectors of self, + * especially if eigenvectors are not required. + */ +VALUE +rb_eigenvv_bang(int argc, VALUE *argv, VALUE self) +{ + VALUE epsilon; + double eps = rb_scan_args(argc, argv, "01", &epsilon) < 1 ? 0.0 : NUM2DBL(epsilon); + CvSize size = cvGetSize(CVARR(self)); + int type = cvGetElemType(CVARR(self)); + VALUE eigen_vectors = new_object(size, type), eigen_values = new_object(size.height, 1, type); + cvEigenVV(CVARR(self), CVARR(eigen_vectors), CVARR(eigen_values), eps); + return rb_ary_new3(2, eigen_vectors, eigen_values); +} + +/* + * call-seq: + * calc_covar_matrix() + * + * not yet. + * + */ +VALUE +rb_calc_covar_matrix(int argc, VALUE *argv, VALUE self) +{ + rb_raise(rb_eNotImpError, ""); +} + +/* + * call-seq: + * mahalonobis(vec, mat) -> float + * + * not yet. + */ +VALUE +rb_mahalonobis(int argc, VALUE *argv, VALUE self) +{ + rb_raise(rb_eNotImpError, ""); +} + + +/* + * call-seq: + * dft(anyflags...) -> cvmat + * + * Performs forward or inverse Discrete Fourier Transform(DFT) of 1D or 2D floating-point array. + * Argument should be following symbol or combination of these. + * + * * :forward or :inverse + * Do forward or inverse transform. The result is not scaled. + * * :scale + * Scale the result: divide it by the number of array elements. + * * :rows + * Do forward or inverse transform of every individual row of the self. + * This flag allow user to transofrm multiple vectors simulaneously and can be used to decrease the overhand + * (which sometimes several times larger then the processing itself), to do 3D and higher-dimensional transforms etc. + * + * e.g. + * mat.dft(:inverse) + * mat.dft(:forward, :scale) etc... + */ +VALUE +rb_dft(int argc, VALUE *argv, VALUE self) +{ + int type = CV_DXT_FORWARD; + if (argc > 0) { + for (int i = 0; i < argc; i++) { + type |= CVMETHOD("DXT_FLAG", argv[i]); + } + } + VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvDFT(CVARR(self), CVARR(dest), type); + return dest; +} + +/* + * call-seq: + * dct(anyflags...) -> cvmat + * + * Performs forward or inverse Discrete Cosine Transform(DCT) of 1D or 2D floating-point array. + * Argument should be following symbol or combination of these. + * + * * :forward or :inverse + * Do forward or inverse transform. + * * :rows + * Do forward or inverse transform of every individual row of the self. + * This flag allow user to transofrm multiple vectors simulaneously and can be used to decrease the overhand + * (which sometimes several times larger then the processing itself), to do 3D and higher-dimensional transforms etc. + */ +VALUE +rb_dct(int argc, VALUE *argv, VALUE self) +{ + int type = CV_DXT_FORWARD; + if (argc > 0) { + for (int i = 0; i < argc; i++) { + type |= CVMETHOD("DXT_FLAG", argv[i]); + } + } + VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvDCT(CVARR(self), CVARR(dest), type); + return dest; +} + +/* + * call-seq: + * line(p1, p2[, drawing_option]) -> mat + * + * Return image is drawn a line segment connecting two points. + * + * drawing_option should be Hash include these keys. + * :color + * Line color. + * :thickness + * Line Thickness. + * :line_type + * Type of the line: + * * 0 or 8 - 8-connected line(default). + * * 4 - 4-connected line. + * * negative-value - antialiased line. + * :shift + * Number of fractional bits in the point coordinates. + * + * note: drawing_option's default value is CvMat::DRAWING_OPTION. + * + * for example + * mat = CvMat.new(100, 100) + * mat.line(CvPoint.new(10, 10), CvPoint.new(90, 90), :thickness => 3, :line_type => :aa) + */ +VALUE +rb_line(int argc, VALUE *argv, VALUE self) +{ + return rb_line_bang(argc, argv, rb_clone(self)); +} + +/* + * call-seq: + * line!(p1, p2[, drawing_option]) -> self + * + * Draws a line segment connecting two points. + * Same as CvMat#line, but modifies the receiver in place. + * see CvMat#line + */ +VALUE +rb_line_bang(int argc, VALUE *argv, VALUE self) +{ + VALUE p1, p2, drawing_option; + rb_scan_args(argc, argv, "21", &p1, &p2, &drawing_option); + drawing_option = DRAWING_OPTION(drawing_option); + cvLine(CVARR(self), VALUE_TO_CVPOINT(p1), VALUE_TO_CVPOINT(p2), + DO_COLOR(drawing_option), + DO_THICKNESS(drawing_option), + DO_LINE_TYPE(drawing_option), + DO_SHIFT(drawing_option)); + return self; +} + +/* + * call-seq: + * rectangle(p1, p2[, drawing_option]) -> mat + * + * Return image is drawn a rectangle with two opposite corners p1 and p2. + * + * drawing_options should be Hash include these keys. + * :color + * Line color. + * :thickness + * Thickness of lines that make up the rectangle. + * Negative values make the function to draw a filled rectangle. + * :line_type + * Type of the line: + * * 0 or 8 - 8-connected line(default). + * * 4 - 4-connected line. + * * negative-value - antialiased line. + * :shift + * Number of fractional bits in the point coordinates. + * + * note: drawing_option's default value is CvMat::DRAWING_OPTION. + */ +VALUE +rb_rectangle(int argc, VALUE *argv, VALUE self) +{ + return rb_rectangle_bang(argc, argv, rb_clone(self)); +} + +/* + * call-seq: + * rectangle!(p1, p2[, drawing_option]) -> self + * + * Draws simple, thick or filled rectangle. + * Same as CvMat#rectangle, but modifies the receiver in place. + * see CvMat#rectangle + */ +VALUE +rb_rectangle_bang(int argc, VALUE *argv, VALUE self) +{ + VALUE p1, p2, drawing_option; + rb_scan_args(argc, argv, "21", &p1, &p2, &drawing_option); + drawing_option = DRAWING_OPTION(drawing_option); + cvRectangle(CVARR(self), VALUE_TO_CVPOINT(p1), VALUE_TO_CVPOINT(p2), + DO_COLOR(drawing_option), + DO_THICKNESS(drawing_option), + DO_LINE_TYPE(drawing_option), + DO_SHIFT(drawing_option)); + return self; +} + +/* + * call-seq: + * circle(center, radius[,drawing_option]) -> cvmat + * + * Return image is drawn a simple or filled circle with given center and radius. + * + * drawing_options should be Hash include these keys. + * :color + * Circle color. + * :thickness + * Thickness of the circle outline if positive, otherwise that a filled circle has to be drawn. + * :line_type + * Type of the circle boundary: + * * 0 or 8 - 8-connected line(default). + * * 4 - 4-connected line. + * * negative-value - antialiased line. + * :shift + * Number of fractional bits in the center coordinates and radius value. + * + * note: drawing_option's default value is CvMat::DRAWING_OPTION. + */ +VALUE +rb_circle(int argc, VALUE *argv, VALUE self) +{ + return rb_circle_bang(argc, argv, rb_clone(self)); +} + +/* + * call-seq: + * circle!(center, radius[,drawing_option]) -> cvmat + * + * Draw a circle. + * Same as CvMat#circle, but modifies the receiver in place. + * + * see CvMat#circle + */ +VALUE +rb_circle_bang(int argc, VALUE *argv, VALUE self) +{ + VALUE center, radius, drawing_option; + rb_scan_args(argc, argv, "21", ¢er, &radius, &drawing_option); + drawing_option = DRAWING_OPTION(drawing_option); + cvCircle(CVARR(self), VALUE_TO_CVPOINT(center), NUM2INT(radius), + DO_COLOR(drawing_option), + DO_THICKNESS(drawing_option), + DO_LINE_TYPE(drawing_option), + DO_SHIFT(drawing_option)); + return self; +} + +/* + * call-seq: + * ellipse(center, axis, angle, start_angle, end_angle[,drawing_option]) -> mat + * + * Return image is drawn a simple or thick elliptic arc or fills an ellipse sector. + * + * drawing_options should be Hash include these keys. + * :color + * Ellipse color. + * :thickness + * Thickness of the ellipse arc. + * :line_type + * Type of the ellipse boundary: + * * 0 or 8 - 8-connected line(default). + * * 4 - 4-connected line. + * * negative-value - antialiased line. + * :shift + * Number of fractional bits in the center coordinates and axes' value. + * + * note: drawing_option's default value is CvMat::DRAWING_OPTION. + */ +VALUE +rb_ellipse(int argc, VALUE *argv, VALUE self) +{ + return rb_ellipse_bang(argc, argv, rb_clone(self)); +} + +/* + * call-seq: + * ellipse!(center, axis, angle, start_angle, end_angle[,drawing_option]) -> self + * + * Draws simple or thick elliptic arc or fills ellipse sector. + * Same as CvMat#ellipse, but modifies the receiver in place. + * + * see CvMat#ellipse + */ +VALUE +rb_ellipse_bang(int argc, VALUE *argv, VALUE self) +{ + VALUE center, axis, angle, start_angle, end_angle, drawing_option; + rb_scan_args(argc, argv, "51", ¢er, &axis, &angle, &start_angle, &end_angle, &drawing_option); + drawing_option = DRAWING_OPTION(drawing_option); + cvEllipse(CVARR(self), VALUE_TO_CVPOINT(center), + VALUE_TO_CVSIZE(axis), + NUM2DBL(angle), NUM2DBL(start_angle), NUM2DBL(end_angle), + DO_COLOR(drawing_option), + DO_THICKNESS(drawing_option), + DO_LINE_TYPE(drawing_option), + DO_SHIFT(drawing_option)); + return self; +} + +/* + * call-seq: + * ellipse_box(box[, drawing_option]) -> mat + * + * Return image is drawn a simple or thick ellipse outline, or fills an ellipse. + * The method provides a convenient way to draw an ellipse approximating some shape. + * + * drawing_options should be Hash include these keys. + * :color + * Ellipse color. + * :thickness + * Thickness of the ellipse drawn. + * :line_type + * Type of the ellipse boundary: + * * 0 or 8 - 8-connected line(default). + * * 4 - 4-connected line. + * * negative-value - antialiased line. + * :shift + * Number of fractional bits in the box vertex coordinates. + * + * note: drawing_option's default value is CvMat::DRAWING_OPTION. + */ +VALUE +rb_ellipse_box(int argc, VALUE *argv, VALUE self) +{ + return rb_ellipse_box_bang(argc, argv, rb_clone(self)); +} + +/* + * call-seq: + * ellipse_box!(box[, drawing_option]) -> self + * + * Draws simple or thick elliptic arc or fills ellipse sector. + * Same as CvMat#ellipse_box, but modifies the receiver in place. + * + * see CvMat#ellipse_box + */ +VALUE +rb_ellipse_box_bang(int argc, VALUE *argv, VALUE self) +{ + VALUE box, drawing_option; + rb_scan_args(argc, argv, "11", &box, &drawing_option); + drawing_option = DRAWING_OPTION(drawing_option); + cvEllipseBox(CVARR(self), VALUE_TO_CVBOX2D(box), + DO_COLOR(drawing_option), + DO_THICKNESS(drawing_option), + DO_LINE_TYPE(drawing_option), + DO_SHIFT(drawing_option)); + return self; +} + +/* + * call-seq: + * fill_poly(points[,drawing_option]) -> mat + * + * Return image is filled an area bounded by several polygonal contours. + * The method fills complex areas, for example, areas with holes, contour self-intersection, etc. + */ +VALUE +rb_fill_poly(int argc, VALUE *argv, VALUE self) +{ + return rb_fill_poly_bang(argc, argv, self); +} + +/* + * call-seq: + * fill_poly!(points[,drawing_option]) -> self + * + * Fills polygons interior. + * Same as CvMat#fill_poly, but modifies the receiver in place. + * + * drawing_options should be Hash include these keys. + * :color + * Polygon color. + * :line_type + * Type of the polygon boundaries: + * * 0 or 8 - 8-connected line(default). + * * 4 - 4-connected line. + * * negative-value - antialiased line. + * :shift + * Number of fractional bits in the vertex coordinates. + * + * note: drawing_option's default value is CvMat::DRAWING_OPTION. + */ +VALUE +rb_fill_poly_bang(int argc, VALUE *argv, VALUE self) +{ + VALUE points, drawing_option; + rb_scan_args(argc, argv, "11", &points, &drawing_option); + drawing_option = DRAWING_OPTION(drawing_option); + if (!POINT_SET_P(points)) + rb_raise(rb_eTypeError, "argument 1(points) should be %s.", cCvSeq::rb_class()); + /* // todo : draw multi-sequence polygon + CvSeq *seq = CVSEQ(points); + int contours = 1; + while(seq = seq->h_next) + contours++; + int **nps = ALLOCA_N(int*, contours); + CvPoint **ps = ALLOCA_N(CvPoint*, contours); + seq = CVSEQ(points); + for (int i = 0; i < contours; i++) { + } + */ + int np = CVSEQ(points)->total; + VALUE tmp = cCvMat::new_object(1, np, CV_32SC2); + CvPoint *p = (CvPoint*)cvCvtSeqToArray(CVSEQ(points), CVMAT(tmp)->data.ptr, CV_WHOLE_SEQ); + cvFillPoly(CVARR(self), + &p, + &np, + 1, //contours + DO_COLOR(drawing_option), + DO_LINE_TYPE(drawing_option), + DO_SHIFT(drawing_option)); + return self; +} + +/* + * call-seq: + * fill_convex_poly(points[,drawing_option]) -> mat + * + * Return image is filled convex polygon interior. + * This method is much faster than The function CvMat#fill_poly + * and can fill not only the convex polygons but any monotonic polygon, + * i.e. a polygon whose contour intersects every horizontal line (scan line) + * twice at the most. + * + * drawing_options should be Hash include these keys. + * :color + * Polygon color. + * :line_type + * Type of the polygon boundaries: + * * 0 or 8 - 8-connected line(default). + * * 4 - 4-connected line. + * * negative-value - antialiased line. + * :shift + * Number of fractional bits in the vertex coordinates. + * + * note: drawing_option's default value is CvMat::DRAWING_OPTION. + */ +VALUE +rb_fill_convex_poly(int argc, VALUE *argv, VALUE self) +{ + return rb_fill_convex_poly_bang(argc, argv, rb_clone(self)); +} + +/* + * call-seq: + * fill_convex_poly!(points[,drawing_option]) -> self + * + * Fills convex polygon. + * Same as CvMat#fill_convex_poly, but modifies the receiver in place. + * + * see CvMat#fill_cnovex_poly + */ +VALUE +rb_fill_convex_poly_bang(int argc, VALUE *argv, VALUE self) +{ + VALUE points, drawing_option; + rb_scan_args(argc, argv, "11", &points, &drawing_option); + drawing_option = DRAWING_OPTION(drawing_option); + if (!POINT_SET_P(points)) + rb_raise(rb_eTypeError, "argument 1(points) should be %s.", cCvSeq::rb_class()); + int np = CVSEQ(points)->total; + VALUE tmp = cCvMat::new_object(1, np, CV_32SC2); + CvPoint *p = (CvPoint*)cvCvtSeqToArray(CVSEQ(points), CVMAT(tmp)->data.ptr, CV_WHOLE_SEQ); + cvFillConvexPoly(CVARR(self), + p, + np, + DO_COLOR(drawing_option), + DO_LINE_TYPE(drawing_option), + DO_SHIFT(drawing_option)); + return self; +} + +/* + * call-seq: + * poly_line(points[,drawing_option]) -> mat + * + * Return image drawed a single or multiple polygonal curves. + * + * drawing_option should be Hash include these keys. + * :is_closed + * Indicates whether the polylines must be drawn closed. + * If closed, the method draws the line from the last vertex + * of every contour to the first vertex. + * :color + * Polyline color. + * :thickness + * Thickness of the polyline edges + * :line_type + * Type of line segments: + * * 0 or 8 - 8-connected line(default). + * * 4 - 4-connected line. + * * negative-value - antialiased line. + * :shift + * Number of fractional bits in the vertex coordinates. + * + * note: drawing_option's default value is CvMat::DRAWING_OPTION. + */ +VALUE +rb_poly_line(int argc, VALUE *argv, VALUE self) +{ + return rb_poly_line_bang(argc, argv, rb_clone(self)); +} + +/* + * call-seq: + * poly_line!(points[,drawing_option]) -> self + * + * Draws simple or thick polygons. + * + * Same as CvMat#poly_line, but modifies the receiver in place. + * + * see CvMat#poly_line + */ +VALUE +rb_poly_line_bang(int argc, VALUE *argv, VALUE self) +{ + VALUE points, drawing_option; + rb_scan_args(argc, argv, "11", &points, &drawing_option); + drawing_option = DRAWING_OPTION(drawing_option); + /* + if (!POINT_SET_P(points)) + rb_raise(rb_eTypeError, "argument 1(points) should be %s.", cCvSeq::rb_class()); + int np = CVSEQ(points)->total; + VALUE tmp = cCvMat::new_object(1, np, CV_32SC2); + CvPoint *p = (CvPoint*)cvCvtSeqToArray(CVSEQ(points), CVMAT(tmp)->data.ptr, CV_WHOLE_SEQ); + // todo: multi-sequence polygon + cvPolyLine(CVARR(self), + &p, + &np, + 1, //contour + DO_IS_CLOSED(drawing_option), + DO_COLOR(drawing_option), + DO_THICKNESS(drawing_option), + DO_LINE_TYPE(drawing_option), + DO_SHIFT(drawing_option)); + */ + CvPoint *pointset = 0; + int length = CVPOINTS_FROM_POINT_SET(points, &pointset); + cvPolyLine(CVARR(self), + &pointset, + &length, + 1, //contour + DO_IS_CLOSED(drawing_option), + DO_COLOR(drawing_option), + DO_THICKNESS(drawing_option), + DO_LINE_TYPE(drawing_option), + DO_SHIFT(drawing_option)); + + return self; +} + +/* + * call-seq: + * put_text(str, point, font[,color]) -> cvmat + * + * Return image is drawn text string. + * font should be CvFont object. + */ +VALUE +rb_put_text(int argc, VALUE *argv, VALUE self) +{ + return rb_put_text_bang(argc, argv, rb_clone(self)); +} + +/* + * call-seq: + * put_text!(str, point ,font[,color]) -> self + * + * Draws text string. Return self. + */ +VALUE +rb_put_text_bang(int argc, VALUE *argv, VALUE self) +{ + VALUE text, point, font, color; + rb_scan_args(argc, argv, "22", &text, &point, &font, &color); + cvPutText(CVARR(self), StringValueCStr(text), VALUE_TO_CVPOINT(point), CVFONT(font), *CVSCALAR(color)); + return self; +} + +/* + * call-seq: + * sobel(xorder,yorder[,aperture_size=3]) -> cvmat + * + * Calculates first, second, third or mixed image derivatives using extended Sobel operator. + * self should be single-channel 8bit signed/unsigned or 32bit floating-point. + * + * link:../images/CvMat_sobel.png + */ +VALUE +rb_sobel(int argc, VALUE *argv, VALUE self) +{ + VALUE xorder, yorder, aperture_size, dest; + if (rb_scan_args(argc, argv, "21", &xorder, &yorder, &aperture_size) < 3) + aperture_size = INT2FIX(3); + switch(CV_MAT_DEPTH(CVMAT(self)->type)) { + case CV_8U: + case CV_8S: + dest = new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_16S, 1)); + break; + case CV_32F: + dest = new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_32F, 1)); + break; + default: + rb_raise(rb_eNotImpError, "source depth should be CV_8U or CV_8S or CV_32F."); + } + cvSobel(CVARR(self), CVARR(dest), NUM2INT(xorder), NUM2INT(yorder), NUM2INT(aperture_size)); + return dest; +} + +/* + * call-seq: + * laplace([aperture_size = 3]) -> cvmat + * + * Calculates Laplacian of the image. + * self should be single-channel 8bit signed/unsigned or 32bit floating-point. + */ +VALUE +rb_laplace(int argc, VALUE *argv, VALUE self) +{ + VALUE aperture_size, dest; + if (rb_scan_args(argc, argv, "01", &aperture_size) < 1) + aperture_size = INT2FIX(3); + switch(CV_MAT_DEPTH(CVMAT(self)->type)) { + case CV_8U: + case CV_8S: + dest = new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_16S, 1)); + break; + case CV_32F: + dest = new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_32F, 1)); + break; + default: + rb_raise(rb_eNotImpError, "source depth should be CV_8U or CV_8S or CV_32F."); + } + cvLaplace(CVARR(self), CVARR(dest), NUM2INT(aperture_size)); + return dest; +} + +/* + * call-seq: + * canny(thresh1,thresh2[,aperture_size = 3]) -> cvmat + * + * Canny algorithm for edge detection. + */ +VALUE +rb_canny(int argc, VALUE *argv, VALUE self) +{ + VALUE thresh1, thresh2, aperture_size; + if (rb_scan_args(argc, argv, "21", &thresh1, &thresh2, &aperture_size) < 3) + aperture_size = INT2FIX(3); + VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvCanny(CVARR(self), CVARR(dest), NUM2INT(thresh1), NUM2INT(thresh2), NUM2INT(aperture_size)); + return dest; +} + +/* + * call-seq: + * pre_corner_detect([aperture_size = 3]) -> cvmat + * + * Calculates feature map for corner detection. + * aperture_size is parameter for sobel operator(see #sobel). + * + * The corners can be found as local maximums of the function. + */ +VALUE +rb_pre_corner_detect(int argc, VALUE *argv, VALUE self) +{ + VALUE aperture_size, dest; + if (rb_scan_args(argc, argv, "01", &aperture_size) < 1) + aperture_size = INT2FIX(3); + dest = new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_32F, 1)); + cvPreCornerDetect(CVARR(self), CVARR(dest), NUM2INT(aperture_size)); + return dest; +} + +/* + * call-seq: + * corner_eigenvv(block_size[,aperture_size]) -> cvmat + * + * For every pixel considers block_size x block_size neighborhood S(p). + * It calculates convariation matrix of derivatives over the neighborhood. + */ +VALUE +rb_corner_eigenvv(int argc, VALUE *argv, VALUE self) +{ + VALUE block_size, aperture_size, dest; + if (rb_scan_args(argc, argv, "11", &block_size, &aperture_size) < 1) + aperture_size = INT2FIX(3); + Check_Type(block_size, T_FIXNUM); + CvSize size = cvGetSize(CVARR(self)); + dest = new_object(cvSize(size.width * 6, size.height), CV_MAKETYPE(CV_32F, 1)); + cvCornerEigenValsAndVecs(CVARR(self), CVARR(dest), NUM2INT(block_size), NUM2INT(aperture_size)); + return dest; +} + +/* + * call-seq: + * corner_min_eigen_val(block_size[,aperture_size = 3]) -> cvmat + * + * Calculates minimal eigenvalue of gradient matrices for corner detection. + */ +VALUE +rb_corner_min_eigen_val(int argc, VALUE *argv, VALUE self) +{ + VALUE block_size, aperture_size, dest; + rb_scan_args(argc, argv, "11", &block_size, &aperture_size); + dest = new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_32F, 1)); + cvCornerMinEigenVal(CVARR(self), CVARR(dest), FIX2INT(block_size), FIX2INT(aperture_size)); + return dest; +} + +/* + * call-seq: + * corner_harris(block_size[,aperture_size = 3][,k = 0.04]) -> cvmat + * + * Return image Applied Harris edge detector. + */ +VALUE +rb_corner_harris(int argc, VALUE *argv, VALUE self) +{ + SUPPORT_8UC1_ONLY(self); + VALUE block_size, aperture_size, k, dest; + rb_scan_args(argc, argv, "12", &block_size, &aperture_size, &k); + dest = new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_32F, 1)); + cvCornerHarris(CVARR(self), CVARR(dest), FIX2INT(block_size), IF_INT(aperture_size, 3), IF_DBL(k, 0.04)); + return dest; +} + +/* + * call-seq: + * find_corner_sub_pix() + * + * Refines corner locations. + * This method iterates to find the sub-pixel accurate location of corners, + * or radial saddle points, as shown in on the picture below. + */ +VALUE +rbi_find_corner_sub_pix(int argc, VALUE *argv, VALUE self) +{ + /* + VALUE corners, win, zero_zone, criteria; + rb_scan_args(argc, argv, "13", &corners, &win, &zero_zone, &criteria); + if (!rb_obj_is_kind_of(corners, mPointSet::rb_module())) + rb_raise(rb_eTypeError, "argument 1 (corners) should be %s.", rb_class2name(mPointSet::rb_module())); + int count = CVSEQ(corners)->total; + VALUE storage = cCvMemStorage::new_object(); + CvPoint2D32f *pointset = POINTSET2D32f(corners); + //cvFindCornerSubPix(CVARR(self), pointset, count, VALUE_TO_CVSIZE(win), VALUE_TO_CVSIZE(zero_zone), VALUE_TO_CVTERMCRITERIA(criteria)); + //return cCvSeq::new_sequence(); + */ + return Qnil; +} + +VALUE +rb_good_features_to_track(int argc, VALUE *argv, VALUE self) +{ + VALUE quality_level, min_distance, good_features_to_track_option, eigen, tmp, storage; + rb_scan_args(argc, argv, "21", &quality_level, &min_distance, &good_features_to_track_option); + good_features_to_track_option = GOOD_FEATURES_TO_TRACK_OPTION(good_features_to_track_option); + CvMat *src = CVMAT(self); + eigen = cCvMat::new_object(cvGetSize(src), CV_MAKETYPE(CV_32F, 1)); + tmp = cCvMat::new_object(cvGetSize(src), CV_MAKETYPE(CV_32F, 1)); + int np = GF_MAX(good_features_to_track_option); + if(!(np > 0)) + rb_raise(rb_eArgError, "option :max should be positive value."); + CvPoint2D32f *p32 = (CvPoint2D32f*)cvAlloc(sizeof(CvPoint2D32f) * np); + if(!p32) + rb_raise(rb_eNoMemError, "failed allocate memory."); + cvGoodFeaturesToTrack(src, CVARR(eigen), CVARR(tmp), p32, &np, NUM2DBL(quality_level), NUM2DBL(min_distance), + GF_MASK(good_features_to_track_option), + GF_BLOCK_SIZE(good_features_to_track_option), + GF_USE_HARRIS(good_features_to_track_option), + GF_K(good_features_to_track_option)); + storage = cCvMemStorage::new_object(); + CvSeq *pseq = cvCreateSeq(CV_SEQ_POINT_SET, sizeof(CvSeq), sizeof(CvPoint2D32f), CVMEMSTORAGE(storage)); + cvSeqPushMulti(pseq, p32, np); + cvFree(&p32); + return cCvSeq::new_sequence(cCvSeq::rb_class(), pseq, cCvPoint2D32f::rb_class(), storage); +} + +/* + * call-seq: + * sample_line(p1, p2[,connectivity = 8]) {|pixel| } + * + * not yet. + */ +VALUE +rb_sample_line(int argc, VALUE *argv, VALUE self) +{ + /* + VALUE p1, p2, connectivity; + if (rb_scan_args(argc, argv, "21", &p1, &p2, &connectivity) < 3) + connectivity = INT2FIX(8); + CvPoint point1 = VALUE_TO_CVPOINT(p1), point2 = VALUE_TO_CVPOINT(p2); + int size; + switch(FIX2INT(connectivity)) { + case 4: + size = abs(point2.x - point1.x) + abs(point2.y - point1.y) + 1; + break; + case 8: + size = maxint(abs(point2.x - point1.x) + 1, abs(point2.y - point1.y) + 1); + break; + default: + rb_raise(rb_eArgError, "argument 3(connectivity) should be 4 or 8. 8 is default."); + } + VALUE buf = cCvMat::new_object(1, size, cvGetElemType(CVARR(self))); + cvSampleLine(CVARR(self), point1, point2, CVMAT(buf)->data.ptr, FIX2INT(connectivity)); + if (rb_block_given_p()) { + for(int i = 0; i < size; i++) { + //Data_Wrap_Struct(cCvScalar::rb_class(), 0, 0, CVMAT(buf)->data.ptr[]); + //rb_yield(cCvScalar::new_object); + } + } + return buf; + */ + return Qnil; +} + +/* + * call-seq: + * rect_sub_pix(center,size) -> cvmat + * + * Retrieves pixel rectangle from image with sub-pixel accuracy. + * Extracts pixels from self. + * dst(x,y) = self(x + center.x - (size.width - 1) * 0.5, y + center.y - (size.height - 1) * 0.5) + * where the values of pixels at non-integer coordinates are retrived using bilinear iterpolation. + * Every channel of multiple-channel images is processed independently. + * Whereas the rectangle center must be inside the image, the whole rectangle may be partially occludedl. + * In this case, the replication border mode is used to get pixel values beyond the image boundaries. + */ +VALUE +rb_rect_sub_pix(VALUE self, VALUE center, VALUE size) +{ + VALUE dest = new_object(VALUE_TO_CVSIZE(size), cvGetElemType(CVARR(self))); + cvGetRectSubPix(CVARR(self), CVARR(dest), VALUE_TO_CVPOINT2D32F(center)); + return dest; +} + +/* + * call-seq: + * quandrangle_sub_pix(map_matrix) -> cvmat + * + * Retrives pixel quadrangle from image with sub-pixel accuracy. + * Extracts pixel from self at sub-pixel accuracy and store them: + */ +VALUE +rb_quadrangle_sub_pix(VALUE self, VALUE map_matrix, VALUE size) +{ + if (!rb_obj_is_kind_of(map_matrix, cCvMat::rb_class())) + rb_raise(rb_eTypeError, "argument 1 (map matrix) should be %s (2x3).", rb_class2name(cCvMat::rb_class())); + VALUE dest = new_object(VALUE_TO_CVSIZE(size), cvGetElemType(CVARR(self))); + cvGetQuadrangleSubPix(CVARR(self), CVARR(dest), CVMAT(map_matrix)); + return dest; +} + +/* + * call-seq: + * resize(size[,interpolation = :linear]) -> cvmat + * + * Resize image. + * interpolation is interpolation method: + * * :nn + * nearest-neighbor interpolation. + * * :linear + * bilinear interpolation (used by default) + * * :area + * resampling using pixel area relation. It is preferred method for image decimation that give moire-free results. + * In case of zooming it is similar to NN method. + * * :cubic + * bicubic interpolation. + * Return self resized image that it fits exactly to size. If ROI is set, the method consideres the ROI as supported as usual. + */ +VALUE +rb_resize(int argc, VALUE *argv, VALUE self) +{ + VALUE size, interpolation; + rb_scan_args(argc, argv, "11", &size, &interpolation); + VALUE dest = new_object(VALUE_TO_CVSIZE(size), cvGetElemType(CVARR(self))); + cvResize(CVARR(self), CVARR(dest), CVMETHOD("INTERPOLATION_METHOD", interpolation, CV_INTER_LINEAR)); + return self; +} + +/* + * call-seq: + * warp_affine(map_matrix[,interpolation = :linear][,option = :fill_outliers][,fillval = 0]) -> cvmat + * + * Applies affine transformation to the image. + */ +VALUE +rb_warp_affine(int argc, VALUE *argv, VALUE self) +{ + VALUE map_matrix, interpolation, option, fill_value; + if (rb_scan_args(argc, argv, "13", &map_matrix, &interpolation, &option, &fill_value) < 4) + fill_value = INT2FIX(0); + if (!rb_obj_is_kind_of(map_matrix, cCvMat::rb_class())) + rb_raise(rb_eTypeError, "argument 1 (map matrix) should be %s (2x3).", rb_class2name(cCvMat::rb_class())); + VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvWarpAffine(CVARR(self), CVARR(dest), CVMAT(map_matrix), + CVMETHOD("INTERPOLATION_METHOD", interpolation, CV_INTER_LINEAR) | CVMETHOD("WARP_FLAG", option, CV_WARP_FILL_OUTLIERS), VALUE_TO_CVSCALAR(fill_value)); + return dest; +} + +/* + * call-seq: + * CvMat.rotation(center,angle,scale) -> cvmat + * + * Create new affine matrix of 2D rotation (2x3 32bit floating-point matrix). + * center is center of rotation (x, y). + * angle is rotation angle in degrees. + * Positive values mean counter-clockwise rotation + * (the coordinate origin is assumed at top-left corner). + * scale is isotropic scale factor. + * + * [ a b | (1 - a) * center.x - b * center.y ] + * [-b a | (b * center.x + (1 + a) * center.y ] + * where a = scale * cos(angle), b = scale * sin(angle) + */ +VALUE +rb_rotation(VALUE self, VALUE center, VALUE angle, VALUE scale) +{ + VALUE map_matrix = new_object(cvSize(3,2), CV_MAKETYPE(CV_32F, 1)); + cv2DRotationMatrix(VALUE_TO_CVPOINT2D32F(center), NUM2DBL(angle), NUM2DBL(scale), CVMAT(map_matrix)); + return map_matrix; +} + +/* + * call-seq: + * warp_perspective(map_matrix[,interpolation=:linear][,option =:fill_outliers][,fillval=0])) -> cvmat + * + * Applies perspective transformation to the image. + */ +VALUE +rb_warp_perspective(int argc, VALUE *argv, VALUE self) +{ + VALUE map_matrix, interpolation, option, fillval; + if (rb_scan_args(argc, argv, "13", &map_matrix, &interpolation, &option, &fillval) < 4) + fillval = INT2FIX(0); + if (!rb_obj_is_kind_of(map_matrix, cCvMat::rb_class())) + rb_raise(rb_eTypeError, "argument 1 (map matrix) should be %s (3x3).", rb_class2name(cCvMat::rb_class())); + VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvWarpPerspective(CVARR(self), CVARR(dest), CVMAT(map_matrix), + CVMETHOD("INTERPOLATION_METHOD", interpolation, CV_INTER_LINEAR) | CVMETHOD("WARP_FLAG", option, CV_WARP_FILL_OUTLIERS), VALUE_TO_CVSCALAR(fillval)); + return dest; +} + +/* + * call-seq: + * remap(mapx,mapy[,interpolation=:linear][,option=:fill_outliers][,fillval=0]) -> cvmat + * + * Applies generic geometrical transformation to the image. + * Transforms source image using the specified map: + * dst(x,y)<-src(mapx(x,y),mapy(x,y)) + * Similar to other geometrical transformations, some interpolation method (specified by user) is used to + * extract pixels with non-integer coordinates. + */ +VALUE +rb_remap(int argc, VALUE *argv, VALUE self) +{ + VALUE mapx, mapy, interpolation, option, fillval; + if (rb_scan_args(argc, argv, "23", &mapx, &mapy, &interpolation, &option, &fillval) < 5) + fillval = INT2FIX(0); + if (!rb_obj_is_kind_of(mapx, cCvMat::rb_class())) + rb_raise(rb_eTypeError, "argument 1 (map of x-coordinates) should be %s(CV_32F and single-channel).", rb_class2name(cCvMat::rb_class())); + if (!rb_obj_is_kind_of(mapy, cCvMat::rb_class())) + rb_raise(rb_eTypeError, "argument 2 (map of y-coordinates) should be %s(CV_32F and single-channel).", rb_class2name(cCvMat::rb_class())); + VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvRemap(CVARR(self), CVARR(dest), CVARR(mapx), CVARR(mapy), + CVMETHOD("INTERPOLATION_METHOD", interpolation, CV_INTER_LINEAR) | CVMETHOD("WARP_FLAG", option, CV_WARP_FILL_OUTLIERS), VALUE_TO_CVSCALAR(fillval)); + return dest; +} + +/* + * call-seq: + * log_polar(center, magnitude, ) + * + * Remaps image to log-polar space. + */ +VALUE +rb_log_polar(int argc, VALUE *argv, VALUE self) +{ + /* + VALUE size, center, m, flags, fillval, dest; + rb_scan_args(argc, argv, "3*", &size, ¢er, &m, &flags); + dest = cCvMat::new_object(); + cvLogPolar(CVARR(self), CVARR(dest), + VALUE_TO_CVPOINT2D32F(center), NUM2DBL(m), + CVMETHOD("INTERPOLATION_METHOD", interpolation, CV_INTER_LINEAR) | CVMETHOD("WARP_FLAG", option, CV_WARP_FILL_OUTLIEARS), VALUE_TO_CVSCALAR(fillval)); + return dest; + */ + return Qnil; +} + +/* + * call-seq: + * erode([element = nil, iteration = 1]) -> cvmat + * + * Create erodes image by using arbitrary structuring element. + * element is structuring element used for erosion. + * element should be IplConvKernel. If it is nil, a 3x3 rectangular structuring element is used. + * iterations is number of times erosion is applied. + */ +VALUE +rb_erode(int argc, VALUE *argv, VALUE self) +{ + return rb_erode_bang(argc, argv, rb_clone(self)); +} + +/* + * call-seq: + * erode!([element = nil][,iteration = 1]) -> self + * + * Erodes image by using arbitrary structuring element. + * see also #erode. + */ +VALUE +rb_erode_bang(int argc, VALUE *argv, VALUE self) +{ + VALUE element, iteration; + rb_scan_args(argc, argv, "02", &element, &iteration); + cvErode(CVARR(self), CVARR(self), IPLCONVKERNEL(element), IF_INT(iteration, 1)); + return self; +} + +/* + * call-seq: + * dilate([element = nil][,iteration = 1]) -> cvmat + * + * Create dilates image by using arbitrary structuring element. + * element is structuring element used for erosion. + * element should be IplConvKernel. If it is nil, a 3x3 rectangular structuring element is used. + * iterations is number of times erosion is applied. + */ +VALUE +rb_dilate(int argc, VALUE *argv, VALUE self) +{ + return rb_dilate_bang(argc, argv, rb_clone(self)); +} + +/* + * call-seq: + * dilate!([element = nil][,iteration = 1]) -> self + * + * Dilate image by using arbitrary structuring element. + * see also #dilate. + */ +VALUE +rb_dilate_bang(int argc, VALUE *argv, VALUE self) +{ + VALUE element, iteration; + rb_scan_args(argc, argv, "02", &element, &iteration); + cvDilate(CVARR(self), CVARR(self), IPLCONVKERNEL(element), IF_INT(iteration, 1)); + return self; +} + +/* + * call-seq: + * morpholohy_open([element = nil][,iteration = 1]) -> cvmat + * + * Performs advanced morphological transformations "Opening". + * dilate(erode(src,element),element) + */ +VALUE +rb_morphology_open(int argc, VALUE *argv, VALUE self) +{ + VALUE element, iteration, dest; + rb_scan_args(argc, argv, "02", &element, &iteration); + dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvMorphologyEx(CVARR(self), CVARR(dest), 0, IPLCONVKERNEL(element), CV_MOP_OPEN, IF_INT(iteration, 1)); + return dest; +} + +/* + * call-seq: + * morpholohy_close([element = nil][,iteration = 1]) -> cvmat + * + * Performs advanced morphological transformations "Closing". + * erode(dilate(src,element),element) + */ +VALUE +rb_morphology_close(int argc, VALUE *argv, VALUE self) +{ + VALUE element, iteration, dest; + rb_scan_args(argc, argv, "02", &element, &iteration); + dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvMorphologyEx(CVARR(self), CVARR(dest), 0, IPLCONVKERNEL(element), CV_MOP_CLOSE, IF_INT(iteration, 1)); + return dest; +} + +/* + * call-seq: + * morpholohy_gradient([element = nil][,iteration = 1]) -> cvmat + * + * Performs advanced morphological transformations "Morphological gradient". + * dilate(src,element)-erode(src,element) + */ +VALUE +rb_morphology_gradient(int argc, VALUE *argv, VALUE self) +{ + VALUE element, iteration, temp, dest; + rb_scan_args(argc, argv, "02", &element, &iteration); + temp = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvMorphologyEx(CVARR(self), CVARR(dest), CVARR(temp), IPLCONVKERNEL(element), CV_MOP_GRADIENT, IF_INT(iteration, 1)); + return dest; +} + +/* + * call-seq: + * morpholohy_tophat([element = nil][,iteration = 1]) -> cvmat + * + * Performs advanced morphological transformations "tophat". + * src-open(src,element) + */ +VALUE +rb_morphology_tophat(int argc, VALUE *argv, VALUE self) +{ + VALUE element, iteration, dest; + rb_scan_args(argc, argv, "02", &element, &iteration); + dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvMorphologyEx(CVARR(self), CVARR(dest), 0, IPLCONVKERNEL(element), CV_MOP_TOPHAT, IF_INT(iteration, 1)); + return dest; +} + +/* + * call-seq: + * morpholohy_blackhat([element = nil][,iteration = 1]) -> cvmat + * + * Performs advanced morphological transformations "blackhat". + * close(src,element)-src + */ +VALUE +rb_morphology_blackhat(int argc, VALUE *argv, VALUE self) +{ + VALUE element, iteration, dest; + rb_scan_args(argc, argv, "02", &element, &iteration); + dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvMorphologyEx(CVARR(self), CVARR(dest), 0, IPLCONVKERNEL(element), CV_MOP_BLACKHAT, IF_INT(iteration, 1)); + return dest; +} + +/* + * call-seq: + * smooth_blur_no_scale([p1 = 3, p2 = 3]) -> cvmat + * + * Smooths the image by simple blur with no scaling. + * * 8bit unsigned -> return 16bit unsigned + * * 8bit signed -> return 16bit signed + * * 32bit floating point -> return 32bit floating point + * support single-channel image only. + */ +VALUE +rb_smooth_blur_no_scale(int argc, VALUE *argv, VALUE self) +{ + SUPPORT_C1_ONLY(self); + VALUE p1, p2, dest; + rb_scan_args(argc, argv, "02", &p1, &p2); + int type = cvGetElemType(CVARR(self)), dest_type; + switch (CV_MAT_DEPTH(type)) { + case CV_8U: + dest_type = CV_16U; + break; + case CV_8S: + dest_type = CV_16S; + break; + case CV_32F: + dest_type = CV_32F; + break; + default: + rb_raise(rb_eNotImpError, "unsupport format. (support 8bit unsigned/signed or 32bit floating point only)"); + } + dest = new_object(cvGetSize(CVARR(self)), dest_type); + cvSmooth(CVARR(self), CVARR(dest), CV_BLUR_NO_SCALE, IF_INT(p1, 3), IF_INT(p2, 0)); + return dest; +} + +/* + * call-seq: + * smooth_blur([p1 = 3, p2 = 3]) -> cvmat + * + * Smooths the image by simple blur. + * Summation over a pixel p1 x p2 neighborhood with subsequent scaling by 1 / (p1*p2). + */ +VALUE +rb_smooth_blur(int argc, VALUE *argv, VALUE self) +{ + SUPPORT_C1C3_ONLY(self); + VALUE p1, p2, dest; + rb_scan_args(argc, argv, "02", &p1, &p2); + dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvSmooth(CVARR(self), CVARR(dest), CV_BLUR, IF_INT(p1, 3), IF_INT(p2, 0)); + return dest; +} + +/* + * call-seq: + * smooth_gaussian([p1 = 3, p2 = 3, p3 = 0.0, p4 = 0.0]) -> cvmat + * + * Smooths the image by gaussian blur. + * Convolving image with p1 x p2 Gaussian kernel. + * + * p3 may specify Gaussian sigma (standard deviation). + * If it is zero, it is calculated from the kernel size: + * sigma = (n/2 - 1)*0.3 + 0.8, where n = p1 for horizontal kernel, + * n = p2 for vertical kernel. + * + * p4 is in case of non-square Gaussian kernel the parameter. + * It may be used to specify a different (from p3) sigma in the vertical direction. + */ +VALUE +rb_smooth_gaussian(int argc, VALUE *argv, VALUE self) +{ + SUPPORT_C1C3_ONLY(self); + VALUE p1, p2, p3, p4, dest; + rb_scan_args(argc, argv, "04", &p1, &p2, &p3, p4); + dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvSmooth(CVARR(self), CVARR(dest), CV_GAUSSIAN, IF_INT(p1, 3), IF_INT(p2, 0), IF_DBL(p3, 0.0), IF_DBL(p4, 0.0)); + return dest; +} + +/* + * call-seq: + * smooth_median([p1 = 3]) -> cvmat + * + * Smooths the image by median blur. + * Finding median of p1 x p1 neighborhood (i.e. the neighborhood is square). + */ +VALUE +rb_smooth_median(int argc, VALUE *argv, VALUE self) +{ + SUPPORT_8U_ONLY(self); + SUPPORT_C1C3_ONLY(self); + VALUE p1, dest; + rb_scan_args(argc, argv, "01", &p1); + dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvSmooth(CVARR(self), CVARR(dest), CV_MEDIAN, IF_INT(p1, 3)); + return dest; +} + +/* + * call-seq: + * smooth_bilateral([p1 = 3][p2 = 3]) -> cvmat + * + * Smooths the image by bilateral filter. + * Applying bilateral 3x3 filtering with color sigma=p1 and space sigma=p2. + */ +VALUE +rb_smooth_bilateral(int argc, VALUE *argv, VALUE self) +{ + SUPPORT_8U_ONLY(self); + SUPPORT_C1C3_ONLY(self); + VALUE p1, p2, dest; + rb_scan_args(argc, argv, "02", &p1, &p2); + dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvSmooth(CVARR(self), CVARR(dest), CV_BILATERAL, IF_INT(p1, 3), IF_INT(p2, 0)); + return dest; +} + +/* + * call-seq: + * filter2d(kernel[,anchor]) -> cvmat + * + * Convolves image with the kernel. + * Convolution kernel, single-channel floating point matrix (or same depth of self's). + * If you want to apply different kernels to different channels, + * split the image using CvMat#split into separate color planes and process them individually. + */ +VALUE +rb_filter2d(int argc, VALUE *argv, VALUE self) +{ + VALUE kernel, anchor, dest; + rb_scan_args(argc, argv, "11", &kernel, &anchor); + if (!rb_obj_is_kind_of(kernel, cCvMat::rb_class())) + rb_raise(rb_eTypeError, "argument 1 (kernel) should be %s.", rb_class2name(cCvMat::rb_class())); + int type = cvGetElemType(CVARR(kernel)); + dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvFilter2D(CVARR(self), CVARR(dest), CVMAT(kernel), NIL_P(anchor) ? cvPoint(-1,-1) : VALUE_TO_CVPOINT(anchor)); + return dest; +} + +/* + * call-seq: + * copy_make_border_constant(size, offset[,value = CvScalar.new(0)]) + * + * Copies image and makes border around it. + * Border is filled with the fixed value, passed as last parameter of the function. + */ +VALUE +rb_copy_make_border_constant(int argc, VALUE *argv, VALUE self) +{ + VALUE size, offset, value, dest; + rb_scan_args(argc, argv, "21", &size, &offset, &value); + dest = cCvMat::new_object(VALUE_TO_CVSIZE(size), cvGetElemType(CVARR(self))); + cvCopyMakeBorder(CVARR(self), CVARR(dest), VALUE_TO_CVPOINT(offset), IPL_BORDER_CONSTANT, NIL_P(value) ? cvScalar(0) : VALUE_TO_CVSCALAR(value)); + return dest; +} + +/* + * call-seq: + * copy_make_border_replicate(size, offset) + * + * Copies image and makes border around it. + * The pixels from the top and bottom rows, + * the left-most and right-most columns are replicated to fill the border. + */ +VALUE +rb_copy_make_border_replicate(int argc, VALUE *argv, VALUE self) +{ + VALUE size, offset, dest; + rb_scan_args(argc, argv, "20", &size, &offset); + dest = cCvMat::new_object(VALUE_TO_CVSIZE(size), cvGetElemType(CVARR(self))); + cvCopyMakeBorder(CVARR(self), CVARR(dest), VALUE_TO_CVPOINT(offset), IPL_BORDER_REPLICATE); + return dest; +} + +/* + * call-seq: + * integral(need_sqsum = false, need_tilted_sum = false) -> [cvmat, cvmat or nil, cvmat or nil] + * + * Calculates integral images. + * If need_sqsum = true, calculate the integral image for squared pixel values. + * If need_tilted_sum = true, calculate the integral for the image rotated by 45 degrees. + * + * sum(X,Y)=sumxthreshold, max_value[,use_otsu = false]) + * + * Applies fixed-level threshold to array elements. + * + * dst(x,y) = max_value, if src(x,y)>threshold + * 0, otherwise + */ +VALUE +rb_threshold_binary(int argc, VALUE *argv, VALUE self) +{ + VALUE threshold, max_value, use_otsu, dest; + rb_scan_args(argc, argv, "21", &threshold, &max_value, &use_otsu); + dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvThreshold(CVARR(self), CVARR(dest), NUM2DBL(threshold), NUM2DBL(max_value), CV_THRESH_BINARY | (use_otsu == Qtrue ? CV_THRESH_OTSU : 0)); + return dest; +} + +/* + * call-seq: + * threshold_binary_inverse(threshold, max_value[,use_otsu = false]) + * + * Applies fixed-level threshold to array elements. + * + * dst(x,y) = 0, if src(x,y)>threshold + * max_value, otherwise + */ +VALUE +rb_threshold_binary_inverse(int argc, VALUE *argv, VALUE self) +{ + VALUE threshold, max_value, use_otsu, dest; + rb_scan_args(argc, argv, "21", &threshold, &max_value, &use_otsu); + dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvThreshold(CVARR(self), CVARR(dest), NUM2DBL(threshold), NUM2DBL(max_value), CV_THRESH_BINARY_INV | (use_otsu == Qtrue ? CV_THRESH_OTSU : 0)); + return dest; +} + +/* + * call-seq: + * threshold_trunc(threshold[,use_otsu = false]) + * + * Applies fixed-level threshold to array elements. + * + * dst(x,y) = threshold, if src(x,y)>threshold + * src(x,y), otherwise + */ +VALUE +rb_threshold_trunc(int argc, VALUE *argv, VALUE self) +{ + VALUE threshold, use_otsu, dest; + rb_scan_args(argc, argv, "11", &threshold, &use_otsu); + dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvThreshold(CVARR(self), CVARR(dest), NUM2DBL(threshold), 0, CV_THRESH_BINARY_INV | (use_otsu == Qtrue ? CV_THRESH_OTSU : 0)); + return dest; +} + +/* + * call-seq: + * threshold_to_zero(threshold[,use_otsu = false]) + * + * Applies fixed-level threshold to array elements. + * + * dst(x,y) = src(x,y), if src(x,y)>threshold + * 0, otherwise + */ +VALUE +rb_threshold_to_zero(int argc, VALUE *argv, VALUE self) +{ + VALUE threshold, use_otsu, dest; + rb_scan_args(argc, argv, "11", &threshold, &use_otsu); + dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvThreshold(CVARR(self), CVARR(dest), NUM2DBL(threshold), 0, CV_THRESH_TOZERO | (use_otsu == Qtrue ? CV_THRESH_OTSU : 0)); + return dest; +} + +/* + * call-seq: + * threshold_to_zero_inverse(threshold[,use_otsu = false]) + * + * Applies fixed-level threshold to array elements. + * + * dst(x,y) = 0, if src(x,y)>threshold + * src(x,y), otherwise + */ +VALUE +rb_threshold_to_zero_inverse(int argc, VALUE *argv, VALUE self) +{ + VALUE threshold, use_otsu, dest; + rb_scan_args(argc, argv, "11", &threshold, &use_otsu); + dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvThreshold(CVARR(self), CVARR(dest), NUM2DBL(threshold), 0, CV_THRESH_TOZERO_INV | (use_otsu == Qtrue ? CV_THRESH_OTSU : 0)); + return dest; +} + +/* + * call-seq: + * pyr_down([filter = :gaussian_5x5]) -> cvmat + * + * Return downsamples image. + * + * This operation performs downsampling step of Gaussian pyramid decomposition. + * First it convolves source image with the specified filter and then downsamples the image by rejecting even rows and columns. + * + * note: filter - only :gaussian_5x5 is currently supported. + */ +VALUE +rb_pyr_down(int argc, VALUE *argv, VALUE self) +{ + VALUE filter_type, dest; + rb_scan_args(argc, argv, "01", &filter_type); + int filter = CV_GAUSSIAN_5x5; + if (argc > 0) { + switch (TYPE(filter_type)) { + case T_SYMBOL: + // currently suport CV_GAUSSIAN_5x5 only. + break; + default: + rb_raise(rb_eArgError, "argument 1 (filter_type) should be Symbol."); + } + } + CvSize size = cvGetSize(CVARR(self)); + dest = cCvMat::new_object(size.height / 2, size.width / 2, cvGetElemType(CVARR(self))); + cvPyrDown(CVARR(self), CVARR(dest), filter); + return dest; +} + +/* + * call-seq: + * pyr_up([filter = :gaussian_5x5]) -> cvmat + * + * Return upsamples image. + * + * This operation performs up-sampling step of Gaussian pyramid decomposition. + * First it upsamples the source image by injecting even zero rows and columns and then convolves result with the specified filter multiplied by 4 for interpolation. + * So the destination image is four times larger than the source image. + * + * note: filter - only :gaussian_5x5 is currently supported. + */ +VALUE +rb_pyr_up(int argc, VALUE *argv, VALUE self) +{ + VALUE filter_type, dest; + rb_scan_args(argc, argv, "01", &filter_type); + int filter = CV_GAUSSIAN_5x5; + if (argc > 0) { + switch (TYPE(filter_type)) { + case T_SYMBOL: + // currently suport CV_GAUSSIAN_5x5 only. + break; + default: + rb_raise(rb_eArgError, "argument 1 (filter_type) should be Symbol."); + } + } + CvSize size = cvGetSize(CVARR(self)); + dest = cCvMat::new_object(size.height * 2, size.width * 2, cvGetElemType(CVARR(self))); + cvPyrUp(CVARR(self), CVARR(dest), filter); + return dest; +} + +/* + * call-seq: + * flood_fill(seed_point, new_val, lo_diff, up_diff[,flood_fill_option]) -> [cvmat, cvconnectedcomp, iplimage(mask)] + * + * Return image filled a connnected compoment with given color. + * This operation fills a connected component starting from the seed point with the specified color. + * The connectivity is determined by the closeness of pixel values. + * The pixel at (x, y) is considered to belong to the repainted domain if: + * + * src(x',y')-lo_diff<=src(x,y)<=src(x',y')+up_diff, grayscale image, floating range + * src(seed.x,seed.y)-lo<=src(x,y)<=src(seed.x,seed.y)+up_diff, grayscale image, fixed range + * src(x',y')r-lo_diffr<=src(x,y)r<=src(x',y')r+up_diffr and + * src(x',y')g-lo_diffg<=src(x,y)g<=src(x',y')g+up_diffg and + * src(x',y')b-lo_diffb<=src(x,y)b<=src(x',y')b+up_diffb, color image, floating range + * src(seed.x,seed.y)r-lo_diffr<=src(x,y)r<=src(seed.x,seed.y)r+up_diffr and + * src(seed.x,seed.y)g-lo_diffg<=src(x,y)g<=src(seed.x,seed.y)g+up_diffg and + * src(seed.x,seed.y)b-lo_diffb<=src(x,y)b<=src(seed.x,seed.y)b+up_diffb, color image, fixed range + * + * where src(x',y') is value of one of pixel neighbors. + * That is, to be added to the connected component, a pixel's color/brightness should be close enough to: + * * color/brightness of one of its neighbors that are already referred to the connected component in case of floating range + * * color/brightness of the seed point in case of fixed range. + * + * arguments + * * seed_point -The starting point. + * * new_val - New value of repainted domain pixels. + * * lo_diff - Maximal lower brightness/color difference between the currently observed pixel and one of its neighbor belong to the component or seed pixel to add the pixel to component. In case of 8-bit color images it is packed value. + * * up_diff - Maximal upper brightness/color difference between the currently observed pixel and one of its neighbor belong to the component or seed pixel to add the pixel to component. In case of 8-bit color images it is packed value. + * + * and flood_fill_option + * :connectivity => 4 or 8, 4 default + * Connectivity determines which neighbors of a pixel are considered. + * :fixed_range => true or false, false default + * If set the difference between the current pixel and seed pixel is considered, otherwise difference between neighbor pixels is considered (the range is floating). + * :mask_only => true or false, false default + * If set, the function does not fill the image(new_val is ignored), but the fills mask. + * + * note: flood_fill_option's default value is CvMat::FLOOD_FILL_OPTION. + */ +VALUE +rb_flood_fill(int argc, VALUE *argv, VALUE self) +{ + return rb_flood_fill_bang(argc, argv, copy(self)); +} + +/* + * call-seq: + * flood_fill!(seed_point, new_val, lo_diff, up_diff[,flood_fill_option]) -> [self, cvconnectedcomp, iplimage(mask)] + * + * Fills a connected component with given color. + * see CvMat#flood_fill + */ +VALUE +rb_flood_fill_bang(int argc, VALUE *argv, VALUE self) +{ + VALUE seed_point, new_val, lo_diff, up_diff, flood_fill_option, mask, comp; + rb_scan_args(argc, argv, "23", &seed_point, &new_val, &lo_diff, &up_diff, &flood_fill_option); + flood_fill_option = FLOOD_FILL_OPTION(flood_fill_option); + int flags = FF_CONNECTIVITY(flood_fill_option); + if (FF_FIXED_RANGE(flood_fill_option)) { + flags |= CV_FLOODFILL_FIXED_RANGE; + } + if (FF_MASK_ONLY(flood_fill_option)) { + flags |= CV_FLOODFILL_MASK_ONLY; + } + CvSize size = cvGetSize(CVARR(self)); + mask = cIplImage::new_object(size.width + 2, size.height + 2, CV_MAKETYPE(CV_8U, 1)); + comp = cCvConnectedComp::new_object(); + cvFloodFill(CVARR(self), + VALUE_TO_CVPOINT(seed_point), + VALUE_TO_CVSCALAR(new_val), + NIL_P(lo_diff) ? cvScalar(0) : VALUE_TO_CVSCALAR(lo_diff), + NIL_P(lo_diff) ? cvScalar(0) : VALUE_TO_CVSCALAR(up_diff), + CVCONNECTEDCOMP(comp), + flags, + CVARR(mask)); + cvSetImageROI(IPLIMAGE(mask), cvRect(1, 1, size.width, size.height)); + return rb_ary_new3(3, self, comp, mask); +} + +/* + * call-seq: + * find_contours([find_contours_options]) -> cvchain or chcontour or nil + * + * Finds contours in binary image, and return contours as CvContour or CvChain. + * If contours not found, return nil. + * + * flood_fill_option should be Hash include these keys. + * :mode - Retrieval mode. + * :external - retrive only the extreme outer contours + * :list - retrieve all the contours and puts them in the list.(default) + * :ccomp - retrieve all the contours and organizes them into two-level hierarchy: + * top level are external boundaries of the components, second level are bounda boundaries of the holes + * :tree - retrieve all the contours and reconstructs the full hierarchy of nested contours + * Connectivity determines which neighbors of a pixel are considered. + * :method - Approximation method. + * :code - output contours in the Freeman chain code. All other methods output polygons (sequences of vertices). + * :approx_none - translate all the points from the chain code into points; + * :approx_simple - compress horizontal, vertical, and diagonal segments, that is, the function leaves only their ending points;(default) + * :approx_tc89_l1 + * :approx_tc89_kcos - apply one of the flavors of Teh-Chin chain approximation algorithm. + * If set the difference between the current pixel and seed pixel is considered, + * otherwise difference between neighbor pixels is considered (the range is floating). + * :offset - Offset, by which every contour point is shifted. + * This is useful if the contours are extracted from the image ROI + * and then they should be analyzed in the whole image context. Should be CvPoint. + * + * note: find_contours_option's default value is CvMat::FIND_CONTOURS_OPTION. + * + * support single-channel 8bit unsigned image only. + * + * note: Non-zero pixels are treated as 1's, zero pixels remain 0's + * that is image treated as binary. To get such a binary image from grayscale, + * one may use threshold, adaptive_threshold or canny. + */ +VALUE +rb_find_contours(int argc, VALUE *argv, VALUE self) +{ + SUPPORT_8UC1_ONLY(self); + return rb_find_contours_bang(argc, argv, copy(self)); +} + +/* + * call-seq: + * find_contours!([find_contours_options]) -> cvchain or chcontour or nil + * + * Finds contours in binary image. + * The function modifies the source image content. + * (Because the copy is not made, it is slightly faster than find_contours.) + * + * see find_contours + * + * support single-channel 8bit unsigned image only. + */ +VALUE +rb_find_contours_bang(int argc, VALUE *argv, VALUE self) +{ + SUPPORT_8UC1_ONLY(self); + VALUE find_contours_option, klass, element_klass, storage; + rb_scan_args(argc, argv, "01", &find_contours_option); + CvSeq *contour = 0; + find_contours_option = FIND_CONTOURS_OPTION(find_contours_option); + int mode = FC_MODE(find_contours_option); + int method = FC_METHOD(find_contours_option); + int header, header_size, element_size; + if (method == CV_CHAIN_CODE) { + klass = cCvChain::rb_class(); + element_klass = cCvChainCode::rb_class(); + header = CV_SEQ_CHAIN_CONTOUR; + header_size = sizeof(CvChain); + element_size = sizeof(CvChainCode); + } else { + klass = cCvContour::rb_class(); + element_klass = cCvPoint::rb_class(); + header = CV_SEQ_CONTOUR; + header_size = sizeof(CvContour); + element_size = sizeof(CvPoint); + } + storage = cCvMemStorage::new_object(); + if(cvFindContours(CVARR(self), CVMEMSTORAGE(storage), &contour, header, mode, method, FC_OFFSET(find_contours_option)) == 0) + return Qnil; + if(!contour) + contour = cvCreateSeq(header, header_size, element_size, CVMEMSTORAGE(storage)); + return cCvSeq::new_sequence(klass, contour, element_klass, storage); +} + +/* + * call-seq: + * pyr_segmentation(level, threshold1, threshold2) -> [cvmat, cvseq(include cvconnectedcomp)] + * + * Does image segmentation by pyramids. + * The pyramid builds up to the level level. + * The links between any pixel a on leveli and + * its candidate father pixel b on the adjacent level are established if + * p(c(a),c(b)) < threshold1. After the connected components are defined, they are joined into several clusters. Any two segments A and B belong to the same cluster, if + * p(c(A),c(B)) < threshold2. The input image has only one channel, then + * p(c^2,c^2)=|c^2-c^2|. If the input image has three channels (red, green and blue), then + * p(c^2,c^2)=0,3*(c^2 r-c^2 r)+0.59*(c^2 g-c^2 g)+0,11*(c^2 b-c^2 b) . There may be more than one connected component per a cluster. + * + * Return segmented image and sequence of connected components. + * support single-channel or 3-channel 8bit unsigned image only + */ +VALUE +rb_pyr_segmentation(int argc, VALUE *argv, VALUE self) +{ + SUPPORT_8U_ONLY(self); + SUPPORT_C1C3_ONLY(self); + VALUE level, threshold1, threshold2, storage, dest; + rb_scan_args(argc, argv, "30", &level, &threshold1, &threshold2); + IplImage *src = IPLIMAGE(self); + int l = FIX2INT(level); + double t1 = NUM2DBL(threshold1), t2 = NUM2DBL(threshold2); + if (!(l >0)) + rb_raise(rb_eArgError, "argument 1 (level) should be > 0."); + if(((src->width | src->height) & ((1 << l) -1 )) != 0) + rb_raise(rb_eArgError, "bad image size on level %d.", FIX2INT(level)); + if (t1 < 0) + rb_raise(rb_eArgError, "argument 2 (threshold for establishing the link) should be >= 0."); + if (t2 < 0) + rb_raise(rb_eArgError, "argument 3 (threshold for the segments clustering) should be >= 0."); + dest = cIplImage::new_object(cvGetSize(src), cvGetElemType(src)); + CvSeq *comp = 0; + storage = cCvMemStorage::new_object(); + + cvPyrSegmentation(src, + IPLIMAGE(dest), + CVMEMSTORAGE(storage), + &comp, + l, t1, t2); + if(!comp) + comp = cvCreateSeq(CV_SEQ_CONNECTED_COMP, sizeof(CvSeq), sizeof(CvConnectedComp), CVMEMSTORAGE(storage)); + return rb_ary_new3(2, dest, cCvSeq::new_sequence(cCvSeq::rb_class(), comp, cCvConnectedComp::rb_class(), storage)); +} + +/* + * call-seq: + * pyr_mean_shift_filtering(sp, sr[,max_level = 1][termcrit = CvTermCriteria.new(5,1)]) -> cvmat + * + * Does meanshift image segmentation. + * + * sp - The spatial window radius. + * sr - The color window radius. + * max_level - Maximum level of the pyramid for the segmentation. + * termcrit - Termination criteria: when to stop meanshift iterations. + * + * This method is implements the filtering stage of meanshift segmentation, + * that is, the output of the function is the filtered "posterized" image with color gradients and fine-grain texture flattened. + * At every pixel (X,Y) of the input image (or down-sized input image, see below) + * the function executes meanshift iterations, that is, the pixel (X,Y) neighborhood in the joint space-color hyperspace is considered: + * {(x,y): X-sp≤x≤X+sp && Y-sp≤y≤Y+sp && ||(R,G,B)-(r,g,b)|| ≤ sr}, + * where (R,G,B) and (r,g,b) are the vectors of color components at (X,Y) and (x,y), + * respectively (though, the algorithm does not depend on the color space used, + * so any 3-component color space can be used instead). + * Over the neighborhood the average spatial value (X',Y') + * and average color vector (R',G',B') are found and they act as the neighborhood center on the next iteration: + * (X,Y)~(X',Y'), (R,G,B)~(R',G',B'). + * After the iterations over, the color components of the initial pixel (that is, the pixel from where the iterations started) + * are set to the final value (average color at the last iteration): + * I(X,Y) <- (R*,G*,B*). + * Then max_level > 0, the gaussian pyramid of max_level+1 levels is built, + * and the above procedure is run on the smallest layer. + * After that, the results are propagated to the larger layer and the iterations are run again + * only on those pixels where the layer colors differ much (>sr) from the lower-resolution layer, + * that is, the boundaries of the color regions are clarified. + * + * Note, that the results will be actually different from the ones obtained by running the meanshift procedure on the whole original image (i.e. when max_level==0). + */ +VALUE +rb_pyr_mean_shift_filtering(int argc, VALUE *argv, VALUE self) +{ + VALUE spatial_window_radius, color_window_radius, max_level, termcrit, dest; + rb_scan_args(argc, argv, "22", &spatial_window_radius, &color_window_radius, &max_level, &termcrit); + dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvPyrMeanShiftFiltering(CVARR(self), CVARR(dest), + NUM2DBL(spatial_window_radius), + NUM2DBL(color_window_radius), + IF_INT(max_level, 1), + NIL_P(termcrit) ? cvTermCriteria(CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 5, 1) : VALUE_TO_CVTERMCRITERIA(termcrit)); + return dest; +} + +/* + * call-seq: + * watershed -> cvmat(mean markers:cv32s) + * + * Does watershed segmentation. + */ +VALUE +rb_watershed(VALUE self) +{ + VALUE markers = cCvMat::new_object(cvGetSize(CVARR(self)), CV_32SC1); + cvZero(CVARR(markers)); + cvWatershed(CVARR(self), CVARR(markers)); + return markers; +} + +/* + * call-seq: + * moments -> array(include CvMoments) + * + * Calculates moments. + */ +VALUE +rb_moments(int argc, VALUE *argv, VALUE self) +{ + VALUE is_binary, moments; + rb_scan_args(argc, argv, "01", &is_binary); + IplImage image = *IPLIMAGE(self); + int cn = CV_MAT_CN(cvGetElemType(CVARR(self))); + moments = rb_ary_new(); + for(int i = 1; i <= cn; i++) { + cvSetImageCOI(&image, i); + rb_ary_push(moments, cCvMoments::new_object(&image, TRUE_OR_FALSE(is_binary, 0))); + } + return moments; +} + +/* + * call-seq: + * hough_line_standard(rho, theta, threshold) -> cvseq(include CvLine) + * + * Finds lines in binary image using standard(classical) Hough transform. + * * rho - Distance resolution in pixel-related units. + * * 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. + */ +VALUE +rb_hough_lines_standard(int argc, VALUE *argv, VALUE self) +{ + SUPPORT_8UC1_ONLY(self); + VALUE rho, theta, threshold, storage; + rb_scan_args(argc, argv, "30", &rho, &theta, &threshold); + storage = cCvMemStorage::new_object(); + CvSeq *seq = cvHoughLines2(CVARR(copy(self)), CVMEMSTORAGE(storage), + CV_HOUGH_STANDARD, NUM2DBL(rho), NUM2DBL(theta), NUM2INT(threshold)); + return cCvSeq::new_sequence(cCvSeq::rb_class(), seq, cCvLine::rb_class(), storage); +} + +/* + * call-seq: + * hough_line_probabilistic(rho, theta, threshold, min_length, max_gap) -> cvseq(include CvTwoPoints) + * + * Finds lines in binary image using probabilistic Hough transform. + * * rho - Distance resolution in pixel-related units. + * * 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. + * * min_length - The minimum line length. + * * max_gap - The maximum gap between line segments lieing on the same line to treat them as the single line segment (i.e. to join them). + */ +VALUE +rb_hough_lines_probabilistic(int argc, VALUE *argv, VALUE self) +{ + SUPPORT_8UC1_ONLY(self); + VALUE rho, theta, threshold, p1, p2, storage; + rb_scan_args(argc, argv, "50", &rho, &theta, &threshold, &p1, &p2); + storage = cCvMemStorage::new_object(); + CvSeq *seq = cvHoughLines2(CVARR(copy(self)), CVMEMSTORAGE(storage), + CV_HOUGH_PROBABILISTIC, NUM2DBL(rho), NUM2DBL(theta), NUM2INT(threshold), + NUM2DBL(p1), NUM2DBL(p2)); + return cCvSeq::new_sequence(cCvSeq::rb_class(), seq, cCvTwoPoints::rb_class(), storage); +} + +/* + * call-seq: + * hough_line_multi_scale(rho, theta, threshold, div_rho, div_theta) -> cvseq(include CvLine) + * + * Finds lines in binary image using multi-scale variant of classical Hough transform. + * * rho - Distance resolution in pixel-related units. + * * 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. + * * div_rho = divisor for distance resolution rho. + * * div_theta = divisor for angle resolution theta. + */ +VALUE +rb_hough_lines_multi_scale(int argc, VALUE *argv, VALUE self) +{ + SUPPORT_8UC1_ONLY(self); + VALUE rho, theta, threshold, p1, p2, storage; + rb_scan_args(argc, argv, "50", &rho, &theta, &threshold, &p1, &p2); + storage = cCvMemStorage::new_object(); + CvSeq *seq = cvHoughLines2(CVARR(copy(self)), CVMEMSTORAGE(storage), + CV_HOUGH_MULTI_SCALE, NUM2DBL(rho), NUM2DBL(theta), NUM2INT(threshold), + NUM2DBL(p1), NUM2DBL(p2)); + return cCvSeq::new_sequence(cCvSeq::rb_class(), seq, cCvLine::rb_class(), storage); +} + +/* + * call-seq: + * hough_circles_gradient(dp, min_dist, threshold_canny, threshold_accumulate, min_radius = 0, max_radius = max(width,height)) -> cvseq(include CvCircle32f) + * + * Finds circles in grayscale image using Hough transform. + */ +VALUE +rb_hough_circles_gradient(int argc, VALUE *argv, VALUE self) +{ + SUPPORT_8UC1_ONLY(self); + VALUE dp, min_dist, threshold_canny, threshold_accumulate, min_radius, max_radius, storage; + rb_scan_args(argc, argv, "24", &dp, &min_dist, &threshold_canny, &threshold_accumulate, &min_radius, &max_radius); + storage = cCvMemStorage::new_object(); + CvSeq *seq = cvHoughCircles(CVARR(self), CVMEMSTORAGE(storage), + CV_HOUGH_GRADIENT, NUM2DBL(dp), NUM2DBL(min_dist), + NUM2DBL(threshold_canny), NUM2DBL(threshold_accumulate), + IF_INT(min_radius, 0), IF_INT(max_radius, 0)); + return cCvSeq::new_sequence(cCvSeq::rb_class(), seq, cCvCircle32f::rb_class(), storage); +} + +/* + * call-seq: + * inpaint_ns(mask, radius) -> cvmat + * + * Inpaints the selected region in the image by Navier-Stokes based method. + * The radius of circlular neighborhood of each point inpainted that is considered by the algorithm. + */ +VALUE +rb_inpaint_ns(VALUE self, VALUE mask, VALUE radius) +{ + SUPPORT_8U_ONLY(self); + SUPPORT_C1C3_ONLY(self); + VALUE dest; + if (!(rb_obj_is_kind_of(mask, cCvMat::rb_class())) || cvGetElemType(CVARR(mask)) != CV_8UC1) + rb_raise(rb_eTypeError, "argument 1 (mask) should be mask image."); + dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvInpaint(CVARR(self), CVARR(mask), CVARR(dest), NUM2DBL(radius), CV_INPAINT_NS); + return dest; +} + +/* + * call-seq: + * inpaint_telea(mask, radius) -> cvmat + * + * Inpaints the selected region in the image by The method by Alexandru Telea's method. + * The radius of circlular neighborhood of each point inpainted that is considered by the algorithm. + */ +VALUE +rb_inpaint_telea(VALUE self, VALUE mask, VALUE radius) +{ + SUPPORT_8U_ONLY(self); + SUPPORT_C1C3_ONLY(self); + VALUE dest; + if (!(rb_obj_is_kind_of(mask, cCvMat::rb_class())) || cvGetElemType(CVARR(mask)) != CV_8UC1) + rb_raise(rb_eTypeError, "argument 1 (mask) should be mask image."); + dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvInpaint(CVARR(self), CVARR(mask), CVARR(dest), NUM2DBL(radius), CV_INPAINT_TELEA); + return dest; +} + +/* + * call-seq: + * equalize_hist - cvmat + * + * Equalize histgram of grayscale of image. + * + * equalizes histogram of the input image using the following algorithm: + * 1. calculate histogram H for src. + * 2. normalize histogram, so that the sum of histogram bins is 255. + * 3. compute integral of the histogram: + * H’(i) = sum0≤j≤iH(j) + * 4. transform the image using H’ as a look-up table: dst(x,y)=H’(src(x,y)) + * The algorithm normalizes brightness and increases contrast of the image. + * + * support single-channel 8bit image (grayscale) only. + */ +VALUE +rb_equalize_hist(VALUE self) +{ + SUPPORT_8UC1_ONLY(self); + VALUE dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self))); + cvEqualizeHist(CVARR(self), CVARR(dest)); + return dest; +} + +/* + * call-seq: + * match_template(template[,method = :sqdiff]) -> cvmat(result) + * + * Compares template against overlapped image regions. + + * method is specifies the way the template must be compared with image regions. + * method should be following symbol. (see CvMat::MATCH_TEMPLATE_METHOD 's key and value.) + * + * * :sqdiff + * R(x,y)=sumx',y'[T(x',y')-I(x+x',y+y')]2 + * * :sqdiff_normed + * R(x,y)=sumx',y'[T(x',y')-I(x+x',y+y')]2/sqrt[sumx',y'T(x',y')2*sumx',y'I(x+x',y+y')2] + * * :ccorr + * R(x,y)=sumx',y'[T(x',y')*I(x+x',y+y')] + * * :ccorr_normed + * R(x,y)=sumx',y'[T(x',y')*I(x+x',y+y')]/sqrt[sumx',y'T(x',y')2*sumx',y'I(x+x',y+y')2] + * * :ccoeff + * R(x,y)=sumx',y'[T'(x',y')*I'(x+x',y+y')], + * where T'(x',y')=T(x',y') - 1/(w*h)*sumx",y"T(x",y") + * I'(x+x',y+y')=I(x+x',y+y') - 1/(w*h)*sumx",y"I(x+x",y+y") + * * :ccoeff_normed + * R(x,y)=sumx',y'[T'(x',y')*I'(x+x',y+y')]/sqrt[sumx',y'T'(x',y')2*sumx',y'I'(x+x',y+y')2] + * + * After the match_template finishes comparison, the best matches can be found as global + * minimums (:sqdiff*) or maximums(:ccorr* or :ccoeff*) using minmax function. + * In case of color image and template summation in both numerator and each sum in denominator + * is done over all the channels (and separate mean values are used for each channel). + */ +VALUE +rb_match_template(int argc, VALUE *argv, VALUE self) +{ + VALUE templ, method, result; + rb_scan_args(argc, argv, "11", &templ, &method); + if (!(rb_obj_is_kind_of(templ, cCvMat::rb_class()))) + rb_raise(rb_eTypeError, "argument 1 (template) should be %s.", rb_class2name(cCvMat::rb_class())); + if (cvGetElemType(CVARR(self)) != cvGetElemType(CVARR(templ))) + rb_raise(rb_eTypeError, "template should be same type of self."); + CvSize src_size = cvGetSize(CVARR(self)), template_size = cvGetSize(CVARR(self)); + result = cCvMat::new_object(cvSize(src_size.width - template_size.width + 1, + src_size.height - template_size.height + 1), + CV_32FC1); + cvMatchTemplate(CVARR(self), CVARR(templ), CVARR(result), CVMETHOD("MATCH_TEMPLATE_METHOD", CV_TM_SQDIFF)); + return result; +} + +/* + * call-seq: + * match_shapes_i1(object) -> float + * + * Compares two shapes(self and object). object should be CvMat or CvContour. + * + * A ~ object1, B - object2): + * I1(A,B)=sumi=1..7abs(1/mAi - 1/mBi) + */ +VALUE +rb_match_shapes_i1(int argc, VALUE *argv, VALUE self) +{ + VALUE object; + rb_scan_args(argc, argv, "10", &object); + if ((!(rb_obj_is_kind_of(object, cCvMat::rb_class()))) && (!(rb_obj_is_kind_of(object, cCvContour::rb_class())))) + rb_raise(rb_eTypeError, "argument 1 (shape) should be %s or %s", rb_class2name(cCvMat::rb_class()), rb_class2name(cCvContour::rb_class())); + return rb_float_new(cvMatchShapes(CVARR(self), CVARR(object), CV_CONTOURS_MATCH_I1)); +} + +/* + * call-seq: + * match_shapes_i2(object) -> float + * + * Compares two shapes(self and object). object should be CvMat or CvContour. + * + * A ~ object1, B - object2): + * I2(A,B)=sumi=1..7abs(mAi - mBi) + */ +VALUE +rb_match_shapes_i2(int argc, VALUE *argv, VALUE self) +{ + VALUE object; + rb_scan_args(argc, argv, "10", &object); + if ((!(rb_obj_is_kind_of(object, cCvMat::rb_class()))) && (!(rb_obj_is_kind_of(object, cCvContour::rb_class())))) + rb_raise(rb_eTypeError, "argument 1 (shape) should be %s or %s", rb_class2name(cCvMat::rb_class()), rb_class2name(cCvContour::rb_class())); + return rb_float_new(cvMatchShapes(CVARR(self), CVARR(object), CV_CONTOURS_MATCH_I2)); +} + +/* + * call-seq: + * match_shapes_i3(object) -> float + * + * Compares two shapes(self and object). object should be CvMat or CvContour. + * + * A ~ object1, B - object2): + * I3(A,B)=sumi=1..7abs(mAi - mBi)/abs(mAi) + */ +VALUE +rb_match_shapes_i3(int argc, VALUE *argv, VALUE self) +{ + VALUE object; + rb_scan_args(argc, argv, "10", &object); + if ((!(rb_obj_is_kind_of(object, cCvMat::rb_class()))) && (!(rb_obj_is_kind_of(object, cCvContour::rb_class())))) + rb_raise(rb_eTypeError, "argument 1 (shape) should be %s or %s", rb_class2name(cCvMat::rb_class()), rb_class2name(cCvContour::rb_class())); + return rb_float_new(cvMatchShapes(CVARR(self), CVARR(object), CV_CONTOURS_MATCH_I3)); +} + + +/* + * call-seq: + * mean_shift(window, criteria) -> comp + * + * Implements CAMSHIFT object tracking algrorithm. + * First, it finds an object center using mean_shift and, after that, + * calculates the object size and orientation. + */ +VALUE +rb_mean_shift(VALUE self, VALUE window, VALUE criteria) +{ + VALUE comp = cCvConnectedComp::new_object(); + cvMeanShift(CVARR(self), VALUE_TO_CVRECT(window), VALUE_TO_CVTERMCRITERIA(criteria), CVCONNECTEDCOMP(comp)); + return comp; +} + +/* + * call-seq: + * cam_shift(window, criteria) -> [comp, box] + * + * Implements CAMSHIFT object tracking algrorithm. First, it finds an object center using cvMeanShift and, + * after that, calculates the object size and orientation. The function returns number of iterations made + * within cvMeanShift. + */ +VALUE +rb_cam_shift(VALUE self, VALUE window, VALUE criteria) +{ + VALUE comp, box; + comp = cCvConnectedComp::new_object(); + box = cCvBox2D::new_object(); + cvCamShift(CVARR(self), VALUE_TO_CVRECT(window), VALUE_TO_CVTERMCRITERIA(criteria), CVCONNECTEDCOMP(comp), CVBOX2D(box)); + return rb_ary_new3(2, comp, box); +} + +/* + * call-seq: + * snake_image(points, alpha, beta, gamma, window, criteria[, calc_gradient = true]) -> cvseq(pointset) + * + * Updates snake in order to minimize its total energy that is a sum of internal energy + * that depends on contour shape (the smoother contour is, the smaller internal energy is) + * and external energy that depends on the energy field and reaches minimum at the local energy + * extremums that correspond to the image edges in case of image gradient. + + * The parameter criteria.epsilon is used to define the minimal number of points that must be moved + * during any iteration to keep the iteration process running. + * + * If at some iteration the number of moved points is less than criteria.epsilon or + * the function performed criteria.max_iter iterations, the function terminates. + * + * points + * Contour points (snake). + * alpha + * Weight[s] of continuity energy, single float or array of length floats, one per each contour point. + * beta + * Weight[s] of curvature energy, similar to alpha. + * gamma + * Weight[s] of image energy, similar to alpha. + * window + * Size of neighborhood of every point used to search the minimum, both win.width and win.height must be odd. + * criteria + * Termination criteria. + * calc_gradient + * Gradient flag. If not 0, the function calculates gradient magnitude for every image pixel and consideres + * it as the energy field, otherwise the input image itself is considered. + */ +VALUE +rb_snake_image(int argc, VALUE *argv, VALUE self) +{ + VALUE points, alpha, beta, gamma, window, criteria, calc_gradient, storage; + rb_scan_args(argc, argv, "43", &points, &alpha, &beta, &gamma, &window, &criteria, &calc_gradient); + CvPoint *pointset = 0; + CvSeq *seq = 0; + int length = CVPOINTS_FROM_POINT_SET(points, &pointset); + int coeff = (TYPE(alpha) == T_ARRAY || TYPE(beta) == T_ARRAY || TYPE(gamma) == T_ARRAY) ? CV_ARRAY : CV_VALUE; + float *a = 0, *b = 0, *c = 0; + IplImage stub; + if(coeff == CV_VALUE){ + a = ALLOC(float); + a[0] = (float)NUM2DBL(alpha); + b = ALLOC(float); + b[0] = (float)NUM2DBL(beta); + c = ALLOC(float); + c[0] = (float)NUM2DBL(gamma); + }else{ // CV_ARRAY + rb_raise(rb_eNotImpError, ""); + // todo + } + CvSize w = VALUE_TO_CVSIZE(window); + CvTermCriteria tc = VALUE_TO_CVTERMCRITERIA(criteria); + cvSnakeImage(cvGetImage(CVARR(self), &stub), pointset, length, + a, b, c, coeff, w, tc, IF_BOOL(calc_gradient, 1, 0, 1)); + storage = cCvMemStorage::new_object(); + seq = cvCreateSeq(CV_SEQ_POINT_SET, sizeof(CvSeq), sizeof(CvPoint), CVMEMSTORAGE(storage)); + cvSeqPushMulti(seq, pointset, length); + return cCvSeq::new_sequence(cCvSeq::rb_class(), seq, cCvPoint::rb_class(), storage); +} + +/* + * call-seq: + * optical_flow_hs(prev[,velx = nil][,vely = nil][,options]) -> [cvmat, cvmat] + * + * Calculates optical flow for two images (previous -> self) using Horn & Schunck algorithm. + * Return horizontal component of the optical flow and vertical component of the optical flow. + * prev is previous image + * velx is previous velocity field of x-axis, and vely is previous velocity field of y-axis. + * + * options + * * :lambda -> should be Float (default is 0.0005) + * Lagrangian multiplier. + * * :criteria -> should be CvTermCriteria object (default is CvTermCriteria(1, 0.001)) + * Criteria of termination of velocity computing. + * note: option's default value is CvMat::OPTICAL_FLOW_HS_OPTION. + * + * sample code + * velx, vely = nil, nil + * while true + * current = capture.query + * velx, vely = current.optical_flow_hs(prev, velx, vely) if prev + * prev = current + * emd + */ +VALUE +rb_optical_flow_hs(int argc, VALUE *argv, VALUE self) +{ + SUPPORT_8UC1_ONLY(self); + VALUE prev, velx, vely, options; + int use_previous = 0; + rb_scan_args(argc, argv, "13", &prev, &velx, &vely, &options); + options = OPTICAL_FLOW_HS_OPTION(options); + if (!rb_obj_is_kind_of(prev, cCvMat::rb_class())) + rb_raise(rb_eTypeError, "argument 1 (previous image) should be %s", rb_class2name(cCvMat::rb_class())); + if (NIL_P(velx) && NIL_P(vely)) { + velx = cCvMat::new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_32F, 1)); + vely = cCvMat::new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_32F, 1)); + } else { + if (rb_obj_is_kind_of(velx, cCvMat::rb_class()) && rb_obj_is_kind_of(vely, cCvMat::rb_class())) + use_previous = 1; + else + rb_raise(rb_eArgError, "Necessary to give both argument 2(previous velocity field x) and argument 3(previous velocity field y)"); + } + cvCalcOpticalFlowHS(CVARR(prev), CVARR(self), use_previous, CVARR(velx), CVARR(vely), HS_LAMBDA(options), HS_CRITERIA(options)); + return rb_ary_new3(2, velx, vely); +} + +/* + * call-seq: + * optical_flow_lk(prev, win_size) -> [cvmat, cvmat] + * + * Calculates optical flow for two images (previous -> self) using Lucas & Kanade algorithm + * Return horizontal component of the optical flow and vertical component of the optical flow. + * + * win_size is size of the averaging window used for grouping pixels. + */ +VALUE +rb_optical_flow_lk(int argc, VALUE *argv, VALUE self) +{ + SUPPORT_8UC1_ONLY(self); + VALUE prev, win_size, velx, vely; + rb_scan_args(argc, argv, "20", &prev, &win_size); + if (!rb_obj_is_kind_of(prev, cCvMat::rb_class())) + rb_raise(rb_eTypeError, "argument 1 (previous image) should be %s", rb_class2name(cCvMat::rb_class())); + velx = cCvMat::new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_32F, 1)); + vely = cCvMat::new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_32F, 1)); + cvCalcOpticalFlowLK(CVARR(prev), CVARR(self), VALUE_TO_CVSIZE(win_size), CVARR(velx), CVARR(vely)); + return rb_ary_new3(2, velx, vely); +} + +/* + * call-seq: + * optical_flow_bm(prev[,velx = nil][,vely = nil][,option]) -> [cvmat, cvmat] + * + * Calculates optical flow for two images (previous -> self) using block matching method. + * Return horizontal component of the optical flow and vertical component of the optical flow. + * prev is previous image. + * velx is previous velocity field of x-axis, and vely is previous velocity field of y-axis. + * + * options + * * :block_size -> should be CvSize (default is CvSize(4,4)) + * Size of basic blocks that are compared. + * * :shift_size -> should be CvSize (default is CvSize(1,1)) + * Block coordinate increments. + * * :max_range -> should be CvSize (default is CVSize(4,4)) + * Size of the scanned neighborhood in pixels around block. + * note: option's default value is CvMat::OPTICAL_FLOW_BM_OPTION. + * + * Velocity is computed for every block, but not for every pixel, + * so velocity image pixels correspond to input image blocks. + * input/output velocity field's size should be (self.width / block_size.width)x(self.height / block_size.height). + * e.g. image.size is 320x240 and block_size is 4x4, velocity field's size is 80x60. + * + */ +VALUE +rb_optical_flow_bm(int argc, VALUE *argv, VALUE self) +{ + SUPPORT_8UC1_ONLY(self); + VALUE prev, velx, vely, options; + int use_previous = 0; + rb_scan_args(argc, argv, "13", &prev, &velx, &vely, &options); + options = OPTICAL_FLOW_BM_OPTION(options); + CvSize + image_size = cvGetSize(CVARR(self)), + block_size = BM_BLOCK_SIZE(options), + shift_size = BM_SHIFT_SIZE(options), + max_range = BM_MAX_RANGE(options), + velocity_size = cvSize(image_size.width / block_size.width, image_size.height / block_size.height); + if (NIL_P(velx) && NIL_P(vely)) { + velx = cCvMat::new_object(velocity_size, CV_MAKETYPE(CV_32F, 1)); + vely = cCvMat::new_object(velocity_size, CV_MAKETYPE(CV_32F, 1)); + } else { + if (rb_obj_is_kind_of(velx, cCvMat::rb_class()) && rb_obj_is_kind_of(vely, cCvMat::rb_class())) + use_previous = 1; + else + rb_raise(rb_eArgError, "Necessary to give both argument 2(previous velocity field x) and argument 3(previous velocity field y)"); + } + cvCalcOpticalFlowBM(CVARR(prev), CVARR(self), + block_size, shift_size, max_range, use_previous, + CVARR(velx), CVARR(vely)); + return rb_ary_new3(2, velx, vely); +} + +/* + * call-seq: + * CvMat.find_fundamental_mat_7point(points1, points2[,options = {}]) -> fundamental_matrix(cvmat) or nil + * + * Calculates fundamental matrix from corresponding points, use for 7-point algorism. Return fundamental matrix(9x3). + * points1 and points2 should be 2x7 or 3x7 single-channel, or 1x7 multi-channel matrix. + * option should be Hash include these keys. + * :with_status (true or false) + * If set true, return fundamental_matrix and status. [fundamental_matrix, status] + * Otherwise return fundamental matrix only(default). + * + * note: option's default value is CvMat::FIND_FUNDAMENTAL_MAT_OPTION. + * note: 9x3 fundamental matrix means 3x3 three fundamental matrices. + */ +VALUE +rb_find_fundamental_mat_7point(int argc, VALUE *argv, VALUE klass) +{ + VALUE points1, points2, option, fundamental_matrix, status; + int num = 0; + rb_scan_args(argc, argv, "21", &points1, &points2, &option); + option = FIND_FUNDAMENTAL_MAT_OPTION(option); + fundamental_matrix = cCvMat::new_object(9, 3, CV_32FC1); + if(FFM_WITH_STATUS(option)){ + status = cCvMat::new_object(cvGetSize(CVARR(points1)), CV_8UC1); + num = cvFindFundamentalMat(CVMAT(points1), CVMAT(points2), CVMAT(fundamental_matrix), CV_FM_7POINT, 0, 0, CVMAT(status)); + return rb_ary_new3(2, fundamental_matrix, status); + }else{ + num = cvFindFundamentalMat(CVMAT(points1), CVMAT(points2), CVMAT(fundamental_matrix), CV_FM_7POINT, 0, 0, NULL); + return fundamental_matrix; + } +} + + +/* + * call-seq: + * CvMat.find_fundamental_mat_8point(points1, points2[,options = {}]) -> fundamental_matrix(cvmat) or nil + * + * Calculates fundamental matrix from corresponding points, use for 8-point algorism. + * points1 and points2 should be 2x7 or 3x7 single-channel, or 1x7 multi-channel matrix. + * option should be Hash include these keys. + * :with_status (true or false) + * If set true, return fundamental_matrix and status. [fundamental_matrix, status] + * Otherwise return fundamental matrix only(default). + * + * note: option's default value is CvMat::FIND_FUNDAMENTAL_MAT_OPTION. + */ +VALUE +rb_find_fundamental_mat_8point(int argc, VALUE *argv, VALUE klass) +{ + VALUE points1, points2, option, fundamental_matrix, status; + int num = 0; + rb_scan_args(argc, argv, "21", &points1, &points2, &option); + option = FIND_FUNDAMENTAL_MAT_OPTION(option); + fundamental_matrix = cCvMat::new_object(3, 3, CV_32FC1); + if(FFM_WITH_STATUS(option)){ + status = cCvMat::new_object(cvGetSize(CVARR(points1)), CV_8UC1); + num = cvFindFundamentalMat(CVMAT(points1), CVMAT(points2), CVMAT(fundamental_matrix), CV_FM_8POINT, 0, 0, CVMAT(status)); + return num == 0 ? Qnil : rb_ary_new3(2, fundamental_matrix, status); + }else{ + num = cvFindFundamentalMat(CVMAT(points1), CVMAT(points2), CVMAT(fundamental_matrix), CV_FM_8POINT, 0, 0, NULL); + return num == 0 ? Qnil : fundamental_matrix; + } +} + +/* + * call-seq: + * CvMat.find_fundamental_mat_ransac(points1, points2[,options = {}]) -> fundamental_matrix(cvmat) or nil + * + * Calculates fundamental matrix from corresponding points, use for RANSAC algorism. + * points1 and points2 should be 2x7 or 3x7 single-channel, or 1x7 multi-channel matrix. + * option should be Hash include these keys. + * :with_status (true or false) + * If set true, return fundamental_matrix and status. [fundamental_matrix, status] + * Otherwise return fundamental matrix only(default). + * :maximum_distance + * The maximum distance from point to epipolar line in pixels, beyond which the point is considered an outlier + * and is not used for computing the final fundamental matrix. Usually it is set to 0.5 or 1.0. + * :desirable_level + * It denotes the desirable level of confidence that the matrix is correct. + * + * note: option's default value is CvMat::FIND_FUNDAMENTAL_MAT_OPTION. + */ +VALUE +rb_find_fundamental_mat_ransac(int argc, VALUE *argv, VALUE klass) +{ + VALUE points1, points2, option, fundamental_matrix, status; + int num = 0; + rb_scan_args(argc, argv, "21", &points1, &points2, &option); + option = FIND_FUNDAMENTAL_MAT_OPTION(option); + fundamental_matrix = cCvMat::new_object(3, 3, CV_32FC1); + if(FFM_WITH_STATUS(option)){ + status = cCvMat::new_object(cvGetSize(CVARR(points1)), CV_8UC1); + num = cvFindFundamentalMat(CVMAT(points1), CVMAT(points2), CVMAT(fundamental_matrix), CV_FM_RANSAC, FFM_MAXIMUM_DISTANCE(option), FFM_DESIRABLE_LEVEL(option), CVMAT(status)); + return num == 0 ? Qnil : rb_ary_new3(2, fundamental_matrix, status); + }else{ + num = cvFindFundamentalMat(CVMAT(points1), CVMAT(points2), CVMAT(fundamental_matrix), CV_FM_RANSAC, FFM_MAXIMUM_DISTANCE(option), FFM_DESIRABLE_LEVEL(option), NULL); + return num == 0 ? Qnil : fundamental_matrix; + } +} + +/* + * call-seq: + * CvMat.find_fundamental_mat_lmeds(points1, points2[,options = {}]) -> fundamental_matrix(cvmat) or nil + * + * Calculates fundamental matrix from corresponding points, use for LMedS algorism. + * points1 and points2 should be 2x7 or 3x7 single-channel, or 1x7 multi-channel matrix. + * option should be Hash include these keys. + * :with_status (true or false) + * If set true, return fundamental_matrix and status. [fundamental_matrix, status] + * Otherwise return fundamental matrix only(default). + * :maximum_distance + * The maximum distance from point to epipolar line in pixels, beyond which the point is considered an outlier + * and is not used for computing the final fundamental matrix. Usually it is set to 0.5 or 1.0. + * :desirable_level + * It denotes the desirable level of confidence that the matrix is correct. + * + * note: option's default value is CvMat::FIND_FUNDAMENTAL_MAT_OPTION. + */ +VALUE +rb_find_fundamental_mat_lmeds(int argc, VALUE *argv, VALUE klass) +{ + VALUE points1, points2, option, fundamental_matrix, status; + int num = 0; + rb_scan_args(argc, argv, "21", &points1, &points2, &option); + option = FIND_FUNDAMENTAL_MAT_OPTION(option); + fundamental_matrix = cCvMat::new_object(3, 3, CV_32FC1); + if(FFM_WITH_STATUS(option)){ + status = cCvMat::new_object(cvGetSize(CVARR(points1)), CV_8UC1); + num = cvFindFundamentalMat(CVMAT(points1), CVMAT(points2), CVMAT(fundamental_matrix), CV_FM_LMEDS, FFM_MAXIMUM_DISTANCE(option), FFM_DESIRABLE_LEVEL(option), CVMAT(status)); + return num == 0 ? Qnil : rb_ary_new3(2, fundamental_matrix, status); + }else{ + num = cvFindFundamentalMat(CVMAT(points1), CVMAT(points2), CVMAT(fundamental_matrix), CV_FM_LMEDS, FFM_MAXIMUM_DISTANCE(option), FFM_DESIRABLE_LEVEL(option), NULL); + return num == 0 ? Qnil : fundamental_matrix; + } +} + +/* + * call-seq: + * CvMat.compute_correspond_epilines(points, which_image, fundamental_matrix) -> correspondent_lines(cvmat) + * + * For points in one image of stereo pair computes the corresponding epilines in the other image. + * Finds equation of a line that contains the corresponding point (i.e. projection of the same 3D point) + * in the other image. Each line is encoded by a vector of 3 elements l=[a,b,c]T, so that: + * lT*[x, y, 1]T=0, + * or + * a*x + b*y + c = 0 + * From the fundamental matrix definition (see cvFindFundamentalMatrix discussion), line l2 for a point p1 in the first image (which_image=1) can be computed as: + * l2=F*p1 + * and the line l1 for a point p2 in the second image (which_image=1) can be computed as: + * l1=FT*p2 + * Line coefficients are defined up to a scale. They are normalized (a2+b2=1) are stored into correspondent_lines. + */ +VALUE +rb_compute_correspond_epilines(VALUE klass, VALUE points, VALUE which_image, VALUE fundamental_matrix) +{ + VALUE correspondent_lines; + CvSize size = cvGetSize(CVARR(points)); + int n; + if(size.width <= 3 && size.height >= 7) + n = size.height; + else if(size.height <= 3 && size.width >= 7) + n = size.width; + else + rb_raise(rb_eTypeError, "input points should 2xN, Nx2 or 3xN, Nx3 matrix(N >= 7)."); + correspondent_lines = cCvMat::new_object(n, 3, CV_32F); + cvComputeCorrespondEpilines(CVMAT(points), FIX2INT(which_image), CVMAT(fundamental_matrix), CVMAT(correspondent_lines)); + return correspondent_lines; +} + +VALUE +new_object(int rows, int cols, int type) +{ + return OPENCV_OBJECT(rb_klass, cvCreateMat(rows, cols, type)); +} + +VALUE +new_object(CvSize size, int type) +{ + return OPENCV_OBJECT(rb_klass, cvCreateMat(size.height, size.width, type)); +} + +__NAMESPACE_END_OPENCV +__NAMESPACE_END_CVMAT diff --git a/ext/cvmat.h b/ext/cvmat.h new file mode 100644 index 00000000..45fa680b --- /dev/null +++ b/ext/cvmat.h @@ -0,0 +1,286 @@ +/************************************************************ + + cvmat.h - + + $Author: lsxi $ + + Copyright (C) 2005-2007 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVMAT_H +#define RUBY_OPENCV_CVMAT_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVMAT namespace cCvMat{ +#define __NAMESPACE_END_CVMAT } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVMAT + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_allocate(VALUE klass); +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); + +VALUE rb_method_missing(int argc, VALUE *argv, VALUE self); +VALUE rb_to_s(VALUE self); +VALUE rb_has_parent_q(VALUE self); +VALUE rb_parent(VALUE self); +VALUE rb_inside_q(VALUE self, VALUE object); +VALUE rb_to_IplConvKernel(VALUE self, VALUE anchor); +VALUE rb_create_mask(VALUE self); + +VALUE rb_width(VALUE self); +VALUE rb_height(VALUE self); +VALUE rb_depth(VALUE self); +VALUE rb_channel(VALUE self); +VALUE rb_data(VALUE self); + +VALUE rb_clone(VALUE self); +VALUE rb_copy(int argc, VALUE *argv, VALUE self); +VALUE copy(VALUE mat); + +VALUE rb_to_8u(VALUE self); +VALUE rb_to_8s(VALUE self); +VALUE rb_to_16u(VALUE self); +VALUE rb_to_16s(VALUE self); +VALUE rb_to_32s(VALUE self); +VALUE rb_to_32f(VALUE self); +VALUE rb_to_64f(VALUE self); +VALUE rb_vector_q(VALUE self); +VALUE rb_square_q(VALUE self); +// cxcore function +VALUE rb_to_CvMat(VALUE self); +VALUE rb_to_IplImage(VALUE self); +VALUE rb_sub_rect(VALUE self, VALUE args); +VALUE rb_slice_width(VALUE self, VALUE num); +VALUE rb_slice_height(VALUE self, VALUE num); +VALUE rb_row(VALUE self, VALUE args); +VALUE rb_col(VALUE self, VALUE args); +VALUE rb_each_row(VALUE self); +VALUE rb_each_col(VALUE self); +VALUE rb_diag(int argc, VALUE *argv, VALUE self); +VALUE rb_size(VALUE self); +VALUE rb_dims(VALUE self); +VALUE rb_dim_size(VALUE self, VALUE index); +VALUE rb_aref(VALUE self, VALUE args); +VALUE rb_aset(VALUE self, VALUE args); +VALUE rb_fill(int argc, VALUE *argv, VALUE self); +VALUE rb_fill_bang(int argc, VALUE *argv, VALUE self); +VALUE rb_clear(VALUE self); +VALUE rb_clear_bang(VALUE self); +VALUE rb_set_identity(int argc, VALUE *argv, VALUE self); +VALUE rb_set_identity_bang(int argc, VALUE *argv, VALUE self); +VALUE rb_range(int argc, VALUE *argv, VALUE self); +VALUE rb_range_bang(int argc, VALUE *argv, VALUE self); +/* Transforms and Permutations */ +VALUE rb_reshape(VALUE self, VALUE hash); +VALUE rb_repeat(VALUE self, VALUE object); +VALUE rb_flip(int argc, VALUE *argv, VALUE self); +VALUE rb_flip_bang(int argc, VALUE *argv, VALUE self); +VALUE rb_split(VALUE self); +VALUE rb_merge(VALUE klass, VALUE args); +VALUE rb_mix_channels(int argc, VALUE *argv, VALUE klass); +VALUE rb_rand_shuffle(int argc, VALUE *argv, VALUE klass); +VALUE rb_rand_shuffle_bang(int argc, VALUE *argv, VALUE klass); + +VALUE rb_lut(VALUE self, VALUE lut); +VALUE rb_convert_scale(VALUE self, VALUE hash); +VALUE rb_convert_scale_abs(VALUE self, VALUE hash); +VALUE rb_add(int argc, VALUE *argv, VALUE self); +VALUE rb_sub(int argc, VALUE *argv, VALUE self); +VALUE rb_mul(int argc, VALUE *argv, VALUE self); +VALUE rb_div(int argc, VALUE *argv, VALUE self); +VALUE rb_and(int argc, VALUE *argv, VALUE self); +VALUE rb_or(int argc, VALUE *argv, VALUE self); +VALUE rb_xor(int argc, VALUE *argv, VALUE self); +VALUE rb_not(VALUE self); +VALUE rb_not_bang(VALUE self); +VALUE rb_cmp_internal(VALUE self, VALUE val, int operand); +VALUE rb_eq(VALUE self, VALUE val); +VALUE rb_gt(VALUE self, VALUE val); +VALUE rb_ge(VALUE self, VALUE val); +VALUE rb_lt(VALUE self, VALUE val); +VALUE rb_le(VALUE self, VALUE val); +VALUE rb_ne(VALUE self, VALUE val); +VALUE rb_in_range(VALUE self, VALUE min, VALUE max); +VALUE rb_abs_diff(VALUE self, VALUE val); +/* Statistics */ +VALUE rb_count_non_zero(VALUE self); +VALUE rb_sum(VALUE self); +VALUE rb_avg(int argc, VALUE *argv, VALUE self); +VALUE rb_avg_sdv(int argc, VALUE *argv, VALUE self); +VALUE rb_sdv(int argc, VALUE *argv, VALUE self); +VALUE rb_min_max_loc(int argc, VALUE *argv, VALUE self); + +//VALUE rb_norm(); +VALUE rb_dot_product(VALUE self, VALUE mat); +VALUE rb_cross_product(VALUE self, VALUE mat); +// VALUE rb_gemm(); +VALUE rb_transform(int argc, VALUE *argv, VALUE self); +VALUE rb_perspective_transform(VALUE self, VALUE mat); +VALUE rb_mul_transposed(VALUE self, VALUE args); +VALUE rb_trace(VALUE self); +VALUE rb_transpose(VALUE self); +VALUE rb_transpose_bang(VALUE self); +VALUE rb_det(VALUE self); +VALUE rb_invert(int argc, VALUE *argv, VALUE self); +VALUE rb_solve(int argc, VALUE *argv, VALUE self); +VALUE rb_svd(int argc, VALUE *argv, VALUE self); +VALUE rb_svbksb(int argc, VALUE *argv, VALUE self); +VALUE rb_eigenvv(int argc, VALUE *argv, VALUE self); +VALUE rb_eigenvv_bang(int argc, VALUE *argv, VALUE self); +VALUE rb_calc_covar_matrix(int argc, VALUE *argv, VALUE self); +VALUE rb_mahalonobis(int argc, VALUE *argv, VALUE self); + +VALUE rb_dft(int argc, VALUE *argv, VALUE self); +//VALUE rb_optimal_dft_size(VALUE self); +//VALUE rb_mul_spectrums(int argc, VALUE *argv, VALUE self); +VALUE rb_dct(int argc, VALUE *argv, VALUE self); + +/* drawing function*/ +VALUE rb_line(int argc, VALUE *argv, VALUE self); +VALUE rb_line_bang(int argc, VALUE *argv, VALUE self); +VALUE rb_rectangle(int argc, VALUE *argv, VALUE self); +VALUE rb_rectangle_bang(int argc, VALUE *argv, VALUE self); +VALUE rb_circle(int argc, VALUE *argv, VALUE self); +VALUE rb_circle_bang(int argc, VALUE *argv, VALUE self); +VALUE rb_ellipse(int argc, VALUE *argv, VALUE self); +VALUE rb_ellipse_bang(int argc, VALUE *argv, VALUE self); +VALUE rb_ellipse_box(int argc, VALUE *argv, VALUE self); +VALUE rb_ellipse_box_bang(int argc, VALUE *argv, VALUE self); +VALUE rb_fill_poly(int argc, VALUE *argv, VALUE self); +VALUE rb_fill_poly_bang(int argc, VALUE *argv, VALUE self); +VALUE rb_fill_convex_poly(int argc, VALUE *argv, VALUE self); +VALUE rb_fill_convex_poly_bang(int argc, VALUE *argv, VALUE self); +VALUE rb_poly_line(int argc, VALUE *argv, VALUE self); +VALUE rb_poly_line_bang(int argc, VALUE *argv, VALUE self); + +VALUE rb_put_text(int argc, VALUE *argv, VALUE self); +VALUE rb_put_text_bang(int argc, VALUE *argv, VALUE self); +/* cv function */ +VALUE rb_sobel(int argc, VALUE *argv, VALUE self); +VALUE rb_laplace(int argc, VALUE *argv, VALUE self); +VALUE rb_canny(int argc, VALUE *argv, VALUE self); +VALUE rb_pre_corner_detect(int argc, VALUE *argv, VALUE self); +VALUE rb_corner_eigenvv(int argc, VALUE *argv, VALUE self); +VALUE rb_corner_min_eigen_val(int argc, VALUE *argv, VALUE self); +VALUE rb_corner_harris(int argc, VALUE *argv, VALUE self); +VALUE rbi_find_corner_sub_pix(int argc, VALUE *argv, VALUE self); +VALUE rb_good_features_to_track(int argc, VALUE *argv, VALUE self); + +VALUE rb_sample_line(int argc, VALUE *argv, VALUE self); +VALUE rb_rect_sub_pix(VALUE self, VALUE center, VALUE size); +VALUE rb_quadrangle_sub_pix(VALUE self, VALUE map_matrix, VALUE size); +VALUE rb_resize(int argc, VALUE *argv, VALUE self); +VALUE rb_warp_affine(int argc, VALUE *argv, VALUE self); +VALUE rb_rotation(VALUE self, VALUE center, VALUE angle, VALUE scale); +VALUE rb_warp_perspective(int argc, VALUE *argv, VALUE self); +//VALUE rb_perspective_transform(); +VALUE rb_remap(int argc, VALUE *argv, VALUE self); +VALUE rb_log_polar(int argc, VALUE *argv); + +VALUE rb_erode(int argc, VALUE *argv, VALUE self); +VALUE rb_erode_bang(int argc, VALUE *argv, VALUE self); +VALUE rb_dilate(int argc, VALUE *argv, VALUE self); +VALUE rb_dilate_bang(int argc, VALUE *argv, VALUE self); +VALUE rb_morphology_open(int argc, VALUE *argv, VALUE self); +VALUE rb_morphology_close(int argc, VALUE *argv, VALUE self); +VALUE rb_morphology_gradient(int argc, VALUE *argv, VALUE self); +VALUE rb_morphology_tophat(int argc, VALUE *argv, VALUE self); +VALUE rb_morphology_blackhat(int argc, VALUE *argv, VALUE self); + +VALUE rb_smooth_blur_no_scale(int argc, VALUE *argv, VALUE self); +VALUE rb_smooth_blur(int argc, VALUE *argv, VALUE self); +VALUE rb_smooth_gaussian(int argc, VALUE *argv, VALUE self); +VALUE rb_smooth_median(int argc, VALUE *argv, VALUE self); +VALUE rb_smooth_bilateral(int argc, VALUE *argv, VALUE self); +VALUE rb_filter2d(int argc, VALUE *argv, VALUE self); +VALUE rb_copy_make_border_constant(int argc, VALUE *argv, VALUE self); +VALUE rb_copy_make_border_replicate(int argc, VALUE *argv, VALUE self); +VALUE rb_integral(int argc, VALUE *argv, VALUE self); +VALUE rb_threshold_binary(int argc, VALUE *argv, VALUE self); +VALUE rb_threshold_binary_inverse(int argc, VALUE *argv, VALUE self); +VALUE rb_threshold_trunc(int argc, VALUE *argv, VALUE self); +VALUE rb_threshold_to_zero(int argc, VALUE *argv, VALUE self); +VALUE rb_threshold_to_zero_inverse(int argc, VALUE *argv, VALUE self); +VALUE rb_adaptive_threshold(int argc, VALUE *argv, VALUE self); + +VALUE rb_pyr_down(int argc, VALUE *argv, VALUE self); +VALUE rb_pyr_up(int argc, VALUE *argv, VALUE self); + +VALUE rb_flood_fill(int argc, VALUE *argv, VALUE self); +VALUE rb_flood_fill_bang(int argc, VALUE *argv, VALUE self); +VALUE rb_find_contours(int argc, VALUE *argv, VALUE self); +VALUE rb_find_contours_bang(int argc, VALUE *argv, VALUE self); +VALUE rb_pyr_segmentation(int argc, VALUE *argv, VALUE self); +VALUE rb_pyr_mean_shift_filtering(int argc, VALUE *argv, VALUE self); +VALUE rb_watershed(VALUE self); + +VALUE rb_moments(int argc, VALUE *argv, VALUE self); + +VALUE rb_hough_lines_standard(int argc, VALUE *argv, VALUE self); +VALUE rb_hough_lines_probabilistic(int argc, VALUE *argv, VALUE self); +VALUE rb_hough_lines_multi_scale(int argc, VALUE *argv, VALUE self); +VALUE rb_hough_circles_gradient(int argc, VALUE *argv, VALUE self); +VALUE rb_dist_transform(int argc, VALUE *argv, VALUE self); +VALUE rb_inpaint_ns(VALUE self, VALUE mask, VALUE radius); +VALUE rb_inpaint_telea(VALUE self, VALUE mask, VALUE radius); + +VALUE rb_equalize_hist(VALUE self); +/* Matching*/ +VALUE rb_match_template(int argc, VALUE *argv, VALUE self); +VALUE rb_match_shapes_i1(int argc, VALUE *argv, VALUE self); +VALUE rb_match_shapes_i2(int argc, VALUE *argv, VALUE self); +VALUE rb_match_shapes_i3(int argc, VALUE *argv, VALUE self); +// VALUE rb_calc_emd(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); +VALUE rb_snake_image(int argc, VALUE *argv, VALUE self); +/* Optical Flow */ +VALUE rb_optical_flow_hs(int argc, VALUE *argv, VALUE self); +VALUE rb_optical_flow_lk(int argc, VALUE *argv, VALUE self); +VALUE rb_optical_flow_bm(int argc, VALUE *argv, VALUE self); +VALUE rb_optical_flow_pyr_lk(int argc, VALUE *argv, VALUE self); + +/* Epipolar Geometory */ +VALUE rb_find_fundamental_mat_7point(int argc, VALUE *argv, VALUE klass); +VALUE rb_find_fundamental_mat_8point(int argc, VALUE *argv, VALUE klass); +VALUE rb_find_fundamental_mat_ransac(int argc, VALUE *argv, VALUE klass); +VALUE rb_find_fundamental_mat_lmeds(int argc, VALUE *argv, VALUE klass); +VALUE rb_compute_correspond_epilines(VALUE klass, VALUE points, VALUE which_image, VALUE fundamental_matrix); + +// HighGUI function +VALUE rb_save_image(VALUE self, VALUE filename); + +VALUE new_object(int rows, int cols, int type); +VALUE new_object(CvSize size, int type); + +__NAMESPACE_END_CVMAT + +inline CvMat* +CVMAT(VALUE object) +{ + CvMat *ptr, stub; + Data_Get_Struct(object, CvMat, ptr); + return cvGetMat(ptr, &stub); +} + +inline CvMat* +MASK(VALUE object) +{ + if(NIL_P(object)) + return NULL; + else if(rb_obj_is_kind_of(object, cCvMat::rb_class()) && CV_MAT_CN(CVMAT(object)->type) == CV_8UC1) + return CVMAT(object); + else + rb_raise(rb_eTypeError, "object is not mask."); +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVMAT_H diff --git a/ext/cvmatnd.cpp b/ext/cvmatnd.cpp new file mode 100644 index 00000000..6a2d3102 --- /dev/null +++ b/ext/cvmatnd.cpp @@ -0,0 +1,44 @@ +/*********************************************************** + + cvmatnd.cpp - + + $Author: lsxi $ + + Copyright (C) 2007 Masakazu Yonekura + +************************************************************/ +#include "cvmatnd.h" +/* + * Document-class: OpenCV::CvMatND + * + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVMATND + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * cvmat = rb_define_class_under(opencv, "CvMat", rb_cObject); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(), cvmat = cCvMat::rb_class(); + + rb_klass = rb_define_class_under(opencv, "CvMatND", cvmat); +} + +__NAMESPACE_END_CVMATND +__NAMESPACE_END_OPENCV + diff --git a/ext/cvmatnd.h b/ext/cvmatnd.h new file mode 100644 index 00000000..75165c76 --- /dev/null +++ b/ext/cvmatnd.h @@ -0,0 +1,28 @@ +/************************************************************ + + cvmatnd.h - + + $Author: lsxi $ + + Copyright (C) 2007 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVMATND_H +#define RUBY_OPENCV_CVMATND_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVMATND namespace cCvMatND{ +#define __NAMESPACE_END_CVMATND } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVMATND + +VALUE rb_class(); + +void define_ruby_class(); + +__NAMESPACE_END_CVMATND +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVMATND_H diff --git a/ext/cvmemstorage.cpp b/ext/cvmemstorage.cpp new file mode 100644 index 00000000..bc082912 --- /dev/null +++ b/ext/cvmemstorage.cpp @@ -0,0 +1,64 @@ +/************************************************************ + + cvmemstorage.cpp - + + $Author: lsxi $ + + Copyright (C) 2005 Masakazu Yonekura + +************************************************************/ +#include "cvmemstorage.h" +/* + * Document-class: OpenCV::CvMemStorage + * + * Internal memory management class used by CvSeq. + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVMEMSTORAGE + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if(rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + rb_klass = rb_define_class_under(opencv, "CvMemStorage", rb_cObject); + //rb_define_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); +} + +VALUE +rb_allocate(VALUE klass) +{ + CvMemStorage *storage = cvCreateMemStorage(); + return Data_Wrap_Struct(klass, 0, free, storage); +} + +void +free(void *ptr) +{ + cvReleaseMemStorage((CvMemStorage**)&ptr); +} + +VALUE +new_object(int blocksize) +{ + CvMemStorage *storage = cvCreateMemStorage(blocksize); + return Data_Wrap_Struct(rb_klass, 0, free, storage); +} + + +__NAMESPACE_END_CVMEMSTORAGE +__NAMESPACE_END_OPENCV diff --git a/ext/cvmemstorage.h b/ext/cvmemstorage.h new file mode 100644 index 00000000..1f800dac --- /dev/null +++ b/ext/cvmemstorage.h @@ -0,0 +1,53 @@ +/************************************************************ + + cvmemstorage.h - + + $Author: lsxi $ + + Copyright (C) 2005 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVMEMSTORAGE_H +#define RUBY_OPENCV_CVMEMSTORAGE_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVMEMSTORAGE namespace cCvMemStorage{ +#define __NAMESPACE_END_CVMEMSTORAGE } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVMEMSTORAGE + +void define_ruby_class(); + +VALUE rb_class(); +VALUE rb_allocate(VALUE klass); +void free(void *ptr); + +VALUE new_object(int blocksize = 0); + +__NAMESPACE_END_CVMEMSTORAGE + +inline CvMemStorage* +CVMEMSTORAGE(VALUE object) +{ + CvMemStorage *ptr; + Data_Get_Struct(object, CvMemStorage, ptr); + return ptr; +} + +inline VALUE +CHECK_CVMEMSTORAGE(VALUE object) +{ + if(rb_obj_is_kind_of(object, cCvMemStorage::rb_class())) + return object; + else{ + if(!NIL_P(object)) + rb_warn("invalid CvMemStorage object given. allocate new memory storage automatically."); + return cCvMemStorage::new_object(); + } +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVMEMSTORAGE_H diff --git a/ext/cvmoments.cpp b/ext/cvmoments.cpp new file mode 100644 index 00000000..ae47dcf3 --- /dev/null +++ b/ext/cvmoments.cpp @@ -0,0 +1,204 @@ +/************************************************************ + + cvmoments.cpp - + + $Author: lsxi $ + + Copyright (C) 2007 Masakazu Yonekura + +************************************************************/ +#include "cvmoments.h" +/* + * Document-class: OpenCV::CvMoments + * + * moments + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVMOMENTS + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + + rb_klass = rb_define_class_under(opencv, "CvMoments", rb_cObject); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_private_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); + rb_define_method(rb_klass, "spatial", RUBY_METHOD_FUNC(rb_spatial), 2); + rb_define_method(rb_klass, "central", RUBY_METHOD_FUNC(rb_central), 2); + rb_define_method(rb_klass, "normalized_central", RUBY_METHOD_FUNC(rb_normalized_central), 2); + rb_define_method(rb_klass, "hu", RUBY_METHOD_FUNC(rb_hu), 0); + rb_define_method(rb_klass, "gravity_center", RUBY_METHOD_FUNC(rb_gravity_center), 0); + rb_define_alias(rb_klass, "center", "gravity_center"); + rb_define_method(rb_klass, "angle", RUBY_METHOD_FUNC(rb_angle), 0); +} + +VALUE +rb_allocate(VALUE klass) +{ + CvMoments *ptr; + return Data_Make_Struct(klass, CvMoments, 0, -1, ptr); +} +/* + * call-seq: + * CvMoments.new(src[,is_binary = nil]) + * + * Calculates all moments up to third order of a polygon or rasterized shape. + * src should be CvMat or CvPolygon. + * + * If is_binary = true, all the zero pixel values are treated as zeroes, all the others are treated as 1's. + */ +VALUE +rb_initialize(int argc, VALUE *argv, VALUE self) +{ + VALUE src, is_binary; + rb_scan_args(argc, argv, "02", &src, &is_binary); + if (NIL_P(src)) + ; + else if (rb_obj_is_kind_of(src, cCvMat::rb_class()) || rb_obj_is_kind_of(src, cCvSeq::rb_class())) + cvMoments(CVARR(src), CVMOMENTS(self), TRUE_OR_FALSE(is_binary, 0)); + else + rb_raise(rb_eTypeError, "argument 1 (src) should be %s or %s.", rb_class2name(cCvMat::rb_class()), rb_class2name(cCvSeq::rb_class())); + return self; +} + +/* + * call-seq: + * spatial -> float + * + * Retrieves spatial moment. + * + * which in case of image moments is defined as: + * Mx_order,y_order=sumx,y(I(x,y)*xx_order*yy_order) + * where I(x,y) is the intensity of the pixel (x, y). + */ +VALUE +rb_spatial(VALUE self, VALUE x_order, VALUE y_order) +{ + return rb_float_new(cvGetSpatialMoment(CVMOMENTS(self), NUM2INT(x_order), NUM2INT(y_order))); +} + +/* + * call-seq: + * central -> float + * + * Retrieves central moment. + * + * which in case of image moments is defined as: + * μx_order,y_order=sumx,y(I(x,y)*(x-xc)x_order*(y-yc)y_order), + * where xc=M10/M00, yc=M01/M00 - coordinates of the gravity center + */ +VALUE +rb_central(VALUE self, VALUE x_order, VALUE y_order) +{ + return rb_float_new(cvGetCentralMoment(CVMOMENTS(self), NUM2INT(x_order), NUM2INT(y_order))); +} + +/* + * call-seq: + * normalized_central -> float + * + * Retrieves normalized central moment. + * + * ηx_order,y_order= μx_order,y_order/M00((y_order+x_order)/2+1) + */ +VALUE +rb_normalized_central(VALUE self, VALUE x_order, VALUE y_order) +{ + return rb_float_new(cvGetNormalizedCentralMoment(CVMOMENTS(self), NUM2INT(x_order), NUM2INT(y_order))); +} + +/* + * call-seq: + * hu -> [hu1, hu2, ... ,hu7] + * + * Calculates seven Hu invariants. + * + * seven Hu invariants that are defined as: + * h1=η20+η02 + * h2=(η20-η02)²+4η11² + * h3=(η30-3η12)²+ (3η21-η03)² + * h4=(η30+η12)²+ (η21+η03)² + * h5=(η30-3η12)(η30+η12)[(η30+η12)²-3(η21+η03)²]+(3η21-η03)(η21+η03)[3(η30+η12)²-(η21+η03)²] + * h6=(η20-η02)[(η30+η12)²- (η21+η03)²]+4η11(η30+η12)(η21+η03) + * h7=(3η21-η03)(η21+η03)[3(η30+η12)²-(η21+η03)²]-(η30-3η12)(η21+η03)[3(η30+η12)²-(η21+η03)²] + * where ηi,j are normalized central moments of 2-nd and 3-rd orders. The computed values are proved to be invariant to the image scaling, rotation, and reflection except the seventh one, whose sign is changed by reflection. + */ +VALUE +rb_hu(VALUE self) +{ + CvHuMoments hu_moments; + cvGetHuMoments(CVMOMENTS(self), &hu_moments); + return rb_ary_new3(7, + rb_float_new(hu_moments.hu1), + rb_float_new(hu_moments.hu2), + rb_float_new(hu_moments.hu3), + rb_float_new(hu_moments.hu4), + rb_float_new(hu_moments.hu5), + rb_float_new(hu_moments.hu6), + rb_float_new(hu_moments.hu7)); +} + +/* + * call-seq: + * gravity_center -> cvpoint2d32f + * + * Return gravity center. + */ +VALUE +rb_gravity_center(VALUE self) +{ + CvMoments *moments = CVMOMENTS(self); + double + m00 = cvGetSpatialMoment(moments, 0, 0), + m10 = cvGetSpatialMoment(moments, 1, 0), + m01 = cvGetSpatialMoment(moments, 0, 1); + return cCvPoint2D32f::new_object(cvPoint2D32f(m10 / m00, m01 / m00)); +} + +/* + * call-seq: + * angle -> float + * + * Return angle. + */ +VALUE +rb_angle(VALUE self) +{ + CvMoments *moments = CVMOMENTS(self); + double + m11 = cvGetCentralMoment(moments, 1, 1), + m20 = cvGetCentralMoment(moments, 2, 0), + m02 = cvGetCentralMoment(moments, 0, 2), + mangle = 0.5 * atan(2 * m11 / (m20 - m02)); + if(!cvIsNaN(mangle) && !cvIsInf(mangle)) + return rb_float_new(mangle); + else + return Qnil; +} + +VALUE +new_object(CvArr *arr, int is_binary = 0) +{ + VALUE object = rb_allocate(rb_class()); + cvMoments(arr, CVMOMENTS(object), TRUE_OR_FALSE(is_binary, 0)); + return object; +} + +__NAMESPACE_END_CVMOMENTS +__NAMESPACE_END_OPENCV diff --git a/ext/cvmoments.h b/ext/cvmoments.h new file mode 100644 index 00000000..9eda0025 --- /dev/null +++ b/ext/cvmoments.h @@ -0,0 +1,48 @@ +/************************************************************ + + cvmoments.h - + + $Author: lsxi $ + + Copyright (C) 2007 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVMOMENTS_H +#define RUBY_OPENCV_CVMOMENTS_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVMOMENTS namespace cCvMoments{ +#define __NAMESPACE_END_CVMOMENTS } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVMOMENTS + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_allocate(VALUE klass); +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); +VALUE rb_spatial(VALUE self, VALUE x_order, VALUE y_order); +VALUE rb_central(VALUE self, VALUE x_order, VALUE y_order); +VALUE rb_normalized_central(VALUE self, VALUE x_order, VALUE y_order); +VALUE rb_hu(VALUE self); +VALUE rb_gravity_center(VALUE self); +VALUE rb_angle(VALUE self); + +VALUE new_object(CvArr *arr, int is_binary); + +__NAMESPACE_END_CVMOMENTS + +inline CvMoments* +CVMOMENTS(VALUE object) +{ + CvMoments *ptr; + Data_Get_Struct(object, CvMoments, ptr); + return ptr; +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVMOMENTS_H diff --git a/ext/cvpoint.cpp b/ext/cvpoint.cpp new file mode 100644 index 00000000..52bf680b --- /dev/null +++ b/ext/cvpoint.cpp @@ -0,0 +1,229 @@ +/************************************************************ + + cvpoint.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include "cvpoint.h" +/* + * Document-class: OpenCV::CvPoint + * + * This class means one point on X axis Y axis. + * X and Y takes the value of the Fixnum. see also CvPoint2D32F + * + * C structure is here, very simple. + * typdef struct CvPoint{ + * int x; + * int y; + * } + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVPOINT + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + + rb_klass = rb_define_class_under(opencv, "CvPoint", rb_cObject); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_singleton_method(rb_klass, "compatible?", RUBY_METHOD_FUNC(rb_compatible_q), 1); + rb_define_private_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); + rb_define_method(rb_klass, "x", RUBY_METHOD_FUNC(rb_x), 0); + rb_define_method(rb_klass, "x=", RUBY_METHOD_FUNC(rb_set_x), 1); + rb_define_method(rb_klass, "y", RUBY_METHOD_FUNC(rb_y), 0); + rb_define_method(rb_klass, "y=", RUBY_METHOD_FUNC(rb_set_y), 1); + + rb_define_method(rb_klass, "to_s", RUBY_METHOD_FUNC(rb_to_s), 0); + rb_define_method(rb_klass, "to_ary", RUBY_METHOD_FUNC(rb_to_ary), 0); +} + +/* + * call-seq: + * combatible?(obj) + * + * Return compatibility to CvPoint. Return true if object have method #x and #y. + * + * For example. + * class MyPoint + * def x + * 1 + * end + * def y + * 2 + * end + * end + * mp = MyPoint.new + * CvPoint.compatible?(mp) #=> true + * CvPoint.new(mp) #=> same as CvPoint(1, 2) + */ +VALUE +rb_compatible_q(VALUE klass, VALUE object) +{ + return (rb_respond_to(object, rb_intern("x")) && rb_respond_to(object, rb_intern("y"))) ? Qtrue : Qfalse; +} + +VALUE +rb_allocate(VALUE klass) +{ + CvPoint *ptr; + return Data_Make_Struct(klass, CvPoint, 0, -1, ptr); +} + +/* + * call-seq: + * new -> CvPoint.new(0, 0) + * new(obj) -> CvPoint.new(obj.x.to_i, obj.y.to_i) + * new(x, y) + * + * Create new 2D-coordinate, (x, y). It is dropped below the decimal point. + * + * new() is same as new(0, 0) + * + * new(obj) is same as new(obj.x.to_i, obj.y.to_i) + */ +VALUE +rb_initialize(int argc, VALUE *argv, VALUE self) +{ + VALUE obj, x, y; + switch (argc) { + case 0: + break; + case 1: + obj = argv[0]; + if (rb_compatible_q(rb_klass, obj)) { + CVPOINT(self)->x = NUM2INT(rb_funcall(rb_funcall(obj, rb_intern("x"), 0), rb_intern("to_i"), 0)); + CVPOINT(self)->y = NUM2INT(rb_funcall(rb_funcall(obj, rb_intern("y"), 0), rb_intern("to_i"), 0)); + }else{ + rb_raise(rb_eArgError, "object is not compatible %s.", rb_class2name(rb_klass)); + } + break; + case 2: + x = argv[0], y = argv[1]; + CVPOINT(self)->x = NUM2INT(x); + CVPOINT(self)->y = NUM2INT(y); + break; + default: + rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..2)", argc); + } + return Qnil; +} + +/* + * Return parameter on x-axis. + */ +VALUE +rb_x(VALUE self) +{ + return INT2FIX(CVPOINT(self)->x); +} + +/* + * call-seq: + * x = val + * + * Set x-axis parameter, return self. + * It is dropped below the decimal point. + * pt = CvPoint.new + * pt.x = 1.1 + * pt.x #=> 1 + * pt.x = 100.9 + * pt.x #=> 100 + */ +VALUE +rb_set_x(VALUE self, VALUE x) +{ + CVPOINT(self)->x = NUM2INT(x); + return self; +} + +/* + * Return parameter on y-axis. + */ +VALUE +rb_y(VALUE self) +{ + return INT2FIX(CVPOINT(self)->y); +} + +/* + * call-seq: + * y = val + * + * Set y-axis parameter, return self. + * It is dropped below the decimal point. + */ +VALUE +rb_set_y(VALUE self, VALUE y) +{ + CVPOINT(self)->y = NUM2INT(y); + return self; +} + +/* + * call-seq: + * to_s -> "" + * + * Return x and y by String. + */ +VALUE +rb_to_s(VALUE self) +{ + const int i = 4; + VALUE str[i]; + str[0] = rb_str_new2("<%s:(%d,%d)>"); + str[1] = rb_str_new2(rb_class2name(CLASS_OF(self))); + str[2] = rb_x(self); + str[3] = rb_y(self); + return rb_f_sprintf(i, str); +} + +/* + * call-seq: + * to_ary -> [x, y] + * + * Return x and y by Array. + */ +VALUE +rb_to_ary(VALUE self) +{ + return rb_ary_new3(2, rb_x(self), rb_y(self)); +} + +VALUE +new_object() +{ + VALUE object = rb_allocate(rb_klass); + *CVPOINT(object) = cvPoint(0, 0); + return object; +} + + +VALUE +new_object(CvPoint point) +{ + VALUE object = rb_allocate(rb_klass); + *CVPOINT(object) = point; + return object; +} + +__NAMESPACE_END_CVPOINT +__NAMESPACE_END_OPENCV diff --git a/ext/cvpoint.h b/ext/cvpoint.h new file mode 100644 index 00000000..488c6e4b --- /dev/null +++ b/ext/cvpoint.h @@ -0,0 +1,59 @@ +/************************************************************ + + cvpoint.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVPOINT_H +#define RUBY_OPENCV_CVPOINT_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVPOINT namespace cCvPoint{ +#define __NAMESPACE_END_CVPOINT } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVPOINT + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_compatible_q(VALUE klass, VALUE object); + +VALUE rb_allocate(VALUE klass); +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); +VALUE rb_x(VALUE self); +VALUE rb_set_x(VALUE self, VALUE x); +VALUE rb_y(VALUE self); +VALUE rb_set_y(VALUE self, VALUE y); + +VALUE rb_to_s(VALUE self); +VALUE rb_to_ary(VALUE self); + +VALUE new_object(); +VALUE new_object(CvPoint point); + +__NAMESPACE_END_CVPOINT + +inline CvPoint *CVPOINT(VALUE object){ + CvPoint *ptr; + Data_Get_Struct(object, CvPoint, ptr); + return ptr; +} + +inline CvPoint VALUE_TO_CVPOINT(VALUE object){ + if(cCvPoint::rb_compatible_q(cCvPoint::rb_class(), object)){ + return cvPoint(NUM2INT(rb_funcall(object, rb_intern("x"), 0)), + NUM2INT(rb_funcall(object, rb_intern("y"), 0))); + }else{ + rb_raise(rb_eTypeError, "require %s or compatible object.", rb_class2name(cCvPoint::rb_class())); + } +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVPOINT_H diff --git a/ext/cvpoint2d32f.cpp b/ext/cvpoint2d32f.cpp new file mode 100644 index 00000000..05b5b0e8 --- /dev/null +++ b/ext/cvpoint2d32f.cpp @@ -0,0 +1,213 @@ +/************************************************************ + + cvpoint2d32f.cpp - + + $Author: lsxi $ + + Copyright (C) 2005 Masakazu Yonekura + +************************************************************/ +#include"cvpoint2d32f.h" +/* + * Document-class: OpenCV::CvPoint2D32f + * + * This class means one point on X axis Y axis. + * X and Y takes the value of the Float. see also CvPoint + * + * C structure is here, very simple. + * typdef struct CvPoint2D32f{ + * float x; + * float y; + * } + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVPOINT2D32F + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if(rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + + rb_klass = rb_define_class_under(opencv, "CvPoint2D32f", rb_cObject); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_singleton_method(rb_klass, "compatible?", RUBY_METHOD_FUNC(rb_compatible_q), 1); + rb_define_private_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); + rb_define_method(rb_klass, "x", RUBY_METHOD_FUNC(rb_x), 0); + rb_define_method(rb_klass, "x=", RUBY_METHOD_FUNC(rb_set_x), 1); + rb_define_method(rb_klass, "y", RUBY_METHOD_FUNC(rb_y), 0); + rb_define_method(rb_klass, "y=", RUBY_METHOD_FUNC(rb_set_y), 1); + + rb_define_method(rb_klass, "to_s", RUBY_METHOD_FUNC(rb_to_s), 0); + rb_define_method(rb_klass, "to_ary", RUBY_METHOD_FUNC(rb_to_ary), 0); +} + +/* + * call-seq: + * combatible?(obj) + * + * Return compatibility to CvPoint2D32f. Return true if object have method #x and #y. + * + * For example. + * class MyPoint2D32f + * def x + * 95.7 + * end + * def y + * 70.2 + * end + * end + * mp = MyPoint2D32f.new + * CvPoint2D32f.compatible?(mp) #=> true + * CvPoint2D32f.new(mp) #=> same as CvPoint2D32f(95.7, 70.2) + */ +VALUE +rb_compatible_q(VALUE klass, VALUE object) +{ + return (rb_respond_to(object, rb_intern("x")) && rb_respond_to(object, rb_intern("y"))) ? Qtrue : Qfalse; +} + +VALUE +rb_allocate(VALUE klass) +{ + CvPoint2D32f *ptr; + return Data_Make_Struct(klass, CvPoint2D32f, 0, -1, ptr); +} + +/* + * call-seq: + * new + * new(obj) + * new(x, y) + * + * Create new 2D-coordinate, (x, y). + * + * new() is same as new(0.0, 0.0) + * + * new(obj) is same as new(obj.x.to_f, obj.y.to_f) + */ +VALUE +rb_initialize(int argc, VALUE *argv, VALUE self) +{ + VALUE obj, x, y; + switch (argc) { + case 0: + break; + case 1: + obj = argv[0]; + if(rb_compatible_q(rb_klass, obj)) { + CVPOINT2D32F(self)->x = NUM2DBL(rb_funcall(rb_funcall(obj, rb_intern("x"), 0), rb_intern("to_f"), 0)); + CVPOINT2D32F(self)->y = NUM2DBL(rb_funcall(rb_funcall(obj, rb_intern("y"), 0), rb_intern("to_f"), 0)); + }else{ + rb_raise(rb_eArgError, "object is not compatible %s.", rb_class2name(rb_klass)); + } + break; + case 2: + x = argv[0], y = argv[1]; + CVPOINT2D32F(self)->x = NUM2DBL(x); + CVPOINT2D32F(self)->y = NUM2DBL(y); + break; + default: + rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..2)", argc); + } + return Qnil; +} + +/* + * Return parameter on x-axis. + */ +VALUE +rb_x(VALUE self) +{ + return rb_float_new(CVPOINT2D32F(self)->x); +} + +/* + * call-seq: + * x = val + * + * Set x-axis parameter, return self. + */ +VALUE +rb_set_x(VALUE self, VALUE x) +{ + CVPOINT2D32F(self)->x = NUM2DBL(x); + return self; +} + +/* + * Return parameter on y-axis. + */ +VALUE +rb_y(VALUE self) +{ + return rb_float_new(CVPOINT2D32F(self)->y); +} + +/* + * call-seq: + * y = val + * + * Set y-axis parameter, return self. + */ +VALUE +rb_set_y(VALUE self, VALUE y) +{ + CVPOINT2D32F(self)->y = NUM2DBL(y); + return self; +} + +/* + * call-seq: + * to_s -> "" + * + * Return x and y by String. + */ +VALUE +rb_to_s(VALUE self) +{ + const int i = 4; + VALUE str[i]; + str[0] = rb_str_new2("<%s:(%f,%f)>"); + str[1] = rb_str_new2(rb_class2name(CLASS_OF(self))); + str[2] = rb_x(self); + str[3] = rb_y(self); + return rb_f_sprintf(i, str); +} + +/* + * call-seq: + * to_ary -> [x, y] + * + * Return x and y by Array. + */ +VALUE +rb_to_ary(VALUE self) +{ + return rb_ary_new3(2, rb_x(self), rb_y(self)); +} + +VALUE +new_object(CvPoint2D32f point) +{ + VALUE object = rb_allocate(rb_klass); + *CVPOINT2D32F(object) = point; + return object; +} + +__NAMESPACE_END_CVPOINT2D32F +__NAMESPACE_END_OPENCV diff --git a/ext/cvpoint2d32f.h b/ext/cvpoint2d32f.h new file mode 100644 index 00000000..2e7c60c1 --- /dev/null +++ b/ext/cvpoint2d32f.h @@ -0,0 +1,61 @@ +/************************************************************ + + cvpoint2d32f.h - + + $Author: lsxi $ + + Copyright (C) 2005 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVPOINT2D32F_H +#define RUBY_OPENCV_CVPOINT2D32F_H + +#define __NAMESPACE_BEGIN_CVPOINT2D32F namespace cCvPoint2D32f{ +#define __NAMESPACE_END_CVPOINT2D32F } + +#include"opencv.h" + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVPOINT2D32F + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_compatible_q(VALUE klass, VALUE object); + +VALUE rb_allocate(VALUE klass); +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); +VALUE rb_x(VALUE self); +VALUE rb_set_x(VALUE self, VALUE x); +VALUE rb_y(VALUE self); +VALUE rb_set_y(VALUE self, VALUE y); + +VALUE rb_to_s(VALUE self); +VALUE rb_to_ary(VALUE self); + +VALUE new_object(CvPoint2D32f point); + +__NAMESPACE_END_CVPOINT2D32F + +inline CvPoint2D32f* +CVPOINT2D32F(VALUE object) +{ + CvPoint2D32f *ptr; + Data_Get_Struct(object, CvPoint2D32f, ptr); + return ptr; +} + +inline CvPoint2D32f +VALUE_TO_CVPOINT2D32F(VALUE object) +{ + if(cCvPoint2D32f::rb_compatible_q(cCvPoint2D32f::rb_class(), object)){ + return cvPoint2D32f(NUM2DBL(rb_funcall(object, rb_intern("x"), 0)), + NUM2DBL(rb_funcall(object, rb_intern("y"), 0))); + }else{ + rb_raise(rb_eTypeError, "require %s or compatible object.", rb_class2name(cCvPoint2D32f::rb_class())); + } +} + +__NAMESPACE_END_OPENCV +#endif // RUBY_OPENCV_CVPOINT2D32F_H diff --git a/ext/cvpoint3d32f.cpp b/ext/cvpoint3d32f.cpp new file mode 100644 index 00000000..dd2eacc8 --- /dev/null +++ b/ext/cvpoint3d32f.cpp @@ -0,0 +1,245 @@ +/************************************************************ + + cvpoint3d32f.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2008 Masakazu Yonekura + +************************************************************/ +#include"cvpoint3d32f.h" +/* + * Document-class: OpenCV::CvPoint3D32f + * + * This class means one point on X axis Y axis. + * X and Y takes the value of the Float. see also CvPoint + * + * C structure is here, very simple. + * typdef struct CvPoint3D32f{ + * float x; + * float y; + * float z; + * } + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVPOINT3D32F + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if(rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * cvpoint2d32f = rb_define_class_under(opencv, "CvPoint2D32f", rb_cObject); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + VALUE cvpoint2d32f = cCvPoint2D32f::rb_class(); + rb_klass = rb_define_class_under(opencv, "CvPoint3D32f", cvpoint2d32f); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_singleton_method(rb_klass, "compatible?", RUBY_METHOD_FUNC(rb_compatible_q), 1); + rb_define_private_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); + rb_define_method(rb_klass, "x", RUBY_METHOD_FUNC(rb_x), 0); + rb_define_method(rb_klass, "x=", RUBY_METHOD_FUNC(rb_set_x), 1); + rb_define_method(rb_klass, "y", RUBY_METHOD_FUNC(rb_y), 0); + rb_define_method(rb_klass, "y=", RUBY_METHOD_FUNC(rb_set_y), 1); + rb_define_method(rb_klass, "z", RUBY_METHOD_FUNC(rb_z), 0); + rb_define_method(rb_klass, "z=", RUBY_METHOD_FUNC(rb_set_z), 1); + + rb_define_method(rb_klass, "to_s", RUBY_METHOD_FUNC(rb_to_s), 0); + rb_define_method(rb_klass, "to_ary", RUBY_METHOD_FUNC(rb_to_ary), 0); +} + +/* + * call-seq: + * combatible?(obj) + * + * Return compatibility to CvPoint3D32f. Return true if object have method #x and #y and #z. + * + * For example. + * class MyPoint3D32f + * def x + * 95.7 + * end + * def y + * 70.2 + * end + * def z + * 10.0 + * end + * end + * mp = MyPoint3D32f.new + * CvPoint3D32f.compatible?(mp) #=> true + * CvPoint3D32f.new(mp) #=> same as CvPoint3D32f(95.7, 70.2) + */ +VALUE +rb_compatible_q(VALUE klass, VALUE object) +{ + return (rb_respond_to(object, rb_intern("x")) && rb_respond_to(object, rb_intern("y"))) ? Qtrue : Qfalse; +} + +VALUE +rb_allocate(VALUE klass) +{ + CvPoint3D32f *ptr; + return Data_Make_Struct(klass, CvPoint3D32f, 0, -1, ptr); +} + +/* + * call-seq: + * new + * new(obj) + * new(x, y, z) + * + * Create new 3D-coordinate, (x, y, z). + * + * new() is same as new(0.0, 0.0, 0.0) + * + * new(obj) is same as new(obj.x.to_f, obj.y.to_f, obj.z.to_f) + */ +VALUE +rb_initialize(int argc, VALUE *argv, VALUE self) +{ + VALUE obj, x, y, z; + switch (argc) { + case 0: + break; + case 1: + obj = argv[0]; + if(rb_compatible_q(rb_klass, obj)) { + CVPOINT3D32F(self)->x = NUM2DBL(rb_funcall(rb_funcall(obj, rb_intern("x"), 0), rb_intern("to_f"), 0)); + CVPOINT3D32F(self)->y = NUM2DBL(rb_funcall(rb_funcall(obj, rb_intern("y"), 0), rb_intern("to_f"), 0)); + CVPOINT3D32F(self)->z = NUM2DBL(rb_funcall(rb_funcall(obj, rb_intern("z"), 0), rb_intern("to_f"), 0)); + }else{ + rb_raise(rb_eArgError, "object is not compatible %s.", rb_class2name(rb_klass)); + } + break; + case 3: + x = argv[0], y = argv[1], z = argv[2]; + CVPOINT3D32F(self)->x = NUM2DBL(x); + CVPOINT3D32F(self)->y = NUM2DBL(y); + CVPOINT3D32F(self)->z = NUM2DBL(z); + break; + default: + rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..2)", argc); + } + return Qnil; +} + +/* + * Return parameter on x-axis. + */ +VALUE +rb_x(VALUE self) +{ + return rb_float_new(CVPOINT2D32F(self)->x); +} + +/* + * call-seq: + * x = val + * + * Set x-axis parameter, return self. + */ +VALUE +rb_set_x(VALUE self, VALUE x) +{ + CVPOINT2D32F(self)->x = NUM2DBL(x); + return self; +} + +/* + * Return parameter on y-axis. + */ +VALUE +rb_y(VALUE self) +{ + return rb_float_new(CVPOINT2D32F(self)->y); +} + +/* + * call-seq: + * y = val + * + * Set y-axis parameter, return self. + */ +VALUE +rb_set_y(VALUE self, VALUE y) +{ + CVPOINT2D32F(self)->y = NUM2DBL(y); + return self; +} + +/* + * Return parameter on z-axis. + */ +VALUE +rb_z(VALUE self) +{ + return rb_float_new(CVPOINT3D32F(self)->z); +} + +/* + * call-seq: + * z = val + * + * Set z-axis parameter, return self. + */ +VALUE +rb_set_z(VALUE self, VALUE z) +{ + CVPOINT3D32F(self)->z = NUM2DBL(z); + return self; +} + +/* + * call-seq: + * to_s -> "" + * + * Return x and y by String. + */ +VALUE +rb_to_s(VALUE self) +{ + const int i = 5; + VALUE str[i]; + str[0] = rb_str_new2("<%s:(%f,%f,%f)>"); + str[1] = rb_str_new2(rb_class2name(CLASS_OF(self))); + str[2] = rb_x(self); + str[3] = rb_y(self); + str[4] = rb_z(self); + return rb_f_sprintf(i, str); +} + +/* + * call-seq: + * to_ary -> [x, y, z] + * + * Return x and y by Array. + */ +VALUE +rb_to_ary(VALUE self) +{ + return rb_ary_new3(3, rb_x(self), rb_y(self), rb_z(self)); +} + +VALUE +new_object(CvPoint3D32f point) +{ + VALUE object = rb_allocate(rb_klass); + *CVPOINT3D32F(object) = point; + return object; +} + +__NAMESPACE_END_CVPOINT3D32F +__NAMESPACE_END_OPENCV diff --git a/ext/cvpoint3d32f.h b/ext/cvpoint3d32f.h new file mode 100644 index 00000000..d6b4c48c --- /dev/null +++ b/ext/cvpoint3d32f.h @@ -0,0 +1,64 @@ +/************************************************************ + + cvpoint3d32f.h - + + $Author: lsxi $ + + Copyright (C) 2005-2008 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVPOINT3D32F_H +#define RUBY_OPENCV_CVPOINT3D32F_H + +#define __NAMESPACE_BEGIN_CVPOINT3D32F namespace cCvPoint3D32f{ +#define __NAMESPACE_END_CVPOINT3D32F } + +#include"opencv.h" + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVPOINT3D32F + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_compatible_q(VALUE klass, VALUE object); + +VALUE rb_allocate(VALUE klass); +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); +VALUE rb_x(VALUE self); +VALUE rb_set_x(VALUE self, VALUE x); +VALUE rb_y(VALUE self); +VALUE rb_set_y(VALUE self, VALUE y); +VALUE rb_z(VALUE self); +VALUE rb_set_z(VALUE self, VALUE z); + +VALUE rb_to_s(VALUE self); +VALUE rb_to_ary(VALUE self); + +VALUE new_object(CvPoint3D32f point); + +__NAMESPACE_END_CVPOINT3D32F + +inline CvPoint3D32f* +CVPOINT3D32F(VALUE object) +{ + CvPoint3D32f *ptr; + Data_Get_Struct(object, CvPoint3D32f, ptr); + return ptr; +} + +inline CvPoint3D32f +VALUE_TO_CVPOINT3D32F(VALUE object) +{ + if(cCvPoint3D32f::rb_compatible_q(cCvPoint3D32f::rb_class(), object)){ + return cvPoint3D32f(NUM2DBL(rb_funcall(object, rb_intern("x"), 0)), + NUM2DBL(rb_funcall(object, rb_intern("y"), 0)), + NUM2DBL(rb_funcall(object, rb_intern("z"), 0))); + }else{ + rb_raise(rb_eTypeError, "require %s or compatible object.", rb_class2name(cCvPoint3D32f::rb_class())); + } +} + +__NAMESPACE_END_OPENCV +#endif // RUBY_OPENCV_CVPOINT3D32F_H diff --git a/ext/cvrect.cpp b/ext/cvrect.cpp new file mode 100644 index 00000000..80f67af3 --- /dev/null +++ b/ext/cvrect.cpp @@ -0,0 +1,340 @@ +/************************************************************ + + cvrect.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include "cvrect.h" +/* + * Document-class: OpenCV::CvRect + * + * This class have coordinate of top-left point(x, y) and size, width and height. + * + * + * C stracture is here, very simple. + * typdef struct CvRect{ + * int x; + * int y; + * int width; + * int height; + * } + * + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVRECT + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if(rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + rb_klass = rb_define_class_under(opencv, "CvRect", rb_cObject); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_singleton_method(rb_klass, "compatible?", RUBY_METHOD_FUNC(rb_compatible_q), 1); + rb_define_private_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); + + rb_define_method(rb_klass, "x", RUBY_METHOD_FUNC(rb_x), 0); + rb_define_method(rb_klass, "x=", RUBY_METHOD_FUNC(rb_set_x), 1); + rb_define_method(rb_klass, "y", RUBY_METHOD_FUNC(rb_y), 0); + rb_define_method(rb_klass, "y=", RUBY_METHOD_FUNC(rb_set_y), 1); + rb_define_method(rb_klass, "width", RUBY_METHOD_FUNC(rb_width), 0); + rb_define_method(rb_klass, "width=", RUBY_METHOD_FUNC(rb_set_width), 1); + rb_define_method(rb_klass, "height", RUBY_METHOD_FUNC(rb_height), 0); + rb_define_method(rb_klass, "height=", RUBY_METHOD_FUNC(rb_set_height), 1); + rb_define_method(rb_klass, "center", RUBY_METHOD_FUNC(rb_center), 0); + rb_define_method(rb_klass, "points", RUBY_METHOD_FUNC(rb_points), 0); + rb_define_method(rb_klass, "top_left", RUBY_METHOD_FUNC(rb_top_left), 0); + rb_define_method(rb_klass, "top_right", RUBY_METHOD_FUNC(rb_top_right), 0); + rb_define_method(rb_klass, "bottom_left", RUBY_METHOD_FUNC(rb_bottom_left), 0); + rb_define_method(rb_klass, "bottom_right", RUBY_METHOD_FUNC(rb_bottom_right), 0); + rb_define_method(rb_klass, "or", RUBY_METHOD_FUNC(rb_or), 1); + rb_define_alias(rb_klass, "|", "or"); +} + +/* + * call-seq: + * combatible?(obj) + * + * Return compatibility to CvRect. Return true if object have method #x and #y and #width and #height. + * + * For example. + * class MyRect + * def x + * 1 + * end + * def y + * 2 + * end + * def width + * 10 + * end + * def height + * 20 + * end + * end + * mr = MyRect.new + * CvRect.compatible?(mp) #=> true + * CvRect.new(mp) #=> same as CvRect(1, 2, 10, 20) + */ +VALUE +rb_compatible_q(VALUE klass, VALUE object) +{ + return (rb_respond_to(object, rb_intern("x")) && rb_respond_to(object, rb_intern("y")) && rb_respond_to(object, rb_intern("width")) && rb_respond_to(object, rb_intern("height"))) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * CvRect.bounding + * + */ +VALUE +rb_bounding(VALUE klass, VALUE points) +{ + /* not yet */ + return Qnil; +} + +VALUE +rb_allocate(VALUE klass) +{ + CvRect *ptr; + return Data_Make_Struct(klass, CvRect, 0, -1, ptr); +} + +/* + * call-seq: + * new -> CvRect.new(0, 0, 0, 0) + * new(obj) -> CvRect.new(obj.x.to_i, obj.y.to_i, obj.width.to_i, obj.height.to_i) + * new(x, y, width, height) + * + * Create new rectangle area. (x, y) is top-left point, and width, height is size of area. + * It is dropped below the decimal point. + * + * new() is same as new(0, 0, 0, 0) + * + * new(obj) is same as new(obj.x.to_i, obj.y.to_i, obj.width.to_i, obj.height.to_i) + */ +VALUE +rb_initialize(int argc, VALUE *argv, VALUE self) +{ + VALUE object, x, y, width, height; + switch (argc) { + case 0: + break; + case 1: + object = argv[0]; + if(rb_compatible_q(rb_klass, object)) { + CVRECT(self)->x = NUM2INT(rb_funcall(rb_funcall(object, rb_intern("x"), 0), rb_intern("to_i"), 0)); + CVRECT(self)->y = NUM2INT(rb_funcall(rb_funcall(object, rb_intern("y"), 0), rb_intern("to_i"), 0)); + CVRECT(self)->width = NUM2INT(rb_funcall(rb_funcall(object, rb_intern("width"), 0), rb_intern("to_i"), 0)); + CVRECT(self)->height = NUM2INT(rb_funcall(rb_funcall(object, rb_intern("height"), 0), rb_intern("to_i"), 0)); + }else{ + rb_raise(rb_eArgError, "object is not compatible %s.", rb_class2name(rb_klass)); + } + break; + case 4: + x = argv[0], y = argv[1], width = argv[2], height = argv[3]; + CVRECT(self)->x = NUM2INT(x); + CVRECT(self)->y = NUM2INT(y); + CVRECT(self)->width = NUM2INT(width); + CVRECT(self)->height = NUM2INT(height); + break; + default: + rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..2)", argc); + } + return Qnil; +} + +/* + * Return parameter on x-axis of top-left point. + */ +VALUE +rb_x(VALUE self) +{ + return INT2FIX(CVRECT(self)->x); +} + +/* + * call-seq: + * x = val + * + * Set x-axis parameter of top-left point, return self. + * It is dropped below the decimal point. + */ +VALUE +rb_set_x(VALUE self, VALUE x) +{ + CVRECT(self)->x = NUM2INT(x); + return self; +} + +/* + * Return parameter on y-axis of top-left point. + */ +VALUE +rb_y(VALUE self) +{ + return INT2FIX(CVRECT(self)->y); +} + +/* + * call-seq: + * y = val + * + * Set y-axis parameter of top-left point, return self. + * It is dropped below the decimal point. + */ +VALUE +rb_set_y(VALUE self, VALUE y) +{ + CVRECT(self)->y = NUM2INT(y); + return self; +} + +/* + * Return size of x-axis. + */ +VALUE +rb_width(VALUE self) +{ + return INT2FIX(CVRECT(self)->width); +} + +/* + * call-seq: + * width = val + * + * Set x-axis size, return self. + * It is dropped below the decimal point. + */ +VALUE +rb_set_width(VALUE self, VALUE x) +{ + CVRECT(self)->width = NUM2INT(x); + return self; +} + +/* + * Return size of y-axis. + */ +VALUE +rb_height(VALUE self) +{ + return INT2FIX(CVRECT(self)->height); +} + +/* + * call-seq: + * height = val + * + * Set y-axis size, return self. + * It is dropped below the decimal point. + */ +VALUE +rb_set_height(VALUE self, VALUE y) +{ + CVRECT(self)->height = NUM2INT(y); + return self; +} + +/* + * Return center point of rectangle. + */ +VALUE +rb_center(VALUE self) +{ + CvRect *rect = CVRECT(self); + return cCvPoint2D32f::new_object(cvPoint2D32f((float)rect->x + (float)rect->width / 2.0, + (float)rect->y + (float)rect->height / 2.0)); +} + +/* + * Return 4 points (top-left, bottom-left, bottom-right, top-right) + */ +VALUE +rb_points(VALUE self) +{ + CvRect *rect = CVRECT(self); + return rb_ary_new3(4, + cCvPoint::new_object(cvPoint(rect->x, rect->y)), + cCvPoint::new_object(cvPoint(rect->x, rect->y + rect->height)), + cCvPoint::new_object(cvPoint(rect->x + rect->width, rect->y + rect->height)), + cCvPoint::new_object(cvPoint(rect->x + rect->width, rect->y)) + ); +} + +/* + * Return top-left point of rectangle. + */ +VALUE +rb_top_left(VALUE self) +{ + return cCvPoint::new_object(cvPoint(CVRECT(self)->x, CVRECT(self)->y)); +} + +/* + * Return top-right point of rectangle. + */ +VALUE +rb_top_right(VALUE self) +{ + return cCvPoint::new_object(cvPoint(CVRECT(self)->x + CVRECT(self)->width, CVRECT(self)->y)); +} + +/* + * Return bottom-left point of rectangle. + */ +VALUE +rb_bottom_left(VALUE self) +{ + return cCvPoint::new_object(cvPoint(CVRECT(self)->x, CVRECT(self)->y + CVRECT(self)->height)); +} + +/* + * Return bottom-right point of rectangle. + */ +VALUE +rb_bottom_right(VALUE self) +{ + return cCvPoint::new_object(cvPoint(CVRECT(self)->x + CVRECT(self)->width, CVRECT(self)->y + CVRECT(self)->height)); +} + +/* + * call-seq: + * or(rect) -> cvrect + * + * Finds bounding rectangle for self and given rectangles. + */ +VALUE +rb_or(VALUE self, VALUE rect) +{ + return cCvRect::new_object(cvMaxRect(CVRECT(self), CVRECT(rect))); +} + +VALUE +new_object(CvRect rect) +{ + VALUE object = rb_allocate(rb_klass); + *CVRECT(object) = rect; + return object; +} + +__NAMESPACE_END_CVRECT +__NAMESPACE_END_OPENCV diff --git a/ext/cvrect.h b/ext/cvrect.h new file mode 100644 index 00000000..3686155b --- /dev/null +++ b/ext/cvrect.h @@ -0,0 +1,79 @@ +/************************************************************ + + cvrect.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVRECT_H +#define RUBY_OPENCV_CVRECT_H + +#include"opencv.h" + +#define __NAMESPACE_BEGIN_CVRECT namespace cCvRect{ +#define __NAMESPACE_END_CVRECT } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVRECT + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_compatible_q(VALUE klass, VALUE object); +VALUE rb_bounding(VALUE klass, VALUE points); + +VALUE rb_allocate(VALUE klass); +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); +VALUE rb_x(VALUE self); +VALUE rb_set_x(VALUE self, VALUE x); +VALUE rb_y(VALUE self); +VALUE rb_set_y(VALUE self, VALUE y); +VALUE rb_width(VALUE self); +VALUE rb_set_width(VALUE self, VALUE width); +VALUE rb_height(VALUE self); +VALUE rb_set_height(VALUE self, VALUE height); + +VALUE rb_center(VALUE self); +VALUE rb_points(VALUE self); +VALUE rb_top_left(VALUE self); +VALUE rb_set_top_left(VALUE self, VALUE point); +VALUE rb_top_right(VALUE self); +VALUE rb_set_top_right(VALUE self, VALUE point); +VALUE rb_bottom_left(VALUE self); +VALUE rb_set_bottom_left(VALUE self, VALUE point); +VALUE rb_bottom_right(VALUE self); +VALUE rb_set_bottom_right(VALUE self, VALUE point); + +VALUE rb_or(VALUE self, VALUE rect); + +VALUE new_object(CvRect rect); + +__NAMESPACE_END_CVRECT + +inline CvRect* +CVRECT(VALUE object) +{ + CvRect *ptr; + Data_Get_Struct(object, CvRect, ptr); + return ptr; +} + +inline CvRect +VALUE_TO_CVRECT(VALUE object) +{ + if(cCvRect::rb_compatible_q(cCvRect::rb_class(), object)){ + return cvRect(NUM2INT(rb_funcall(object, rb_intern("x"), 0)), + NUM2INT(rb_funcall(object, rb_intern("y"), 0)), + NUM2INT(rb_funcall(object, rb_intern("width"), 0)), + NUM2INT(rb_funcall(object, rb_intern("height"), 0))); + }else{ + rb_raise(rb_eTypeError, "require %s or compatible object.", rb_class2name(cCvRect::rb_class())); + } +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVRECT_H diff --git a/ext/cvscalar.cpp b/ext/cvscalar.cpp new file mode 100644 index 00000000..0b4923b5 --- /dev/null +++ b/ext/cvscalar.cpp @@ -0,0 +1,227 @@ +/************************************************************ + + cvscalar.cpp - + + $Author: lsxi $ + + Copyright (C) 2005 Masakazu Yonekura + +************************************************************/ +#include "cvscalar.h" +/* + * Document-class: OpenCV::CvScalar + * + * Element-value of one pixel. + * OpenCV supports the image of 4-channels in the maximum. + * Therefore, CvScalar has 4-values. + * + * C structure is here, very simple. + * typdef struct CvScalar{ + * double val[4]; + * }CvScalar; + * + * If obtain CvScalar-object from the method of CvMat(or IplImage), + * the channel outside the range is obtained as all 0. + * + * image = IplImage::load("opencv.jpg") #=> 3-channel 8bit-depth BGR image + * pixel = image[10, 20] #=> Get pixel value of (10, 20) of image. pixel is CvScalar-object. + * blue, green, red = pixel[0], pixel[1], pixel[2] + * # pixel[3] always 0. + * + * CvColor is alias of CvScalar. + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVSCALAR + + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + + rb_klass = rb_define_class_under(opencv, "CvScalar", rb_cObject); + /* CvScalar: class */ + rb_define_const(opencv, "CvColor", rb_klass); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); + rb_define_method(rb_klass, "[]", RUBY_METHOD_FUNC(rb_aref), 1); + rb_define_method(rb_klass, "[]=", RUBY_METHOD_FUNC(rb_aset), 2); + rb_define_method(rb_klass, "sub", RUBY_METHOD_FUNC(rb_sub), -1); + rb_define_alias(rb_klass, "-", "sub"); + + rb_define_method(rb_klass, "to_s", RUBY_METHOD_FUNC(rb_to_s), 0); + rb_define_method(rb_klass, "to_ary", RUBY_METHOD_FUNC(rb_to_ary), 0); + + rb_define_const(rb_klass, "Black", cCvScalar::new_object(cvScalar(0x0,0x0,0x0))); + rb_define_const(rb_klass, "Silver", cCvScalar::new_object(cvScalar(0x0c,0x0c,0x0c))); + rb_define_const(rb_klass, "Gray", cCvScalar::new_object(cvScalar(0x80,0x80,0x80))); + rb_define_const(rb_klass, "White", cCvScalar::new_object(cvScalar(0xff,0xff,0xff))); + rb_define_const(rb_klass, "Maroon", cCvScalar::new_object(cvScalar(0x0,0x0,0x80))); + rb_define_const(rb_klass, "Red", cCvScalar::new_object(cvScalar(0x0,0x0,0xff))); + rb_define_const(rb_klass, "Purple", cCvScalar::new_object(cvScalar(0x80,0x0,0x80))); + rb_define_const(rb_klass, "Fuchsia", cCvScalar::new_object(cvScalar(0xff,0x0,0xff))); + rb_define_const(rb_klass, "Green", cCvScalar::new_object(cvScalar(0x0,0x80,0x0))); + rb_define_const(rb_klass, "Lime", cCvScalar::new_object(cvScalar(0x0,0xff,0x0))); + rb_define_const(rb_klass, "Olive", cCvScalar::new_object(cvScalar(0x0,0x80,0x80))); + rb_define_const(rb_klass, "Yellow", cCvScalar::new_object(cvScalar(0x0,0xff,0xff))); + rb_define_const(rb_klass, "Navy", cCvScalar::new_object(cvScalar(0x80,0x0,0x0))); + rb_define_const(rb_klass, "Blue", cCvScalar::new_object(cvScalar(0xff,0x0,0x0))); + rb_define_const(rb_klass, "Teal", cCvScalar::new_object(cvScalar(0x80,0x80,0x0))); + rb_define_const(rb_klass, "Aqua", cCvScalar::new_object(cvScalar(0xff,0xff,0x0))); +} + +VALUE +rb_allocate(VALUE klass) +{ + CvScalar *ptr; + return Data_Make_Struct(klass, CvScalar, 0, -1, ptr); +} + +/* + * call-seq: + * new([d1][,d2][,d3][,d4]) + * + * Create new Scalar. Argument should be Fixnum (or nil as 0). + */ +VALUE +rb_initialize(int argc, VALUE *argv, VALUE self) +{ + VALUE val[4]; + rb_scan_args(argc, argv, "04", &val[0], &val[1], &val[2], &val[3]); + for (int i = 0; i < 4; i++) { + CVSCALAR(self)->val[i] = NIL_P(val[i]) ? 0 : NUM2DBL(val[i]); + } + return self; +} + +/* + * call-seq: + * [index] + * + * Return value of index dimension. + */ +VALUE +rb_aref(VALUE self, VALUE index) +{ + int idx = NUM2INT(index); + if (!(idx < 0) && idx < 4) { + return rb_float_new(CVSCALAR(self)->val[idx]); + }else{ + rb_raise(rb_eIndexError, "scalar index should be 0...4"); + } +} + +/* + * call-seq: + * [index] = value + * + * Set value of index dimension to value + */ +VALUE +rb_aset(VALUE self, VALUE index, VALUE value) +{ + int idx = NUM2INT(index); + if (!(idx < 0) && idx < 4) { + CVSCALAR(self)->val[idx] = NUM2DBL(value); + return self; + }else{ + rb_raise(rb_eIndexError, "scalar index should be 0...4"); + } +} + +/* + * call-seq: + * sub(val[,mask]) + * + * Return new CvScalar if val is CvScalar or compatible object. + * self[I] - val[I] + * Or return new CvMat if val is CvMat or subclass. + */ +VALUE +rb_sub(int argc, VALUE *argv, VALUE self) +{ + VALUE val, mask; + rb_scan_args(argc, argv, "11", &val, &mask); + if(rb_obj_is_kind_of(val, cCvMat::rb_class())){ + VALUE dest = cCvMat::new_object(cvGetSize(CVARR(val)), cvGetElemType(CVARR(val))); + cvSubRS(CVARR(val), *CVSCALAR(self), CVARR(dest), MASK(mask)); + return dest; + }else{ + CvScalar *src = CVSCALAR(self), scl = VALUE_TO_CVSCALAR(val); + return new_object(cvScalar(src->val[0] - scl.val[0], + src->val[1] - scl.val[1], + src->val[2] - scl.val[2], + src->val[3] - scl.val[3])); + } +} + +/* + * call-seq: + * to_s -> "" + * + * Return values by String. + */ +VALUE +rb_to_s(VALUE self) +{ + const int i = 6; + VALUE str[i]; + str[0] = rb_str_new2("<%s:%d,%d,%d,%d>"); + str[1] = rb_str_new2(rb_class2name(CLASS_OF(self))); + str[2] = rb_aref(self, INT2FIX(0)); + str[3] = rb_aref(self, INT2FIX(1)); + str[4] = rb_aref(self, INT2FIX(2)); + str[5] = rb_aref(self, INT2FIX(3)); + return rb_f_sprintf(i, str); +} + +/* + * call-seq: + * to_ary -> [self[0],self[1],self[2],self[3]] + * + * Return values by Array. + */ +VALUE +rb_to_ary(VALUE self) +{ + return rb_ary_new3(4, + rb_aref(self, INT2FIX(0)), + rb_aref(self, INT2FIX(1)), + rb_aref(self, INT2FIX(2)), + rb_aref(self, INT2FIX(3))); +} + +VALUE +new_object() +{ + VALUE object = rb_allocate(rb_klass); + *CVSCALAR(object) = cvScalar(0); + return object; +} + +VALUE +new_object(CvScalar scalar) +{ + VALUE object = rb_allocate(rb_klass); + *CVSCALAR(object) = scalar; + return object; +} + +__NAMESPACE_END_CVSCALAR +__NAMESPACE_END_OPENCV + diff --git a/ext/cvscalar.h b/ext/cvscalar.h new file mode 100644 index 00000000..381448a1 --- /dev/null +++ b/ext/cvscalar.h @@ -0,0 +1,63 @@ +/************************************************************ + + cvscalar.h - + + $Author: lsxi $ + + Copyright (C) 2005 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVSCALAR_H +#define RUBY_OPENCV_CVSCALAR_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVSCALAR namespace cCvScalar{ +#define __NAMESPACE_END_CVSCALAR } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVSCALAR + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_compatible_q(VALUE klass, VALUE object); + +VALUE rb_allocate(VALUE klass); +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); + +VALUE rb_aref(VALUE self, VALUE index); +VALUE rb_aset(VALUE self, VALUE index, VALUE value); +VALUE rb_sub(int argc, VALUE *argv, VALUE self); + +VALUE rb_to_s(VALUE self); +VALUE rb_to_ary(VALUE self); + +VALUE new_object(); +VALUE new_object(CvScalar scalar); + +__NAMESPACE_END_CVSCALAR + +inline CvScalar* +CVSCALAR(VALUE object) +{ + CvScalar *ptr; + Data_Get_Struct(object, CvScalar, ptr); + return ptr; +} + +inline CvScalar +VALUE_TO_CVSCALAR(VALUE object) +{ + if(FIXNUM_P(object)) + return cvScalarAll(FIX2INT(object)); + return cvScalar(NUM2INT(rb_funcall(object, rb_intern("[]"), 1, INT2FIX(0))), + NUM2INT(rb_funcall(object, rb_intern("[]"), 1, INT2FIX(1))), + NUM2INT(rb_funcall(object, rb_intern("[]"), 1, INT2FIX(2))), + NUM2INT(rb_funcall(object, rb_intern("[]"), 1, INT2FIX(3)))); +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVSCALAR_H diff --git a/ext/cvseq.cpp b/ext/cvseq.cpp new file mode 100644 index 00000000..be6f22dd --- /dev/null +++ b/ext/cvseq.cpp @@ -0,0 +1,583 @@ +/************************************************************ + + cvseq.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include "cvseq.h" +/* + * Document-class: OpenCV::CvSeq + * + * Generic Sequence class. CvSeq has the method like Array (push, pop, select, etc...). + * But, CvSeq cannot store the object of a different class. + * When storing object in CvSeq, conversion is automatically tried, + * and the object occurs the error if it cannot be done. + * + * e.g. + * seq = CvSeq.new(CvPoint) # Argument mean "this sequence contain only this class's object" + * seq.push(CvPoint.new(0, 0)) # => it's ok + * seq.push("hello") # => try convert "hello" to CvPoint. but can't do it. raise error. + * + * If the sequecne contain object of class A. + * When storing object(named "obj") of class B to the sequence. + * Try automatically : A.from_B(obj) => object of class A. + * + * CvSeq has the circulation structure internally. + * That is, when the sequence has three values ("a","b","c"), + * seq[0] and seq[3] are same "a", and seq[-1] and seq[2] are same "c". + * + * The sequence might have another sequence outside. see below. + * Each sequece has h_prev, h_next, v_prev, v_next method. + * If the adjoining sequence exists, each method return the adjoining sequence. + * Otherwise return nil. + * + * link:../images/CvSeq_relationmap.png + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVSEQ + +// contain sequence-block class +st_table *seqblock_klass = st_init_numtable(); + +VALUE +seqblock_class(void *ptr) +{ + VALUE klass; + if(!st_lookup(seqblock_klass, (st_data_t)ptr, (st_data_t*)&klass)){ + rb_raise(rb_eTypeError, "Invalid sequence error."); + } + return klass; +} + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if(rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + rb_klass = rb_define_class_under(opencv, "CvSeq", rb_cObject); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_private_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); + rb_define_method(rb_klass, "total", RUBY_METHOD_FUNC(rb_total), 0); + rb_define_alias(rb_klass, "length", "total"); + rb_define_alias(rb_klass, "size", "total"); + rb_define_method(rb_klass, "empty?", RUBY_METHOD_FUNC(rb_empty_q), 0); + rb_define_method(rb_klass, "[]", RUBY_METHOD_FUNC(rb_aref), 1); + rb_define_method(rb_klass, "first", RUBY_METHOD_FUNC(rb_first), 0); + rb_define_method(rb_klass, "last", RUBY_METHOD_FUNC(rb_last), 0); + rb_define_method(rb_klass, "index", RUBY_METHOD_FUNC(rb_index), 1); + + rb_define_method(rb_klass, "h_prev", RUBY_METHOD_FUNC(rb_h_prev), 0); + rb_define_method(rb_klass, "h_next", RUBY_METHOD_FUNC(rb_h_next), 0); + rb_define_method(rb_klass, "v_prev", RUBY_METHOD_FUNC(rb_v_prev), 0); + rb_define_method(rb_klass, "v_next", RUBY_METHOD_FUNC(rb_v_next), 0); + + rb_define_method(rb_klass, "push", RUBY_METHOD_FUNC(rb_push), -2); + rb_define_alias(rb_klass, "<<", "push"); + rb_define_method(rb_klass, "pop", RUBY_METHOD_FUNC(rb_pop), 0); + rb_define_method(rb_klass, "unshift", RUBY_METHOD_FUNC(rb_unshift), -2); + rb_define_alias(rb_klass, "push_front", "unshift"); + rb_define_method(rb_klass, "shift", RUBY_METHOD_FUNC(rb_shift), 0); + rb_define_alias(rb_klass, "pop_front", "shift"); + rb_define_method(rb_klass, "each", RUBY_METHOD_FUNC(rb_each), 0); + rb_define_method(rb_klass, "each_index", RUBY_METHOD_FUNC(rb_each_index), 0); + rb_define_method(rb_klass, "each_with_index", RUBY_METHOD_FUNC(rb_each_with_index), 0); + rb_define_method(rb_klass, "insert", RUBY_METHOD_FUNC(rb_insert), 2); + rb_define_method(rb_klass, "remove", RUBY_METHOD_FUNC(rb_remove), 1); + rb_define_method(rb_klass, "clear", RUBY_METHOD_FUNC(rb_clear), 0); + + rb_define_alias(rb_klass, "delete_at", "remove"); +} + +VALUE +rb_allocate(VALUE klass) +{ + return Data_Wrap_Struct(klass, mark_root_object, free, 0); +} + +void +free(void *ptr) +{ + if(ptr){ + unresist_object(ptr); + st_delete(seqblock_klass, (st_data_t*)&ptr, 0); + } +} + +void +resist_class_information_of_sequence(CvSeq *seq, VALUE klass) +{ + st_insert(seqblock_klass, (st_data_t)seq, (st_data_t)klass); +} + +/* + * call-seq: + * CvSeq.new(type[,storage]) + * + * Return a new CvSeq. type should be following classes. + * + * * CvIndex + * * CvPoint + */ +VALUE +rb_initialize(int argc, VALUE *argv, VALUE self) +{ + VALUE klass, storage; + rb_scan_args(argc, argv, "11", &klass, &storage); + if(!rb_obj_is_kind_of(klass, rb_cClass)) + rb_raise(rb_eTypeError, "argument 1 (sequence-block class) should be %s.", rb_class2name(rb_cClass)); + CvSeq *seq = 0; + storage = CHECK_CVMEMSTORAGE(storage); + int type = 0, size = 0; + if(klass == cCvIndex::rb_class()){ + type = CV_SEQ_ELTYPE_INDEX; + size = sizeof(CvIndex); + }else if(klass == cCvPoint::rb_class()){ + type = CV_SEQ_ELTYPE_POINT; + size = sizeof(CvPoint); + }else if(klass == cCvPoint2D32f::rb_class()){ + type = CV_SEQ_ELTYPE_POINT; + size = sizeof(CvPoint2D32f); + }else if(klass == cCvPoint3D32f::rb_class()){ + type = CV_SEQ_ELTYPE_POINT3D; + size = sizeof(CvPoint3D32f); + } + auto_extend(self); + // todo: more various class will be support. + if(!size) + rb_raise(rb_eTypeError, "unsupport %s class for sequence-block.", rb_class2name(klass)); + seq = cvCreateSeq(type, sizeof(CvSeq), size, CVMEMSTORAGE(storage)); + DATA_PTR(self) = seq; + resist_root_object(seq, storage); + // resist class information of this sequence. + st_insert(seqblock_klass, (st_data_t)seq, (st_data_t)klass); + return self; +} + +/* + * call-seq: + * total -> int + * + * Return total number of sequence-block. + */ +VALUE +rb_total(VALUE self) +{ + return INT2FIX(CVSEQ(self)->total); +} + +/* + * call-seq: + * empty? -> true or false. + * + * Return true if contain no object, otherwize return false. + */ +VALUE +rb_empty_q(VALUE self) +{ + return CVSEQ(self)->total == 0 ? Qtrue : Qfalse; +} + +/* + * call-seq: + * [index] -> obj or nil + * + * Return sequence-block at index. + */ +VALUE +rb_aref(VALUE self, VALUE index) +{ + CvSeq *seq = CVSEQ(self); + if(!(seq->total > 0)) + return Qnil; + return REFER_OBJECT(seqblock_class(seq), cvGetSeqElem(seq, NUM2INT(index) % seq->total), self); +} + +/* + * call-seq: + * first -> obj or nil + * + * Return first sequence-block. + */ +VALUE +rb_first(VALUE self) +{ + CvSeq *seq = CVSEQ(self); + if(!(seq->total > 0)) + return Qnil; + return REFER_OBJECT(seqblock_class(seq), cvGetSeqElem(seq, 0), self); +} + +/* + * call-seq: + * last -> obj or nil + * + * Return last sequence-block. + */ +VALUE +rb_last(VALUE self) +{ + CvSeq *seq = CVSEQ(self); + if(!(seq->total > 0)) + return Qnil; + return REFER_OBJECT(seqblock_class(seq), cvGetSeqElem(seq, -1), self); +} + +/*when storing it in CvSeq. + * call-seq: + * index(obj) -> int or nil + * + * Return the index of the first object in self. Return nil if no match is found. + */ +VALUE +rb_index(VALUE self, VALUE object) +{ + CvSeq *seq = CVSEQ(self); + int index; + if(CLASS_OF(object) == seqblock_class(seq)){ + index = cvSeqElemIdx(seq, DATA_PTR(object)); + if(!(index < 0)) + return INT2FIX(index); + }else{ + rb_warn("sequence-block class unmatch."); + } + return Qnil; +} + +/* + * call-seq: + * h_prev -> seq or nil + * + * Return the sequence horizontally located in previous. + * Return nil if not existing. + */ +VALUE +rb_h_prev(VALUE self) +{ + CvSeq *seq = CVSEQ(self); + if (seq->h_prev) { + return new_sequence(CLASS_OF(self), seq->h_prev, seqblock_class(seq), lookup_root_object(seq)); + //new_sequence(seq->h_prev, CLASS_OF(self), seqblock_class(seq), lookup_root_object(seq)); + } else + return Qnil; +} + +/* + * call-seq: + * h_next -> seq or nil + * + * Return the sequence horizontally located in next. + * Return nil if not existing. + */ +VALUE +rb_h_next(VALUE self) +{ + CvSeq *seq = CVSEQ(self); + if (seq->h_next) { + return new_sequence(CLASS_OF(self), seq->h_next, seqblock_class(seq), lookup_root_object(seq)); + //new_sequence(seq->h_next, CLASS_OF(self), seqblock_class(seq), lookup_root_object(seq)); + } else + return Qnil; +} + +/* + * call-seq: + * v_prev -> seq or nil + * + * Return the sequence vertically located in previous. + * Return nil if not existing. + */ +VALUE +rb_v_prev(VALUE self) +{ + CvSeq *seq = CVSEQ(self); + if (seq->v_prev) { + return new_sequence(CLASS_OF(self), seq->v_prev, seqblock_class(seq), lookup_root_object(seq)); + } else + return Qnil; +} + +/* + * call-seq: + * v_prev -> seq or nil + * + * Return the sequence vertically located in next. + * Return nil if not existing. + */ +VALUE +rb_v_next(VALUE self) +{ + CvSeq *seq = CVSEQ(self); + if (seq->v_next) { + return new_sequence(CLASS_OF(self), seq->v_next, seqblock_class(seq), lookup_root_object(seq)); + } else + return Qnil; +} + +/* + * call-seq: + * push(obj, ...) -> self + * + * Append - Pushes the given object(s) on the end of this sequence. This expression return the sequence itself, + * so several append may be chainded together. + */ +VALUE +rb_push(VALUE self, VALUE args) +{ + CvSeq *seq = CVSEQ(self); + VALUE klass = seqblock_class(seq), object; + void *buffer = 0; + for(int i = 0; i < RARRAY(args)->len; i++){ + object = RARRAY(args)->ptr[i]; + if(CLASS_OF(object) == klass){ + cvSeqPush(seq, DATA_PTR(object)); + }else if(rb_obj_is_kind_of(object, rb_klass) && CLASS_OF(object) == klass){ // object is CvSeq + buffer = cvCvtSeqToArray(CVSEQ(object), cvAlloc(CVSEQ(object)->total * CVSEQ(object)->elem_size)); + cvSeqPushMulti(seq, buffer, CVSEQ(object)->total); + cvFree((void**)&buffer); + }else{ + object = CONVERT(object, klass); + cvSeqPush(seq, DATA_PTR(object)); + } + } + return self; +} + +/* + * call-seq: + * pop -> obj or nil + * + * Remove the last sequence-block from self and return it, + * or nil if the sequence is empty. + */ +VALUE +rb_pop(VALUE self) +{ + CvSeq *seq = CVSEQ(self); + if(!(seq->total > 0)){ + return Qnil; + } + VALUE object = GENERIC_OBJECT(seqblock_class(seq), malloc(seq->elem_size)); + cvSeqPop(seq, DATA_PTR(object)); + return object; +} + +/* + * call-seq: + * clear -> self + * + * Clears sequence. Removes all elements from the sequence. + */ +VALUE +rb_clear(VALUE self) +{ + cvClearSeq(CVSEQ(self)); + return self; +} + +/* + * call-seq: + * unshift -> self + * + * Prepends objects to the front of sequence. other elements up one. + */ +VALUE +rb_unshift(VALUE self, VALUE args) +{ + CvSeq *seq = CVSEQ(self); + VALUE klass = seqblock_class(seq), object; + void *buffer = 0; + for(int i = 0; i < RARRAY(args)->len; i++){ + object = RARRAY(args)->ptr[i]; + if(CLASS_OF(object) == klass){ + cvSeqPushFront(seq, DATA_PTR(object)); + }else if(rb_obj_is_kind_of(object, rb_klass) && CLASS_OF(object) == klass){ + buffer = cvCvtSeqToArray(CVSEQ(object), cvAlloc(CVSEQ(object)->total * CVSEQ(object)->elem_size)); + cvSeqPushMulti(seq, buffer, CVSEQ(object)->total, 1); + cvFree((void**)&buffer); + }else{ + object = CONVERT(object, klass); + cvSeqPushFront(seq, DATA_PTR(object)); + } + } + return self; +} + +/* + * call-seq: + * shift -> obj or nil + * + * Returns the first element of self and removes it (shifting all other elements down by one). Returns nil if the array is empty. + */ +VALUE +rb_shift(VALUE self) +{ + CvSeq *seq = CVSEQ(self); + if(!(seq->total > 0)){ + return Qnil; + } + VALUE object = GENERIC_OBJECT(seqblock_class(seq), malloc(seq->elem_size)); + cvSeqPopFront(seq, DATA_PTR(object)); + return object; +} + +/* + * call-seq: + * each{|obj| ... } -> self + * + * Calls block once for each sequence-block in self, + * passing that sequence-block as a parameter. + * seq = CvSeq.new(CvIndex) + * seq.push(5, 6, 7) + * seq.each{|x| print x, " -- " + * produces: + * 5 -- 6 -- 7 -- + */ +VALUE +rb_each(VALUE self) +{ + CvSeq *seq = CVSEQ(self); + if(seq->total > 0){ + VALUE klass = seqblock_class(seq); + for(int i = 0; i < seq->total; i++){ + rb_yield(REFER_OBJECT(klass, cvGetSeqElem(seq, i), self)); + } + } + return self; +} + +/* + * call-seq: + * each_index{|index| ... } -> self + * + * Same as CvSeq#each, but passes the index of the element instead of the element itself. + */ +VALUE +rb_each_index(VALUE self) +{ + CvSeq *seq = CVSEQ(self); + for(int i = 0; i < seq->total; i++) + rb_yield(INT2FIX(i)); + return self; +} + +/* + * call-seq: + * each_with_index{|obj, i| ... } -> self + * + * Calls block with two arguments, the sequence-block and its index, for each sequence-block in sequence. + */ +VALUE +rb_each_with_index(VALUE self) +{ + CvSeq *seq = CVSEQ(self); + VALUE klass = seqblock_class(seq); + for(int i = 0; i < seq->total; i++) + rb_yield_values(2, REFER_OBJECT(klass, cvGetSeqElem(seq, i), self), INT2FIX(i)); + return self; +} + +/* + * call-seq: + * insert(index,obj) -> self + * + * Inserts the given values before element with the given index (which may be negative). + */ +VALUE +rb_insert(VALUE self, VALUE index, VALUE object) +{ + Check_Type(index, T_FIXNUM); + CvSeq *seq = CVSEQ(self); + VALUE klass = seqblock_class(seq); + if(CLASS_OF(object) != klass) + object = CONVERT(object, klass); + cvSeqInsert(seq, FIX2INT(index), DATA_PTR(object)); + return self; +} + +/* + * call-seq: + * remove(index) -> obj or nil + * + * Deletes the elements at the specified index. + */ +VALUE +rb_remove(VALUE self, VALUE index) +{ + cvSeqRemove(CVSEQ(self), FIX2INT(index)); + return self; +} + +/* + * call-seq: + * clone + * + * Return copy of sequence. + */ +VALUE +rb_clone(VALUE self) +{ + CvSeq *seq = CVSEQ(self); + VALUE storage = cCvMemStorage::new_object(); + return new_sequence(CLASS_OF(self), cvCloneSeq(seq), seqblock_class(seq), storage); +} + +/* +VALUE +new_object(CvSeq *seq, VALUE klass) +{ + VALUE storage = cCvMemStorage::new_object(); + VALUE object = REFER_OBJECT(rb_klass, seq, storage); + st_insert(seqblock_klass, (st_data_t)seq, (st_data_t)klass); + return object; +} + +VALUE +new_object(CvSeq *seq, VALUE klass, VALUE storage) +{ + VALUE object = REFER_OBJECT(rb_klass, seq, storage); + st_insert(seqblock_klass, (st_data_t)seq, (st_data_t)klass); + return object; +} +*/ + + +VALUE +new_sequence(VALUE klass, CvSeq *seq, VALUE element_klass, VALUE storage) +{ + resist_root_object(seq, storage); + if (!NIL_P(element_klass)) + st_insert(seqblock_klass, (st_data_t)seq, (st_data_t)element_klass); + VALUE object = Data_Wrap_Struct(klass, mark_root_object, free, seq); + auto_extend(object); + return object; +} + +VALUE +auto_extend(VALUE object) +{ + CvSeq *seq = CVSEQ(object); + if(CV_IS_SEQ_POINT_SET(seq)){ + rb_extend_object(object, mPointSet::rb_module()); + } + return object; +} + +__NAMESPACE_END_CVSEQ +__NAMESPACE_END_OPENCV diff --git a/ext/cvseq.h b/ext/cvseq.h new file mode 100644 index 00000000..2acc5a7f --- /dev/null +++ b/ext/cvseq.h @@ -0,0 +1,71 @@ +/************************************************************ + + cvseq.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVSEQ_H +#define RUBY_OPENCV_CVSEQ_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVSEQ namespace cCvSeq{ +#define __NAMESPACE_END_CVSEQ } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVSEQ + +VALUE rb_class(); +void define_ruby_class(); + +VALUE seqblock_class(void *ptr); + +VALUE rb_allocate(VALUE klass); +void free(void *ptr); +void resist_class_information_of_sequence(CvSeq *seq, VALUE klass); + +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); +VALUE rb_total(VALUE self); +VALUE rb_empty_q(VALUE self); +VALUE rb_aref(VALUE self, VALUE index); +VALUE rb_first(VALUE self); +VALUE rb_last(VALUE self); +VALUE rb_index(VALUE self, VALUE object); +VALUE rb_h_prev(VALUE self); +VALUE rb_h_next(VALUE self); +VALUE rb_v_prev(VALUE self); +VALUE rb_v_next(VALUE self); +VALUE rb_push(VALUE self, VALUE args); +VALUE rb_pop(VALUE self); +VALUE rb_unshift(VALUE self, VALUE args); +VALUE rb_shift(VALUE self); +VALUE rb_each(VALUE self); +VALUE rb_each_index(VALUE self); +VALUE rb_each_with_index(VALUE self); +VALUE rb_insert(VALUE self, VALUE index, VALUE object); +VALUE rb_remove(VALUE self, VALUE index); +VALUE rb_clear(VALUE self); +VALUE rb_clone(VALUE self); + +VALUE new_object(CvSeq *seq, VALUE klass); +VALUE new_object(CvSeq *seq, VALUE klass, VALUE storage); +//VALUE new_object(CvSeq *seq, VALUE storage, VALUE klass); +VALUE new_sequence(VALUE klass, CvSeq *seq, VALUE element_klass, VALUE storage); +VALUE auto_extend(VALUE object); + +__NAMESPACE_END_CVSEQ + +inline CvSeq* +CVSEQ(VALUE object) +{ + CvSeq *ptr; + Data_Get_Struct(object, CvSeq, ptr); + return ptr; +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVSEQ_H diff --git a/ext/cvset.cpp b/ext/cvset.cpp new file mode 100644 index 00000000..ea17615a --- /dev/null +++ b/ext/cvset.cpp @@ -0,0 +1,63 @@ +/************************************************************ + + cvseq.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include "cvset.h" +/* + * Document-class: OpenCV::CvSet + * + * Collection of nodes. + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVSET + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if(rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * cvseq = rb_define_class_under(opencv, "CvSeq", rb_cObject); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(), cvseq = cCvSeq::rb_class(); + rb_klass = rb_define_class_under(opencv, "CvSet", cvseq); + rb_define_method(rb_klass, "active_count", RUBY_METHOD_FUNC(rb_active_count), 0); + rb_define_method(rb_klass, "free?", RUBY_METHOD_FUNC(rb_free_q), 0); +} + +/* + * ? + */ +VALUE +rb_active_count(VALUE self) +{ + return INT2FIX(CVSET(self)->active_count); +} + +/* + * ? + */ +VALUE +rb_free_q(VALUE self) +{ + return CVSET(self)->free_elems->flags < 0 ? Qtrue : Qfalse; +} + +__NAMESPACE_END_CVSET +__NAMESPACE_END_OPENCV diff --git a/ext/cvset.h b/ext/cvset.h new file mode 100644 index 00000000..6861dd08 --- /dev/null +++ b/ext/cvset.h @@ -0,0 +1,39 @@ +/************************************************************ + + cvset.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVSET_H +#define RUBY_OPENCV_CVSET_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVSET namespace cCvSet{ +#define __NAMESPACE_END_CVSET } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVSET + +VALUE rb_class(); +void define_ruby_class(); + +VALUE rb_active_count(VALUE self); +VALUE rb_free_q(VALUE self); + +__NAMESPACE_END_CVSET + +inline CvSet* +CVSET(VALUE object) +{ + CvSet *ptr; + Data_Get_Struct(object, CvSet, ptr); + return ptr; +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVSET_H diff --git a/ext/cvsize.cpp b/ext/cvsize.cpp new file mode 100644 index 00000000..39bcd51a --- /dev/null +++ b/ext/cvsize.cpp @@ -0,0 +1,223 @@ +/************************************************************ + + cvsize.cpp - + + $Author: lsxi $ + + Copyright (C) 2005 Masakazu Yonekura + +************************************************************/ +#include"cvsize.h" +/* + * Document-class: OpenCV::CvSize + * + * This class means one size on X axis Y axis. + * X and Y takes the value of the Fixnum. + * + * C structure is here, very simple. + * typdef struct CvSize{ + * int width; + * int height; + * } + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVSIZE + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if(rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + + rb_klass = rb_define_class_under(opencv, "CvSize", rb_cObject); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_singleton_method(rb_klass, "compatible?", RUBY_METHOD_FUNC(rb_compatible_q), 1); + rb_define_private_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); + rb_define_method(rb_klass, "width", RUBY_METHOD_FUNC(rb_width), 0); + rb_define_method(rb_klass, "width=", RUBY_METHOD_FUNC(rb_set_width), 1); + rb_define_method(rb_klass, "height", RUBY_METHOD_FUNC(rb_height), 0); + rb_define_method(rb_klass, "height=", RUBY_METHOD_FUNC(rb_set_height), 1); + + rb_define_method(rb_klass, "to_s", RUBY_METHOD_FUNC(rb_to_s), 0); + rb_define_method(rb_klass, "to_ary", RUBY_METHOD_FUNC(rb_to_ary), 0); +} + +/* + * call-seq: + * compatible?(obj) + * + * Return compatibility to CvSize. Return true if object have method #width and #height. + * + * For example. + * class MySize + * def width + * 10 + * end + * def height + * 20 + * end + * end + * mp = MySize.new + * CvSize.compatible?(mp) #=> true + * CvSize.new(mp) #=> same as CvSize(10, 20) + */ +VALUE +rb_compatible_q(VALUE klass, VALUE object) +{ + return (rb_respond_to(object, rb_intern("width")) && rb_respond_to(object, rb_intern("height"))) ? Qtrue : Qfalse; +} + +VALUE +rb_allocate(VALUE klass) +{ + CvSize *ptr; + return Data_Make_Struct(klass, CvSize, 0, -1, ptr); +} + +/* + * call-seq: + * new + * new(obj) + * new(width, height) + * + * Create new size of 2D, (width, height). It is dropped below the decimal point. + * + * new() is same as new(0, 0) + * + * new(obj) is same as new(obj.x.to_i, obj.y.to_i) + */ +VALUE +rb_initialize(int argc, VALUE *argv, VALUE self) +{ + VALUE obj, x, y; + switch (argc) { + case 0: + break; + case 1: + obj = argv[0]; + if(rb_compatible_q(rb_klass, obj)) { + CVSIZE(self)->width = NUM2INT(rb_funcall(rb_funcall(obj, rb_intern("width"), 0), rb_intern("to_i"), 0)); + CVSIZE(self)->height = NUM2INT(rb_funcall(rb_funcall(obj, rb_intern("height"), 0), rb_intern("to_i"), 0)); + }else{ + rb_raise(rb_eArgError, "object is not compatible %s.", rb_class2name(rb_klass)); + } + break; + case 2: + x = argv[0], y = argv[1]; + CVSIZE(self)->width = NUM2INT(x); + CVSIZE(self)->height = NUM2INT(y); + break; + default: + rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..2)", argc); + } + return Qnil; +} + +/* + * Return size of x-axis. + */ +VALUE +rb_width(VALUE self) +{ + return INT2FIX(CVSIZE(self)->width); +} + +/* + * call-seq: + * width = val + * + * Set x-axis size, return self. + * It is dropped below the decimal point. + */ +VALUE +rb_set_width(VALUE self, VALUE x) +{ + CVSIZE(self)->width = NUM2INT(x); + return self; +} + +/* + * Return size of yaxis. + */ +VALUE +rb_height(VALUE self) +{ + return INT2FIX(CVSIZE(self)->height); +} + +/* + * call-seq: + * height = val + * + * Set y-axis size, return self. + * It is dropped below the decimal point. + */ +VALUE +rb_set_height(VALUE self, VALUE y) +{ + CVSIZE(self)->height = NUM2INT(y); + return self; +} + +/* + * call-seq: + * to_s -> "" + * + * Return width and height by String. + */ +VALUE +rb_to_s(VALUE self) +{ + const int i = 4; + VALUE str[i]; + str[0] = rb_str_new2("<%s:%dx%d>"); + str[1] = rb_str_new2(rb_class2name(CLASS_OF(self))); + str[2] = rb_width(self); + str[3] = rb_height(self); + return rb_f_sprintf(i, str); +} + +/* + * call-seq: + * to_ary -> [width, height] + * + * Return width and height by Array. + */ +VALUE +rb_to_ary(VALUE self) +{ + return rb_ary_new3(2, rb_width(self), rb_height(self)); +} + +VALUE +new_object() +{ + VALUE object = rb_allocate(rb_klass); + *CVSIZE(object) = cvSize(0, 0); + return object; +} + +VALUE +new_object(CvSize size) +{ + VALUE object = rb_allocate(rb_klass); + *CVSIZE(object) = size; + return object; +} + +__NAMESPACE_END_CVSIZE +__NAMESPACE_END_OPENCV diff --git a/ext/cvsize.h b/ext/cvsize.h new file mode 100644 index 00000000..8a75afc3 --- /dev/null +++ b/ext/cvsize.h @@ -0,0 +1,63 @@ +/************************************************************ + + cvsize.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVSIZE_H +#define RUBY_OPENCV_CVSIZE_H + +#include"opencv.h" + +#define __NAMESPACE_BEGIN_CVSIZE namespace cCvSize{ +#define __NAMESPACE_END_CVSIZE } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVSIZE + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_compatible_q(VALUE klass, VALUE object); + +VALUE rb_allocate(VALUE klass); +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); +VALUE rb_width(VALUE self); +VALUE rb_set_width(VALUE self, VALUE width); +VALUE rb_height(VALUE self); +VALUE rb_set_height(VALUE self, VALUE height); + +VALUE rb_to_s(VALUE self); +VALUE rb_to_ary(VALUE self); + +VALUE new_object(); +VALUE new_object(CvSize size); + +__NAMESPACE_END_CVSIZE + +inline CvSize* +CVSIZE(VALUE object) +{ + CvSize *ptr; + Data_Get_Struct(object, CvSize, ptr); + return ptr; +} + +inline CvSize +VALUE_TO_CVSIZE(VALUE object) +{ + if(cCvSize::rb_compatible_q(cCvSize::rb_class(), object)){ + return cvSize(NUM2INT(rb_funcall(object, rb_intern("width"), 0)), + NUM2INT(rb_funcall(object, rb_intern("height"), 0))); + }else{ + rb_raise(rb_eTypeError, "require %s or compatible object.", rb_class2name(cCvSize::rb_class())); + } +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVSIZE_H diff --git a/ext/cvsize2d32f.cpp b/ext/cvsize2d32f.cpp new file mode 100644 index 00000000..85a82c98 --- /dev/null +++ b/ext/cvsize2d32f.cpp @@ -0,0 +1,180 @@ +/************************************************************ + + cvsize2d32f.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include "cvsize2d32f.h" +/* + * Document-class: OpenCV::CvSize2D32f + * + * This class means one size on X axis Y axis. + * X and Y takes the value of the Float. + * + * C structure is here, very simple. + * typdef struct CvSize2D32f{ + * float width; + * float height; + * }CvSize2D32f; + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVSIZE2D32F + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if(rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + + rb_klass = rb_define_class_under(opencv, "CvSize2D32f", rb_cObject); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_singleton_method(rb_klass, "compatible?", RUBY_METHOD_FUNC(rb_compatible_q), 1); + rb_define_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); + rb_define_method(rb_klass, "width", RUBY_METHOD_FUNC(rb_width), 0); + rb_define_method(rb_klass, "width=", RUBY_METHOD_FUNC(rb_set_width), 1); + rb_define_method(rb_klass, "height", RUBY_METHOD_FUNC(rb_height), 0); + rb_define_method(rb_klass, "height=", RUBY_METHOD_FUNC(rb_set_height), 1); +} + +/* + * call-seq: + * compatible?(obj) + * + * Return compatibility to CvSize2D32f. Return true if object have method #width and #height. + * + * For example. + * class MySize + * def width + * 10.1 + * end + * def height + * 20.2 + * end + * end + * mp = MySize.new + * CvSize2D32f.compatible?(mp) #=> true + * CvSize2D32f.new(mp) #=> same as CvSize2D32f.new(10.1, 20.2) + */ +VALUE +rb_compatible_q(VALUE klass, VALUE object) +{ + return (rb_respond_to(object, rb_intern("width")) && rb_respond_to(object, rb_intern("height"))) ? Qtrue : Qfalse; +} + +VALUE +rb_allocate(VALUE klass) +{ + CvSize2D32f *ptr; + return Data_Make_Struct(klass, CvSize2D32f, 0, -1, ptr); +} + +/* + * call-seq: + * new + * new(obj) + * new(width, height) + * + * Create new size of 2D, (width, height). + * + * new() is same as new(0.0, 0.0) + * + * new(obj) is same as new(obj.x.to_f, obj.y.to_f) + */ +VALUE +rb_initialize(int argc, VALUE *argv, VALUE self) +{ + VALUE obj, x, y; + switch(argc){ + case 0: + break; + case 1: + obj = argv[0]; + if(rb_compatible_q(rb_klass, obj)){ + CVSIZE2D32F(self)->width = NUM2DBL(rb_funcall(rb_funcall(obj, rb_intern("width"), 0), rb_intern("to_f"), 0)); + CVSIZE2D32F(self)->height = NUM2DBL(rb_funcall(rb_funcall(obj, rb_intern("height"), 0), rb_intern("to_f"), 0)); + }else{ + rb_raise(rb_eArgError, "object is not compatible %s.", rb_class2name(rb_klass)); + } + break; + case 2: + x = argv[0], y = argv[1]; + CVSIZE2D32F(self)->width = NUM2DBL(x); + CVSIZE2D32F(self)->height = NUM2DBL(y); + break; + default: + rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..2)", argc); + } + return self; +} + +/* + * Return size of x-axis. + */ +VALUE +rb_width(VALUE self) +{ + return rb_float_new(CVSIZE2D32F(self)->width); +} + +/* + * call-seq: + * width = val + * + * Set x-axis size, return self. + */ +VALUE +rb_set_width(VALUE self, VALUE x) +{ + CVSIZE2D32F(self)->width = NUM2DBL(x); + return self; +} + +/* + * Return size of yaxis. + */ +VALUE +rb_height(VALUE self) +{ + return rb_float_new(CVSIZE2D32F(self)->height); +} + +/* + * call-seq: + * height = val + * + * Set y-axis size, return self. + */ +VALUE +rb_set_height(VALUE self, VALUE y) +{ + CVSIZE2D32F(self)->height = NUM2DBL(y); + return self; +} + +VALUE +new_object(CvSize2D32f size) +{ + VALUE object = rb_allocate(rb_klass); + *CVSIZE2D32F(object) = size; + return object; +} + +__NAMESPACE_END_CVSIZE2D32F +__NAMESPACE_END_OPENCV diff --git a/ext/cvsize2d32f.h b/ext/cvsize2d32f.h new file mode 100644 index 00000000..ca038b45 --- /dev/null +++ b/ext/cvsize2d32f.h @@ -0,0 +1,59 @@ +/************************************************************ + + cvsize2d32f.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVSIZE2D32F_H +#define RUBY_OPENCV_CVSIZE2D32F_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVSIZE2D32F namespace cCvSize2D32f{ +#define __NAMESPACE_END_CVSIZE2D32F } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVSIZE2D32F + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_compatible_q(VALUE klass, VALUE object); + +VALUE rb_allocate(VALUE klass); +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); +VALUE rb_width(VALUE self); +VALUE rb_set_width(VALUE self, VALUE width); +VALUE rb_height(VALUE self); +VALUE rb_set_height(VALUE self, VALUE height); + +VALUE new_object(CvSize2D32f size); + +__NAMESPACE_END_CVSIZE2D32F + +inline CvSize2D32f* +CVSIZE2D32F(VALUE object) +{ + CvSize2D32f *ptr; + Data_Get_Struct(object, CvSize2D32f, ptr); + return ptr; +} + +inline CvSize2D32f +VALUE_TO_CVSIZE2D32F(VALUE object) +{ + if(cCvSize2D32f::rb_compatible_q(cCvSize2D32f::rb_class(), object)){ + return cvSize2D32f(NUM2DBL(rb_funcall(object, rb_intern("width"), 0)), + NUM2DBL(rb_funcall(object, rb_intern("height"), 0))); + }else{ + rb_raise(rb_eTypeError, "require %s or compatible object.", rb_class2name(cCvSize2D32f::rb_class())); + } +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVSIZE2D32F_H diff --git a/ext/cvslice.cpp b/ext/cvslice.cpp new file mode 100644 index 00000000..a6cd31b4 --- /dev/null +++ b/ext/cvslice.cpp @@ -0,0 +1,82 @@ +/************************************************************ + + cvslice.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include "cvslice.h" +/* + * Document-class: OpenCV::CvClice + * + * C structure is here, very simple. + * typdef struct CvSlice{ + * int start_index; + * int end_index; + * }CvSlice; + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVSLICE + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + rb_klass = rb_define_class_under(opencv, "CvSlice", rb_cObject); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_singleton_method(rb_klass, "compatible?", RUBY_METHOD_FUNC(rb_compatible_q), 1); + rb_define_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), 2); +} + +/* + * call-seq: + * compatible?(obj) + * + * same Object#kind_of(Range) + */ +VALUE +rb_compatible_q(VALUE klass, VALUE object) +{ + return rb_obj_is_kind_of(object, rb_cRange); +} + +VALUE +rb_allocate(VALUE klass) +{ + CvSlice *ptr; + return Data_Make_Struct(klass, CvSlice, 0, -1, ptr); +} + +/* + * call-seq: + * new(start, end) + * + * Create new slice object. + */ +VALUE +rb_initialize(VALUE self, VALUE start, VALUE end) +{ + CVSLICE(self)->start_index = NUM2INT(start); + CVSLICE(self)->end_index = NUM2INT(end); + return self; +} + +__NAMESPACE_END_CVSLICE +__NAMESPACE_END_OPENCV diff --git a/ext/cvslice.h b/ext/cvslice.h new file mode 100644 index 00000000..fd7a64b6 --- /dev/null +++ b/ext/cvslice.h @@ -0,0 +1,53 @@ +/************************************************************ + + cvslice.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVSLICE_H +#define RUBY_OPENCV_CVSLICE_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVSLICE namespace cCvSlice{ +#define __NAMESPACE_END_CVSLICE } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVSLICE + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_compatible_q(VALUE klass, VALUE object); + +VALUE rb_allocate(VALUE klass); +VALUE rb_initialize(VALUE self, VALUE start, VALUE end); + +__NAMESPACE_END_CVSLICE + +inline CvSlice* +CVSLICE(VALUE object) +{ + CvSlice *ptr; + Data_Get_Struct(object, CvSlice, ptr); + return ptr; +} + +inline CvSlice +VALUE_TO_CVSLICE(VALUE object) +{ + if(cCvSlice::rb_compatible_q(cCvSlice::rb_class(), object)){ + return cvSlice(NUM2INT(rb_funcall(object, rb_intern("begin"), 0)), + rb_funcall(object, rb_intern("exclude_end?"), 0) ? NUM2INT(rb_funcall(object, rb_intern("end"), 0)) : NUM2INT(rb_funcall(object, rb_intern("end"), 0)) - 1); + }else{ + rb_raise(rb_eTypeError, "require %s or compatible object.", rb_class2name(cCvSlice::rb_class())); + } +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVSLICE_H diff --git a/ext/cvsparsemat.cpp b/ext/cvsparsemat.cpp new file mode 100644 index 00000000..5b9ab0f2 --- /dev/null +++ b/ext/cvsparsemat.cpp @@ -0,0 +1,44 @@ +/*********************************************************** + + cvsparse.cpp - + + $Author: lsxi $ + + Copyright (C) 2007 Masakazu Yonekura + +************************************************************/ +#include "cvsparsemat.h" +/* + * Document-class: OpenCV::CvSparseMat + * + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVSPARSEMAT + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * cvmat = rb_define_class_under(opencv, "CvMat", rb_cObject); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(), cvmat = cCvMat::rb_class(); + + rb_klass = rb_define_class_under(opencv, "CvSparseMat", cvmat); +} + +__NAMESPACE_END_CVSPARSEMAT +__NAMESPACE_END_OPENCV + diff --git a/ext/cvsparsemat.h b/ext/cvsparsemat.h new file mode 100644 index 00000000..21338e68 --- /dev/null +++ b/ext/cvsparsemat.h @@ -0,0 +1,28 @@ +/************************************************************ + + cvsparsemat.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVSPARSEMAT_H +#define RUBY_OPENCV_CVSPARSEMAT_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVSPARSEMAT namespace cCvSparseMat{ +#define __NAMESPACE_END_CVSPARSEMAT } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVSPARSEMAT + +VALUE rb_class(); + +void define_ruby_class(); + +__NAMESPACE_END_CVSPARSEMAT +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVSPARSEMAT_H diff --git a/ext/cvtermcriteria.cpp b/ext/cvtermcriteria.cpp new file mode 100644 index 00000000..af6ffc81 --- /dev/null +++ b/ext/cvtermcriteria.cpp @@ -0,0 +1,183 @@ +/************************************************************ + + cvtermcriteria.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include"cvtermcriteria.h" +/* + * Document-class: OpenCV::CvTermCriteria + * + * CvTermCriteria has parameter "max" and "eps". + * "max" is the maximum repetition frequency. + * "eps" is a minimum difference value during current and previous state + * (It is different to which state "eps" refer depending on the method). + * + * Because the name of CvTermCriteria seems to be very long, it has alias named CvTerm. + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVTERMCRITERIA + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + + rb_klass = rb_define_class_under(opencv, "CvTermCriteria", rb_cObject); + /* CvTermCriteria: class */ + rb_define_const(opencv, "CvTerm", rb_klass); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); + rb_define_method(rb_klass, "max", RUBY_METHOD_FUNC(rb_max), 0); + rb_define_method(rb_klass, "max=", RUBY_METHOD_FUNC(rb_set_max), 1); + rb_define_method(rb_klass, "eps", RUBY_METHOD_FUNC(rb_eps), 0); + rb_define_method(rb_klass, "eps=", RUBY_METHOD_FUNC(rb_set_eps), 1); + rb_define_alias(rb_klass, "epsilon", "eps"); + rb_define_alias(rb_klass, "epsilon=", "eps="); + rb_define_method(rb_klass, "to_ary", RUBY_METHOD_FUNC(rb_to_ary), 0); +} + +VALUE +rb_allocate(VALUE klass) +{ + CvTermCriteria *ptr; + return Data_Make_Struct(klass, CvTermCriteria, 0, -1, ptr); +} + +/* + * call-seq: + * CvTermCriteria.new([max = 0][,eps = 0.0]) -> obj + * CvTermCriteria.new(int) = CvTermCriteria.new(int, 0.0) + * CvTermCriteria.new(float) = CvTermCriteria.new(0, float) + * + * Create new term criteria. + */ +VALUE +rb_initialize(int argc, VALUE *argv, VALUE self) +{ + VALUE max, eps; + rb_scan_args(argc, argv, "02", &max, &eps); + int type = 0; + if (!NIL_P(max)) {type |= CV_TERMCRIT_ITER;} + if (!NIL_P(eps)) {type |= CV_TERMCRIT_EPS;} + *CVTERMCRITERIA(self) = cvTermCriteria(type, IF_INT(max, 0), IF_DBL(eps, 0.0)); + return self; +} + +/* + * call-seq: + * max -> int or nil + * + * Return the maximum repetition frequency. + */ +VALUE +rb_max(VALUE self) +{ + CvTermCriteria *ptr = CVTERMCRITERIA(self); + if (ptr->type & CV_TERMCRIT_ITER) + return INT2NUM(ptr->max_iter); + else + return Qnil; +} + +/* + * call-seq: + * max = val -> self + * + * Set the maximum repetition frequency. + * If val is 0 (or negative value), repetition frequency is disregarded. + */ +VALUE +rb_set_max(VALUE self, VALUE max_value) +{ + CvTermCriteria *ptr = CVTERMCRITERIA(self); + int max = NUM2INT(max_value); + if (max > 0) { + ptr->type |= CV_TERMCRIT_ITER; + ptr->max_iter = max; + } else { + ptr->type ^= CV_TERMCRIT_ITER; + ptr->max_iter = 0; + } + return self; +} + +/* + * call-seq: + * eps -> float or nil + * + * Return the minimum difference value during current and previous state. + */ +VALUE +rb_eps(VALUE self) +{ + CvTermCriteria *ptr = CVTERMCRITERIA(self); + if(ptr->type & CV_TERMCRIT_EPS) + return rb_float_new(ptr->epsilon); + else + return Qnil; +} + +/* + * call-seq: + * eps = val -> self + * + * Set the minimum difference value during current and previous state. + * If val is 0.0 (or negative value), the minimum difference value + * during current and previous state is disregarded. + */ +VALUE +rb_set_eps(VALUE self, VALUE eps_value) +{ + CvTermCriteria *ptr = CVTERMCRITERIA(self); + double eps = NUM2DBL(eps_value); + if (eps > 0) { + ptr->type = ptr->type | CV_TERMCRIT_EPS; + ptr->epsilon = eps; + } else { + ptr->type = ptr->type ^ CV_TERMCRIT_EPS; + ptr->epsilon = 0; + } + return self; +} + +VALUE +rb_to_ary(VALUE self) +{ + CvTermCriteria *ptr = CVTERMCRITERIA(self); + VALUE ary = rb_ary_new(); + if (ptr->type & CV_TERMCRIT_ITER) + rb_ary_push(ary, INT2FIX(ptr->max_iter)); + if (ptr->type & CV_TERMCRIT_EPS) + rb_ary_push(ary, rb_float_new(ptr->epsilon)); + return ary; +} + +VALUE +new_object(CvTermCriteria criteria) +{ + VALUE object = rb_allocate(rb_klass); + *CVTERMCRITERIA(object) = criteria; + return object; +} + +__NAMESPACE_END_CVTERMCRITERIA +__NAMESPACE_END_OPENCV diff --git a/ext/cvtermcriteria.h b/ext/cvtermcriteria.h new file mode 100644 index 00000000..16415ce1 --- /dev/null +++ b/ext/cvtermcriteria.h @@ -0,0 +1,71 @@ +/************************************************************ + + cvtermcriteria.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVTERMCRITERIA_H +#define RUBY_OPENCV_CVTERMCRITERIA_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVTERMCRITERIA namespace cCvTermCriteria{ +#define __NAMESPACE_END_CVTERMCRITERIA } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVTERMCRITERIA + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_allocate(VALUE klass); +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); + +VALUE rb_max(VALUE self); +VALUE rb_set_max(VALUE self, VALUE max_value); +VALUE rb_eps(VALUE self); +VALUE rb_set_eps(VALUE self, VALUE eps_value); +VALUE rb_to_ary(VALUE self); + +VALUE new_object(CvTermCriteria criteria); + +__NAMESPACE_END_CVTERMCRITERIA + +inline CvTermCriteria* +CVTERMCRITERIA(VALUE object) +{ + CvTermCriteria *ptr; + Data_Get_Struct(object, CvTermCriteria, ptr); + return ptr; +} + +inline CvTermCriteria +VALUE_TO_CVTERMCRITERIA(VALUE object) +{ + if (rb_obj_is_kind_of(object, cCvTermCriteria::rb_class())) { + return *CVTERMCRITERIA(object); + } + switch (TYPE(object)) { + case T_NIL: + return cvTermCriteria(CV_TERMCRIT_ITER, 0, 0); + case T_FIXNUM: + return cvTermCriteria(CV_TERMCRIT_ITER, NUM2INT(object), 0); + case T_FLOAT: + return cvTermCriteria(CV_TERMCRIT_EPS, 0, NUM2DBL(object)); + case T_ARRAY: + if (RARRAY(object)->len == 2) { + return cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, + NUM2INT(rb_ary_entry(object, 0)), + NUM2DBL(rb_ary_entry(object, 1))); + } + } + rb_raise(rb_eTypeError, ""); +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVTERMCRITERIA_H diff --git a/ext/cvtwopoints.cpp b/ext/cvtwopoints.cpp new file mode 100644 index 00000000..f03fd686 --- /dev/null +++ b/ext/cvtwopoints.cpp @@ -0,0 +1,98 @@ +/************************************************************ + + cvtwopoints.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include "cvtwopoints.h" +/* + * Document-class: OpenCV::CvTwopoints + * + * This class means one twopoints on X axis Y axis. + * X and Y takes the value of the Fixnum. see also CvTwopoints2D32F + * + * C structure is here, very simple. + * typdef struct CvTwopoints{ + * int x; + * int y; + * } + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVTWOPOINTS + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + + rb_klass = rb_define_class_under(opencv, "CvTwoPoints", rb_cObject); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_method(rb_klass, "point1", RUBY_METHOD_FUNC(rb_point1), 0); + rb_define_method(rb_klass, "point2", RUBY_METHOD_FUNC(rb_point2), 0); + rb_define_method(rb_klass, "to_ary", RUBY_METHOD_FUNC(rb_to_ary), 0); +} + +VALUE +rb_allocate(VALUE klass) +{ + CvTwoPoints *ptr; + return Data_Make_Struct(klass, CvTwoPoints, 0, -1, ptr); +} + +VALUE +rb_cvseqblock(VALUE self) +{ + return Qnil; +} + + +/* + * Return point 1. + */ +VALUE +rb_point1(VALUE self) +{ + return cCvPoint::new_object(CVTWOPOINTS(self)->p1); +} + +/* + * Return point2. + */ +VALUE +rb_point2(VALUE self) +{ + return cCvPoint::new_object(CVTWOPOINTS(self)->p2); +} + +/* + * call-seq: + * to_ary -> [self.point1, self.point2] + * + * Return 2 point by Array. + */ +VALUE +rb_to_ary(VALUE self) +{ + return rb_ary_new3(2, rb_point1(self), rb_point2(self)); +} + +__NAMESPACE_END_CVTWOPOINTS +__NAMESPACE_END_OPENCV diff --git a/ext/cvtwopoints.h b/ext/cvtwopoints.h new file mode 100644 index 00000000..dc28a94b --- /dev/null +++ b/ext/cvtwopoints.h @@ -0,0 +1,50 @@ +/************************************************************ + + cvtwopoints.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVTWOPOINTS_H +#define RUBY_OPENCV_CVTWOPOINTS_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVTWOPOINTS namespace cCvTwoPoints{ +#define __NAMESPACE_END_CVTWOPOINTS } + +__NAMESPACE_BEGIN_OPENCV + +typedef struct CvTwoPoints{ + CvPoint p1; + CvPoint p2; +} CvTwoPoints; + +__NAMESPACE_BEGIN_CVTWOPOINTS + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_allocate(VALUE klass); + +VALUE rb_point1(VALUE self); +VALUE rb_point2(VALUE self); +VALUE rb_to_ary(VALUE self); + +VALUE new_object(CvTwoPoints twopoints); + +__NAMESPACE_END_CVTWOPOINTS + +inline CvTwoPoints* +CVTWOPOINTS(VALUE object){ + CvTwoPoints *ptr; + Data_Get_Struct(object, CvTwoPoints, ptr); + return ptr; +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVTWOPOINTS_H diff --git a/ext/cvvector.cpp b/ext/cvvector.cpp new file mode 100644 index 00000000..e1760dff --- /dev/null +++ b/ext/cvvector.cpp @@ -0,0 +1,206 @@ +/************************************************************ + + cvvector.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include "cvvector.h" +/* + * Document-class: OpenCV::CvVector + * + * 2D vector (X axis and Y axis) + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVVECTOR + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + + rb_klass = rb_define_class_under(opencv, "CvVector", rb_cObject); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_singleton_method(rb_klass, "compatible?", RUBY_METHOD_FUNC(rb_compatible_q), 1); + rb_define_private_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); + rb_define_method(rb_klass, "x", RUBY_METHOD_FUNC(rb_x), 0); + rb_define_method(rb_klass, "x=", RUBY_METHOD_FUNC(rb_set_x), 1); + rb_define_method(rb_klass, "y", RUBY_METHOD_FUNC(rb_y), 0); + rb_define_method(rb_klass, "y=", RUBY_METHOD_FUNC(rb_set_y), 1); + + rb_define_method(rb_klass, "to_s", RUBY_METHOD_FUNC(rb_to_s), 0); + rb_define_method(rb_klass, "to_ary", RUBY_METHOD_FUNC(rb_to_ary), 0); +} + +/* + * call-seq: + * combatible?(obj) + * + * Return compatibility to CvVector. Return true if object have method #x and #y. + * + * For example. + * class MyVector + * def x + * 1.0 + * end + * def y + * 2.0 + * end + * end + * mv = MyVector.new + * CvVector.compatible?(mv) #=> true + * CvVector.new(mv) #=> same as CvVector(1.0, 2.0) + */ +VALUE +rb_compatible_q(VALUE klass, VALUE object) +{ + return (rb_respond_to(object, rb_intern("x")) && rb_respond_to(object, rb_intern("y"))) ? Qtrue : Qfalse; +} + +VALUE +rb_allocate(VALUE klass) +{ + CvVector *ptr; + return Data_Make_Struct(klass, CvVector, 0, -1, ptr); +} + +/* + * call-seq: + * new -> CvVector.new(0.0, 0.0) + * new(obj) -> CvVector.new(obj.x.to_f, obj.y.to_f) + * new(x, y) + * + * Create new 2D-vector, (x, y). + * + * new() is same as new(0, 0) + * + * new(obj) is same as new(obj.x.to_f, obj.y.to_f) + */ +VALUE +rb_initialize(int argc, VALUE *argv, VALUE self) +{ + VALUE obj, x, y; + switch (argc) { + case 0: + break; + case 1: + obj = argv[0]; + if (rb_compatible_q(rb_klass, obj)) { + CVVECTOR(self)->x = NUM2INT(rb_funcall(rb_funcall(obj, rb_intern("x"), 0), rb_intern("to_i"), 0)); + CVVECTOR(self)->y = NUM2INT(rb_funcall(rb_funcall(obj, rb_intern("y"), 0), rb_intern("to_i"), 0)); + }else{ + rb_raise(rb_eArgError, "object is not compatible %s.", rb_class2name(rb_klass)); + } + break; + case 2: + x = argv[0], y = argv[1]; + CVVECTOR(self)->x = NUM2INT(x); + CVVECTOR(self)->y = NUM2INT(y); + break; + default: + rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..2)", argc); + } + return Qnil; +} + +/* + * Return parameter on vector of x-axis. + */ +VALUE +rb_x(VALUE self) +{ + return INT2FIX(CVVECTOR(self)->x); +} + +/* + * call-seq: + * x = val + * + * Set vector of x-axis, return self. + */ +VALUE +rb_set_x(VALUE self, VALUE x) +{ + CVVECTOR(self)->x = NUM2INT(x); + return self; +} + +/* + * Return parameter on vector of y-axis. + */ +VALUE +rb_y(VALUE self) +{ + return INT2FIX(CVVECTOR(self)->y); +} + +/* + * call-seq: + * y = val + * + * Set vector of y-axis, return self. + */ +VALUE +rb_set_y(VALUE self, VALUE y) +{ + CVVECTOR(self)->y = NUM2INT(y); + return self; +} + +/* + * call-seq: + * to_s -> "" + * + * Return x and y by String. + */ +VALUE +rb_to_s(VALUE self) +{ + const int i = 4; + VALUE str[i]; + str[0] = rb_str_new2("<%s:(%d,%d)>"); + str[1] = rb_str_new2(rb_class2name(CLASS_OF(self))); + str[2] = rb_x(self); + str[3] = rb_y(self); + return rb_f_sprintf(i, str); +} + +/* + * call-seq: + * to_ary -> [x, y] + * + * Return x and y by Array. + */ +VALUE +rb_to_ary(VALUE self) +{ + return rb_ary_new3(2, rb_x(self), rb_y(self)); +} + +VALUE +new_object(CvVector point) +{ + VALUE object = rb_allocate(rb_klass); + *CVVECTOR(object) = point; + return object; +} + +__NAMESPACE_END_CVVECTOR +__NAMESPACE_END_OPENCV diff --git a/ext/cvvector.h b/ext/cvvector.h new file mode 100644 index 00000000..f2c51b29 --- /dev/null +++ b/ext/cvvector.h @@ -0,0 +1,54 @@ +/************************************************************ + + cvvector.h - + + $Author: lsxi $ + + Copyright (C) 2007 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVVECTOR_H +#define RUBY_OPENCV_CVVECTOR_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVVECTOR namespace cCvVector{ +#define __NAMESPACE_END_CVVECTOR } + +typedef struct CvVector{ + float x; + float y; +} CvVector; + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVVECTOR + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_compatible_q(VALUE klass, VALUE object); + +VALUE rb_allocate(VALUE klass); +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); +VALUE rb_x(VALUE self); +VALUE rb_set_x(VALUE self, VALUE x); +VALUE rb_y(VALUE self); +VALUE rb_set_y(VALUE self, VALUE y); + +VALUE rb_to_s(VALUE self); +VALUE rb_to_ary(VALUE self); + +VALUE new_object(CvVector vector); + +__NAMESPACE_END_CVVECTOR + +inline CvVector *CVVECTOR(VALUE object){ + CvVector *ptr; + Data_Get_Struct(object, CvVector, ptr); + return ptr; +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVVECTOR_H diff --git a/ext/cvvideowriter.cpp b/ext/cvvideowriter.cpp new file mode 100644 index 00000000..dad0df16 --- /dev/null +++ b/ext/cvvideowriter.cpp @@ -0,0 +1,116 @@ +/************************************************************ + + cvvideowriter.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include "cvvideowriter.h" +/* + * Document-class: OpenCV::CvVideoWriter + * + * Create video stream from images. + * + * C structure is "black box". + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVVIDEOWRITER + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if(rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + rb_klass = rb_define_class_under(opencv, "CvVideoWriter", rb_cObject); + rb_define_private_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); + rb_define_method(rb_klass, "write", RUBY_METHOD_FUNC(rb_write), 1); + rb_define_method(rb_klass, "close", RUBY_METHOD_FUNC(rb_close), 0); +} + +/* + * call-seq: + * CvVideoWriter.new(filanem, fourcc, fps, size) -> cvvideowriter + * CvVideoWriter.new(filanem, fourcc, fps, size){|vw| ... } -> nil + * + * Open new video writer. If block given, writer is closed automatically when end of block. + * + * note: if fourcc is nil, popup codec select dialog (Windows only). + */ +VALUE +rb_initialize(int argc, VALUE *argv, VALUE self) +{ + VALUE filename, fourcc, fps, size; + rb_scan_args(argc, argv, "40", &filename, &fourcc, &fps, &size); + char codec[4] = {' ', ' ', ' ', ' '}; + int codec_number; + Check_Type(filename, T_STRING); + if (RSTRING(filename)->len == 0) + rb_raise(rb_eArgError, "argument 1 (file name) dose not given"); + if (NIL_P(fourcc)) + codec_number = -1; + else { + Check_Type(fourcc, T_STRING); + if (RSTRING(fourcc)->len > 4) + rb_raise(rb_eStandardError, "argument 2 (fourcc) should be specific 4-character. (i.e \"PIM1\",\"MJPG\")"); + else { + for (int i = 0; i < RSTRING(fourcc)->len; i++) + codec[i] = RSTRING(fourcc)->ptr[i]; + codec_number = CV_FOURCC(codec[0], codec[1], codec[2], codec[3]); + } + } + DATA_PTR(self) = cvCreateVideoWriter(StringValueCStr(filename), codec_number, FIX2INT(fps), VALUE_TO_CVSIZE(size)); + if (rb_block_given_p()) { + rb_yield(self); + rb_close(self); + return Qnil; + } else { + return self; + } +} + +/* + * call-seq: + * write(frame) + * + * Write image as frame of video stream. + * frame should be CvMat or subclass. + */ +VALUE +rb_write(VALUE self, VALUE frame) +{ + if (!rb_obj_is_kind_of(frame, cCvMat::rb_class())) + rb_raise(rb_eTypeError, "argument 1 (frame) should be %s or subclass", rb_class2name(cCvMat::rb_class())); + cvWriteFrame(CVVIDEOWRITER(self), IPLIMAGE(frame)); + return self; +} + +/* + * Close vidoe writer. + */ +VALUE +rb_close(VALUE self) +{ + CvVideoWriter *writer = CVVIDEOWRITER(self); + cvReleaseVideoWriter(&writer); + return Qnil; +} + + +__NAMESPACE_END_CVVIDEOWRITER +__NAMESPACE_END_OPENCV diff --git a/ext/cvvideowriter.h b/ext/cvvideowriter.h new file mode 100644 index 00000000..0f0a788f --- /dev/null +++ b/ext/cvvideowriter.h @@ -0,0 +1,41 @@ +/************************************************************ + + cvvideowriter.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_CVVIDEOWRITER_H +#define RUBY_OPENCV_CVVIDEOWRITER_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_CVVIDEOWRITER namespace cCvVideoWriter{ +#define __NAMESPACE_END_CVVIDEOWRITER } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_CVVIDEOWRITER + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); +VALUE rb_write(VALUE self, VALUE frame); +VALUE rb_close(VALUE self); + +__NAMESPACE_END_CVVIDEOWRITER + +inline CvVideoWriter* +CVVIDEOWRITER(VALUE object) +{ + CvVideoWriter *ptr; + Data_Get_Struct(object, CvVideoWriter, ptr); + return ptr; +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_CVVIDEOWRITER_H diff --git a/ext/extconf.rb b/ext/extconf.rb new file mode 100755 index 00000000..4ba4e632 --- /dev/null +++ b/ext/extconf.rb @@ -0,0 +1,61 @@ +#!/usr/env ruby +#/usr/local/bin/ruby +=begin +create Makefile script for Ruby/OpenCV + +usage : ruby extconf.rb + make && make install + +VC : ruby extconf.rb + nmake +=end +require "mkmf" + +# option "opencv" +# extconf.rb --with-opencv-lib=/path/to/opencv/lib +# extconf.rb --with-opencv-include=/path/to/opencv/include + +dir_config("opencv", "/usr/local/include/opencv", "/usr/local/lib") +dir_config("ffcall", "/usr/local/include", "/usr/local/lib") + +opencv_libraries = ["cxcore", "cv", "highgui"] + +puts ">> check require libraries..." +case CONFIG["arch"] +when /mswin32/ + have_library("msvcrt", nil) + opencv_libraries.each{|lib| + have_library(lib) + } +else + opencv_libraries.each{|lib| + raise "lib#{lib} not found." unless have_library(lib) + } + #have_library("ml") + have_library("stdc++") +end + +# check require headers +puts ">> check require headers..." +opencv_libraries.map{|lib| "#{lib}.h"}.each{|header| + raise "#{header} not found." unless have_header(header) +} +#have_header("ml.h") +have_header("stdarg.h") + +# check require functions. +# todo + +# optional libraies check. +puts ">> ----- optional -----" +puts ">> check ffcall..." +# check ffcall +if have_library("callback") && have_header("callback.h") + puts ">> support OpenCV::GUI" +else + puts ">> ! unsupport OpenCV::GUI (if need it. install ffcall)" + puts "http://www.haible.de/bruno/packages-ffcall.html" +end + +# step-final. create Makefile +create_makefile("opencv") diff --git a/ext/gui.cpp b/ext/gui.cpp new file mode 100644 index 00000000..5845c700 --- /dev/null +++ b/ext/gui.cpp @@ -0,0 +1,65 @@ +/************************************************************ + + gui.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifdef HAVE_CALLBACK_H + +#include "gui.h" +/* + * Document-module: OpenCV::GUI + * + * OpenCV simple GUI interface. Provides Window, Trackbar. + * This GUI work on GTK or Microsoft Windows native GUI. + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_GUI + +VALUE rb_module; + +VALUE +rb_module_GUI() +{ + return rb_module; +} + +void +define_ruby_module() +{ + if(rb_module) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + rb_module = rb_define_module_under(opencv, "GUI"); + rb_define_singleton_method(rb_module, "wait_key", RUBY_METHOD_FUNC(rb_wait_key), -1); +} + +/* + * call-seq: + * wait_key([delay]) -> int or nil + * + * Waits for a pressed key each GUI wedget. + * Return the code of the pressed key or nil if no key were pressed until the specified timeout has elapsed. + * delay should be Fixnum. Wait delay millisecond. + */ +VALUE +rb_wait_key(int argc, VALUE *argv, VALUE self) +{ + VALUE delay; + rb_scan_args(argc, argv, "01", &delay); + int keycode = 0; + return ((keycode = cvWaitKey(IF_INT(delay, 0))) < 0) ? Qnil : INT2FIX(keycode); +} + +__NAMESPACE_END_GUI +__NAMESPACE_END_OPENCV + +#endif // HAVE_CALLBACK_H diff --git a/ext/gui.h b/ext/gui.h new file mode 100644 index 00000000..e4924aaf --- /dev/null +++ b/ext/gui.h @@ -0,0 +1,33 @@ +/************************************************************ + + gui.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifdef HAVE_CALLBACK_H + +#define __NAMESPACE_BEGIN_GUI namespace mGUI{ +#define __NAMESPACE_END_GUI } + +#ifndef RUBY_OPENCV_GUI_H +#define RUBY_OPENCV_GUI_H + +#include "opencv.h" + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_GUI + +VALUE rb_module_GUI(); +void define_ruby_module(); + +VALUE rb_wait_key(int argc, VALUE *argv, VALUE self); + +__NAMESPACE_END_GUI +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_GUI_H + +#endif // HAVE_CALLBACK_H diff --git a/ext/iplconvkernel.cpp b/ext/iplconvkernel.cpp new file mode 100644 index 00000000..b0a10547 --- /dev/null +++ b/ext/iplconvkernel.cpp @@ -0,0 +1,177 @@ +/************************************************************ + + iplconvkernel.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include"iplconvkernel.h" +/* + * Document-class: OpenCV::IplConvKernel + * + * Structuring element can be used in the morphological operations. + * + * CvMat#erode, CvMat#dilate, CvMat#morphology_open, CvMat#morphology_close, + * CvMat#morphology_gradient, CvMat#morphology_tophat, CvMat#morphology_blackhat + * + * Create by IplConvKernel.new or CvMat#to_IplConvKernel + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_IPLCONVKERNEL + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + rb_klass = rb_define_class_under(opencv, "IplConvKernel", rb_cObject); + rb_define_alloc_func(rb_klass, rb_allocate); + + rb_define_private_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); + rb_define_method(rb_klass, "size", RUBY_METHOD_FUNC(rb_size), 0); + rb_define_method(rb_klass, "cols", RUBY_METHOD_FUNC(rb_cols), 0); + rb_define_alias(rb_klass, "columns", "cols"); + rb_define_method(rb_klass, "rows", RUBY_METHOD_FUNC(rb_rows), 0); + rb_define_method(rb_klass, "anchor", RUBY_METHOD_FUNC(rb_anchor), 0); + rb_define_method(rb_klass, "anchor_x", RUBY_METHOD_FUNC(rb_anchor_x), 0); + rb_define_method(rb_klass, "anchor_y", RUBY_METHOD_FUNC(rb_anchor_y), 0); +} + +VALUE +rb_allocate(VALUE klass) +{ + return OPENCV_OBJECT(klass, 0); +} + +/* + * call-seq: + * IplConvKernel.new(shape, rows, cols, anchor_x, anchor_y) + * + * Creates structuring element. + * shape + * Shape of the structuring element; may have the following values: + * :rect + * :cross + * :ellipse + * cols + * Number of columns in the structuring element. + * rows + * Number of rows in the structuring element. + * anchor_x + * Relative horizontal offset of the anchor point. + * anchor_y + * Relative vertical offset of the anchor point. + * + */ +VALUE +rb_initialize(int argc, VALUE *argv, VALUE self) +{ + VALUE shape, rows, cols, anchor_x, anchor_y; + rb_scan_args(argc, argv, "50", &shape, &rows, &cols, &anchor_x, &anchor_y); + Check_Type(shape, T_SYMBOL); + const char *shape_name = rb_id2name(SYM2ID(shape)); + int shape_type = 0; + if (!strcmp(shape_name, "rect")) + shape_type = CV_SHAPE_RECT; + else if (!strcmp(shape_name, "corss")) + shape_type = CV_SHAPE_CROSS; + else if (!strcmp(shape_name, "ellipse")) + shape_type = CV_SHAPE_ELLIPSE; + else + rb_raise(rb_eTypeError, "argument 1 (shape) should be :rect or :cross or :ellipse."); + DATA_PTR(self) = cvCreateStructuringElementEx(NUM2INT(cols), NUM2INT(rows), NUM2INT(anchor_x), NUM2INT(anchor_y), shape_type); + return self; +} + +/* + * call-seq: + * size -> cvsize + * + * Return the structuring element's size. + */ +VALUE +rb_size(VALUE self) +{ + IplConvKernel *kernel = IPLCONVKERNEL(self); + return cCvSize::new_object(cvSize(kernel->nCols, kernel->nRows)); +} + +/* + * call-seq: + * cols -> int + * + * Return number of columns in the structuring element. + */ +VALUE +rb_cols(VALUE self) +{ + return INT2NUM(IPLCONVKERNEL(self)->nCols); +} + +/* + * call-seq: + * rows -> int + * + * Return number of rows in the structuring element. + */ +VALUE +rb_rows(VALUE self) +{ + return INT2NUM(IPLCONVKERNEL(self)->nRows); +} + +/* + * call-seq: + * anchor -> cvpoint + * + * Return anchor of the structuring element. + */ +VALUE +rb_anchor(VALUE self) +{ + IplConvKernel *kernel = IPLCONVKERNEL(self); + return cCvPoint::new_object(cvPoint(kernel->anchorX, kernel->anchorY)); +} + +/* + * call-seq: + * anchor_x -> int + * + * Return relative horizontal offset of the anchor point. + */ +VALUE +rb_anchor_x(VALUE self) +{ + return INT2NUM(IPLCONVKERNEL(self)->anchorX); +} + +/* + * call-seq: + * anchor_y -> int + * + * Return relative vertical offset of the anchor point. + */ +VALUE +rb_anchor_y(VALUE self) +{ + return INT2NUM(IPLCONVKERNEL(self)->anchorY); +} + +__NAMESPACE_END_IPLCONVKERNEL +__NAMESPACE_END_OPENCV diff --git a/ext/iplconvkernel.h b/ext/iplconvkernel.h new file mode 100644 index 00000000..d39e2595 --- /dev/null +++ b/ext/iplconvkernel.h @@ -0,0 +1,52 @@ +/************************************************************ + + iplconvkernel.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_IPLCONVKERNEL_H +#define RUBY_OPENCV_IPLCONVKERNEL_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_IPLCONVKERNEL namespace cIplConvKernel{ +#define __NAMESPACE_END_IPLCONVKERNEL } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_IPLCONVKERNEL + +VALUE rb_class(); +VALUE rb_allocate(VALUE klass); + +void define_ruby_class(); +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); +VALUE rb_size(VALUE self); +VALUE rb_cols(VALUE self); +VALUE rb_rows(VALUE self); +VALUE rb_anchor(VALUE self); +VALUE rb_anchor_x(VALUE self); +VALUE rb_anchor_y(VALUE self); + +__NAMESPACE_END_IPLCONVKERNEL + +inline IplConvKernel* +IPLCONVKERNEL(VALUE object) +{ + IplConvKernel *ptr; + if (NIL_P(object)) + return NULL; + else if (rb_obj_is_kind_of(object, cIplConvKernel::rb_class())) { + Data_Get_Struct(object, IplConvKernel, ptr); + return ptr; + } else { + rb_warn("invalid kernel. use default kernel (3x3 rectangle)."); + return NULL; + } +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_IPLCONVKERNEL_H diff --git a/ext/iplimage.cpp b/ext/iplimage.cpp new file mode 100644 index 00000000..a109576f --- /dev/null +++ b/ext/iplimage.cpp @@ -0,0 +1,238 @@ +/************************************************************ + + iplimage.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include "iplimage.h" +/* + * Document-class: OpenCV::IplImage + * + * IPL(Intel Image Processing Library) Image class. + * + * IplImage is subclass of CvMat. IplImage support ROI(region of interest) and COI(color of interest). + * Most of CvMat method support ROI, and some of CvMat method support COI. + * + * =What is ROI? + * region of interest. + * + * =What is COI? + * color of interest. + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_IPLIMAGE + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * cvmat = rb_define_class_under(opencv, "CvMat", rb_cObject); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + VALUE cvmat = cCvMat::rb_class(); + rb_klass = rb_define_class_under(opencv, "IplImage", cvmat); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_singleton_method(rb_klass, "load", RUBY_METHOD_FUNC(rb_load_image), -1); + rb_define_private_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); + rb_define_method(rb_klass, "get_roi", RUBY_METHOD_FUNC(rb_get_roi), 0); + rb_define_alias(rb_klass, "roi", "get_roi"); + rb_define_method(rb_klass, "set_roi", RUBY_METHOD_FUNC(rb_set_roi), 1); + rb_define_alias(rb_klass, "roi=", "set_roi"); + rb_define_method(rb_klass, "reset_roi", RUBY_METHOD_FUNC(rb_reset_roi), 0); + rb_define_method(rb_klass, "get_coi", RUBY_METHOD_FUNC(rb_get_coi), 0); + rb_define_alias(rb_klass, "coi", "get_coi"); + rb_define_method(rb_klass, "set_coi", RUBY_METHOD_FUNC(rb_set_coi), 1); + rb_define_alias(rb_klass, "coi=", "set_coi"); + rb_define_method(rb_klass, "reset_coi", RUBY_METHOD_FUNC(rb_reset_coi), 0); +} + +VALUE +rb_allocate(VALUE klass) +{ + return OPENCV_OBJECT(rb_klass, 0); +} + +/* + * call-seq: + * new(width, height[, depth = CV_8U][, channel = 3]) + * + * Create width * height image. Each element-value set 0. + * + * Each element possigle range is set by depth. Default is unsigned 8bit. + * + * Number of channel is set by channel. channel should be 1..4. + * + * note: width = col, height = row, on CvMat. It is noted not to make a mistake + * because the order of arguument is differenct to CvMat. + */ +VALUE +rb_initialize(int argc, VALUE *argv, VALUE self) +{ + VALUE width, height, depth, channel; + rb_scan_args(argc, argv, "22", &width, &height, &depth, &channel); + int _depth = argc < 3 ? CV_8U : FIX2INT(depth); + int _channel = argc < 4 ? 3 : FIX2INT(channel); + DATA_PTR(self) = cvCreateImage(cvSize(FIX2INT(width), FIX2INT(height)), cvCvToIplDepth(_depth), _channel); + return self; +} + +/* + * call-seq: + * IplImage::load(filename[,iscolor = nil]) + * + * Load an image from file. + * iscolor = true, the loaded image is forced to be color 3-channel image. + * iscolor = false, the loaded image is forced to be grayscale. + * iscolor = nil, the loaded image will be loaded as is (depend on the file). + * Currently the following file format are supported. + * * Windows bitmaps - BMP,DIB + * * JPEG files - JPEG,JPG,JPE + * * Portable Network Graphics - PNG + * * Portable image format - PBM,PGM,PPM + * * Sun rasters - SR,RAS + * * TIFF files - TIFF,TIF + */ +VALUE +rb_load_image(int argc, VALUE *argv, VALUE self) +{ + VALUE filename, iscolor; + rb_scan_args(argc, argv, "11", &filename, &iscolor); + Check_Type(filename, T_STRING); + int _iscolor; + switch (TYPE(iscolor)) { + case T_FALSE: + _iscolor = 0; + break; + case T_TRUE: + _iscolor = 1; + break; + case T_NIL: + _iscolor = -1; + break; + default: + rb_warn("argument 2 should be true(color)/false(non-color) or nil(auto)."); + _iscolor = -1; + } + IplImage *image; + if ((image = cvLoadImage(StringValueCStr(filename), _iscolor)) == NULL) { + rb_raise(rb_eStandardError, "file does not exist or invalid format image."); + } + return OPENCV_OBJECT(rb_klass, image); +} + +/* + * Get ROI as CvRect. + */ +VALUE +rb_get_roi(VALUE self) +{ + return cCvRect::new_object(cvGetImageROI(IPLIMAGE(self))); +} + +/* + * call-seq: + * set_roi(rect) + * set_roi(rect){|image| ...} + * + * Set ROI. rect should be CvRect or compatible object. + * Return self. + */ +VALUE +rb_set_roi(VALUE self, VALUE roi) +{ + VALUE block = rb_block_given_p() ? rb_block_proc() : 0; + if (block) { + CvRect prev_roi = cvGetImageROI(IPLIMAGE(self)); + cvSetImageROI(IPLIMAGE(self), VALUE_TO_CVRECT(roi)); + rb_yield_values(1, self); + cvSetImageROI(IPLIMAGE(self), prev_roi); + } else { + cvSetImageROI(IPLIMAGE(self), VALUE_TO_CVRECT(roi)); + } + return self; +} + + +/* + * Reset ROI setting. Same as IplImage#roi = nil. Return self. + */ +VALUE +rb_reset_roi(VALUE self) +{ + cvResetImageROI(IPLIMAGE(self)); + return self; +} + +/* + * Return COI as Fixnum. + */ +VALUE +rb_get_coi(VALUE self) +{ + return INT2FIX(cvGetImageCOI(IPLIMAGE(self))); +} + +/* + * call-seq: + * set_coi(coi) + * set_coi(coi){|image| ...} + * + * Set COI. coi should be Fixnum. + * Return self. + */ +VALUE +rb_set_coi(VALUE self, VALUE coi) +{ + VALUE block = rb_block_given_p() ? rb_block_proc() : 0; + if (block) { + int prev_coi = cvGetImageCOI(IPLIMAGE(self)); + cvSetImageCOI(IPLIMAGE(self), FIX2INT(coi)); + rb_yield_values(1, self); + cvSetImageCOI(IPLIMAGE(self), prev_coi); + } else { + cvSetImageCOI(IPLIMAGE(self), FIX2INT(coi)); + } + return self; +} + +/* + * Reset COI setting. Same as IplImage#coi = 0. Return self. + */ +VALUE +rb_reset_coi(VALUE self) +{ + cvSetImageCOI(IPLIMAGE(self), 0); + return self; +} + + +VALUE +new_object(int width, int height, int type) +{ + return OPENCV_OBJECT(rb_klass, cvCreateImage(cvSize(width, height), cvCvToIplDepth(type), CV_MAT_CN(type))); +} + +VALUE +new_object(CvSize size, int type) +{ + return OPENCV_OBJECT(rb_klass, cvCreateImage(size, cvCvToIplDepth(type), CV_MAT_CN(type))); +} + +__NAMESPACE_END_IPLIMAGE +__NAMESPACE_END_OPENCV diff --git a/ext/iplimage.h b/ext/iplimage.h new file mode 100644 index 00000000..9e7dc081 --- /dev/null +++ b/ext/iplimage.h @@ -0,0 +1,54 @@ +/************************************************************ + + iplimage.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_IPLIMAGE_H +#define RUBY_OPENCV_IPLIMAGE_H + +#include "opencv.h" + +#define __NAMESPACE_BEGIN_IPLIMAGE namespace cIplImage{ +#define __NAMESPACE_END_IPLIMAGE } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_IPLIMAGE + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_allocate(VALUE klass); +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); + +VALUE rb_load_image(int argc, VALUE *argv, VALUE self); + +VALUE rb_color_model(VALUE self); + +VALUE rb_get_roi(VALUE self); +VALUE rb_set_roi(VALUE self, VALUE roi); +VALUE rb_reset_roi(VALUE self); + +VALUE rb_get_coi(VALUE self); +VALUE rb_set_coi(VALUE self, VALUE coi); +VALUE rb_reset_coi(VALUE self); + +VALUE new_object(int width, int height, int type); +VALUE new_object(CvSize size, int type); +__NAMESPACE_END_IPLIMAGE + +inline IplImage* +IPLIMAGE(VALUE object) +{ + IplImage *ptr, stub; + Data_Get_Struct(object, IplImage, ptr); + return cvGetImage(ptr, &stub); +} + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_IPLIMAGE_H diff --git a/ext/mouseevent.cpp b/ext/mouseevent.cpp new file mode 100644 index 00000000..615902c6 --- /dev/null +++ b/ext/mouseevent.cpp @@ -0,0 +1,184 @@ +/************************************************************ + + mouseevent.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2007 Masakazu Yonekura + +************************************************************/ +#ifdef HAVE_CALLBACK_H + +#include "mouseevent.h" +/* + * Document-module: OpenCV::GUI::MouseEvent + * + * MouseEvent object. + * have + * see OpenCV::GUI::Window#set_mouse_callback. + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_GUI +__NAMESPACE_BEGIN_MOUSEEVENT + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * GUI = rb_define_module_under(opencv, "GUI"); + * cvpoint = rb_define_class_under(opencv, "CvPoint", rb_cObject); + */ + VALUE GUI = rb_module_GUI(); + VALUE cvpoint = cCvPoint::rb_class(); + rb_klass = rb_define_class_under(GUI, "MouseEvent", cvpoint); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_method(rb_klass, "event", RUBY_METHOD_FUNC(rb_event), 0); + rb_define_method(rb_klass, "left_button?", RUBY_METHOD_FUNC(rb_left_button_q), 0); + rb_define_method(rb_klass, "right_button?", RUBY_METHOD_FUNC(rb_right_button_q), 0); + rb_define_method(rb_klass, "middle_button?", RUBY_METHOD_FUNC(rb_middle_button_q), 0); + rb_define_method(rb_klass, "ctrl_key?", RUBY_METHOD_FUNC(rb_ctrl_key_q), 0); + rb_define_method(rb_klass, "shift_key?", RUBY_METHOD_FUNC(rb_shift_key_q), 0); + rb_define_method(rb_klass, "alt_key?", RUBY_METHOD_FUNC(rb_alt_key_q), 0); +} + +VALUE +rb_allocate(VALUE klass) +{ + MouseEvent *ptr; + return Data_Make_Struct(klass, MouseEvent, 0, -1, ptr); +} + +/* + * call-seq: + * event -> symbol + * + * Return Symbol about mouse event. + * + * Currently, return these symbol: + * :move + * When mouse move. + * :right_button_down + * When mouse right button down. + * :left_button_down + * When mosue left button down. + * :middle_button_down + * When mosue middle button down. + * :left_button_up + * When mouse left button down. + * :right_button_up + * When mouse right button down. + * :middle_button_up + * When mouse middle button down. + * + * note: original OpenCV define "double-click" event(e.g. CV_EVENT_LBUTTONDBLCLK). + * But never call these event. Is it bug? + */ +VALUE rb_event(VALUE self) +{ + switch(MOUSEEVENT(self)->event) { + case CV_EVENT_MOUSEMOVE: + return ID2SYM(rb_intern("move")); + case CV_EVENT_LBUTTONDOWN: + return ID2SYM(rb_intern("left_button_down")); + case CV_EVENT_RBUTTONDOWN: + return ID2SYM(rb_intern("right_button_down")); + case CV_EVENT_MBUTTONDOWN: + return ID2SYM(rb_intern("middle_button_down")); + case CV_EVENT_LBUTTONUP: + return ID2SYM(rb_intern("left_button_up")); + case CV_EVENT_RBUTTONUP: + return ID2SYM(rb_intern("right_button_up")); + case CV_EVENT_MBUTTONUP: + return ID2SYM(rb_intern("middle_button_up")); + case CV_EVENT_LBUTTONDBLCLK: + return ID2SYM(rb_intern("left_button_double_click")); + case CV_EVENT_RBUTTONDBLCLK: + return ID2SYM(rb_intern("right_button_double_click")); + case CV_EVENT_MBUTTONDBLCLK: + return ID2SYM(rb_intern("middle_button_double_click")); + } + return Qnil; +} + +/* + * Return true when mouse left button is pushed. Otherwise return false. + */ +VALUE +rb_left_button_q(VALUE self) +{ + return MOUSEEVENT(self)->flag & CV_EVENT_FLAG_LBUTTON ? Qtrue : Qfalse; +} + +/* + * Return true when mouse right button is pushed. Otherwise return false. + */ +VALUE +rb_right_button_q(VALUE self) +{ + return MOUSEEVENT(self)->flag & CV_EVENT_FLAG_RBUTTON ? Qtrue : Qfalse; +} + +/* + * Return true when mouse middle button is pushed. Otherwise return false. + */ +VALUE +rb_middle_button_q(VALUE self) +{ + return MOUSEEVENT(self)->flag & CV_EVENT_FLAG_MBUTTON ? Qtrue : Qfalse; +} + +/* + * Return true when CTRL key is pushed. Otherwise return false. + */ +VALUE +rb_ctrl_key_q(VALUE self) +{ + return MOUSEEVENT(self)->flag & CV_EVENT_FLAG_CTRLKEY ? Qtrue : Qfalse; +} + +/* + * Return true when shift key is pushed. Otherwise return false. + */ +VALUE +rb_shift_key_q(VALUE self) +{ + return MOUSEEVENT(self)->flag & CV_EVENT_FLAG_SHIFTKEY ? Qtrue : Qfalse; +} + +/* + * Return true when ALT key is pushed. Otherwise return false. + */ +VALUE +rb_alt_key_q(VALUE self) +{ + return MOUSEEVENT(self)->flag & CV_EVENT_FLAG_ALTKEY ? Qtrue : Qfalse; +} + +VALUE +new_object(int flag, int y, int x, int event) +{ + VALUE object = rb_allocate(rb_class()); + MouseEvent *mouseevent = MOUSEEVENT(object); + mouseevent->point.x = x; + mouseevent->point.y = y; + mouseevent->event = event; + mouseevent->flag = flag; + return object; +} + +__NAMESPACE_END_MOUSEEVENT +__NAMESPACE_END_GUI +__NAMESPACE_END_OPENCV + +#endif // HAVE_CALLBACK_H diff --git a/ext/mouseevent.h b/ext/mouseevent.h new file mode 100644 index 00000000..a74f99db --- /dev/null +++ b/ext/mouseevent.h @@ -0,0 +1,59 @@ +/************************************************************ + + mouseevent.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifdef HAVE_CALLBACK_H + +#define __NAMESPACE_BEGIN_MOUSEEVENT namespace cMouseEvent{ +#define __NAMESPACE_END_MOUSEEVENT } + +#ifndef RUBY_OPENCV_GUI_MOUSEEVENT_H +#define RUBY_OPENCV_GUI_MOUSEEVENT_H + +#include"opencv.h" + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_GUI +__NAMESPACE_BEGIN_MOUSEEVENT + +typedef struct MouseEvent{ + CvPoint point; + int event; + int flag; +}MouseEvent; + +VALUE rb_class(); + +void define_ruby_class(); + +VALUE rb_allocate(VALUE klass); + +VALUE rb_event(VALUE self); + +VALUE rb_left_button_q(VALUE self); +VALUE rb_right_button_q(VALUE self); +VALUE rb_middle_button_q(VALUE self); +VALUE rb_ctrl_key_q(VALUE self); +VALUE rb_shift_key_q(VALUE self); +VALUE rb_alt_key_q(VALUE self); + +VALUE new_object(int event, int x, int y, int flag); + +inline MouseEvent *MOUSEEVENT(VALUE object){ + MouseEvent *ptr; + Data_Get_Struct(object, MouseEvent, ptr); + return ptr; +} + +__NAMESPACE_END_MOUSEEVENT +__NAMESPACE_END_GUI +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_GUI_MOUSEEVENT_H + +#endif // HAVE_CALLBACK_H diff --git a/ext/opencv.cpp b/ext/opencv.cpp new file mode 100644 index 00000000..05b1d220 --- /dev/null +++ b/ext/opencv.cpp @@ -0,0 +1,481 @@ +/************************************************************ + + opencv.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2008 Masakazu Yonekura + +************************************************************/ +/* + * Document-module: OpenCV + * + * =What is OpenCV? + * + * OpenCV is "Open Source Computer Vision Library". + * OpenCV is developed by Intel and many opensource developers. + * This library include many useful function for computer vision, such as object-detection. + * + * OpenCV is developed at + * sourceforge.net[http://sourceforge.net/projects/opencvlibrary] + * + * =What is Ruby/OpenCV? + * Ruby/OpenCV is manual Wrapper of OpenCV (not use SWIG). + * This library seem to be *Ruby*. + * * object-oriented + * * support Garbage Collection by Ruby + * Ruby/OpenCV is developed + * http://rubyforge.org/projects/opencv (Official) + * and + * http://blueruby.mydns.jp/pages/opencv (Japanese) + * + * =How to install + * + * Show INSTALL + * + * =How to generate this documentation? + * This document created by rdoc. + * If you have Ruby 1.8 or later, you might use rdoc command. + * for example + * > cd opencv + * > rdoc + * and show "./doc/index.html" + */ +#include "opencv.h" + +__NAMESPACE_BEGIN_OPENCV + + +/* + * Hashtable for protect from GC + */ +st_table *root_table = st_init_numtable(); + +/* + * Mark root object. (protect from GC) + */ +void +mark_root_object(void *ptr) +{ + VALUE value; + if(ptr && st_lookup(root_table, (st_data_t)ptr, (st_data_t*)&value)){ + rb_gc_mark(value); + } +} + +/* + * Look-up Root root object. + */ +VALUE +lookup_root_object(void *ptr) +{ + VALUE value = 0; + if(ptr) + st_lookup(root_table, (st_data_t)ptr, (st_data_t*)&value); + return value; +} + +/* + * Resist root object. + */ +void +resist_root_object(void *ptr, VALUE root) +{ + st_insert(root_table, (st_data_t)ptr, (st_data_t)root); +} + +/* + * Delete mark symbol from hashtable only, not free memory. + */ +void +unresist_object(void *ptr) +{ + st_delete(root_table, (st_data_t*)&ptr, 0); +} + +/* + * Delete mark symbol from hash table, then free memory. + */ +void +free_object(void *ptr) +{ + if(ptr){ + unresist_object(ptr); + cvFree(&ptr); + } +} + +/* + * Release OpenCV specific structure(i.e CvMat, IplImage..) from memory and delete from hashtable. + */ +void +release_object(void *ptr) +{ + if(ptr){ + unresist_object(ptr); + cvRelease(&ptr); + } +} + +VALUE rb_module; +VALUE rb_opencv_constants; + +VALUE +rb_module_opencv() +{ + return rb_module; +} + +/* + * convert OpenCV internal error to Ruby exception. + */ +int +error_callback(int status, + const char *function_name, + const char *error_message, + const char *file_name, + int line, + void *user_data) +{ + int error_code = (CvStatus)cvGetErrStatus(); + if(error_code){ + OPENCV_RSTERR(); // = CV_StsOk + rb_warn("OpenCV error code (%d) : %s (%d in %s)", error_code, function_name, line, file_name); + rb_raise(mCvError::by_code(error_code), "%s", error_message); + } + return 0; +} + +void +define_ruby_module() +{ + if(rb_module) + return; + rb_module = rb_define_module("OpenCV"); + + /* 0: 8bit unsigned */ + rb_define_const(rb_module, "CV_8U", INT2FIX(CV_8U)); + /* 1: 8bit signed */ + rb_define_const(rb_module, "CV_8S", INT2FIX(CV_8S)); + /* 2: 16bit unsigned */ + rb_define_const(rb_module, "CV_16U", INT2FIX(CV_16U)); + /* 3: 16bit signed */ + rb_define_const(rb_module, "CV_16S", INT2FIX(CV_16S)); + /* 4: 32bit signed */ + rb_define_const(rb_module, "CV_32S", INT2FIX(CV_32S)); + /* 5: 32bit floating-point */ + rb_define_const(rb_module, "CV_32F", INT2FIX(CV_32F)); + /* 6: 64bit floating-point */ + rb_define_const(rb_module, "CV_64F", INT2FIX(CV_64F)); + + + VALUE inversion_method = rb_hash_new(); + /* {:lu, :svd, :svd_sym(:svd_symmetric)}: Inversion method */ + rb_define_const(rb_module, "INVERSION_METHOD", inversion_method); + RESIST_CVMETHOD(inversion_method, "lu", CV_LU); + RESIST_CVMETHOD(inversion_method, "svd", CV_SVD); + RESIST_CVMETHOD(inversion_method, "svd_sym", CV_SVD_SYM); + RESIST_CVMETHOD(inversion_method, "svd_symmetric", CV_SVD_SYM); + + VALUE dxt_flag = rb_hash_new(); + /* {:forward, :inverse, :scale, :rows}: DFT and DCT flags */ + rb_define_const(rb_module, "DXT_FLAG", dxt_flag); + RESIST_CVMETHOD(dxt_flag, "forward", CV_DXT_FORWARD); + RESIST_CVMETHOD(dxt_flag, "inverse", CV_DXT_INVERSE); + RESIST_CVMETHOD(dxt_flag, "scale", CV_DXT_SCALE); + RESIST_CVMETHOD(dxt_flag, "rows", CV_DXT_ROWS); + + VALUE interpolation_method = rb_hash_new(); + /* {:nn, :linear, :area, :cubic}: Interpolation method */ + rb_define_const(rb_module, "INTERPOLATION_METHOD", interpolation_method); + RESIST_CVMETHOD(interpolation_method, "nn", CV_INTER_NN); + RESIST_CVMETHOD(interpolation_method, "linear", CV_INTER_LINEAR); + RESIST_CVMETHOD(interpolation_method, "area", CV_INTER_AREA); + RESIST_CVMETHOD(interpolation_method, "cubic", CV_INTER_CUBIC); + + VALUE warp_flag = rb_hash_new(); + /* {:fill_outliers, :inverse_map}: Warp affine optional flags */ + rb_define_const(rb_module, "WARP_FLAG", warp_flag); + RESIST_CVMETHOD(warp_flag, "fill_outliers", CV_WARP_FILL_OUTLIERS); + RESIST_CVMETHOD(warp_flag, "inverse_map", CV_WARP_INVERSE_MAP); + + VALUE depth = rb_hash_new(); + /* {:cv8u, :cv8s, :cv16u, :cv16s, :cv32s, :cv32f, :cv64f}: Depth of each pixel. */ + rb_define_const(rb_module, "DEPTH", depth); + RESIST_CVMETHOD(depth, "cv8u", CV_8U); + RESIST_CVMETHOD(depth, "cv8s", CV_8S); + RESIST_CVMETHOD(depth, "cv16u", CV_16U); + RESIST_CVMETHOD(depth, "cv16s", CV_16S); + RESIST_CVMETHOD(depth, "cv32s", CV_32S); + RESIST_CVMETHOD(depth, "cv32f", CV_32F); + RESIST_CVMETHOD(depth, "cv64f", CV_64F); + + VALUE connectivity = rb_hash_new(); + /* {:aa(:anti_alias)}: Determined by the closeness of pixel values */ + rb_define_const(rb_module, "CONNECTIVITY", connectivity); + RESIST_CVMETHOD(depth, "aa", CV_AA); + RESIST_CVMETHOD(depth, "anti_alias", CV_AA); + + VALUE retrieval_mode = rb_hash_new(); + /* {:external, :list, :ccomp, :tree}: Retrieval mode */ + rb_define_const(rb_module, "RETRIEVAL_MODE", retrieval_mode); + RESIST_CVMETHOD(retrieval_mode, "external", CV_RETR_EXTERNAL); + RESIST_CVMETHOD(retrieval_mode, "list", CV_RETR_LIST); + RESIST_CVMETHOD(retrieval_mode, "ccomp", CV_RETR_CCOMP); + RESIST_CVMETHOD(retrieval_mode, "tree", CV_RETR_TREE); + + VALUE approx_chain_method = rb_hash_new(); + /* {:code, :approx_none, :approx_simple, :apporx_tc89_11, :approx_tc89_kcos}: Approximation method */ + rb_define_const(rb_module, "APPROX_CHAIN_METHOD", approx_chain_method); + RESIST_CVMETHOD(approx_chain_method, "code", CV_CHAIN_CODE); + RESIST_CVMETHOD(approx_chain_method, "approx_none", CV_CHAIN_APPROX_NONE); + RESIST_CVMETHOD(approx_chain_method, "approx_simple", CV_CHAIN_APPROX_SIMPLE); + RESIST_CVMETHOD(approx_chain_method, "approx_tc89_l1", CV_CHAIN_APPROX_TC89_L1); + RESIST_CVMETHOD(approx_chain_method, "approx_tc89_kcos", CV_CHAIN_APPROX_TC89_KCOS); + + VALUE approx_poly_method = rb_hash_new(); + /* {:dp}: Approximation method (polygon) */ + rb_define_const(rb_module, "APPROX_POLY_METHOD", approx_poly_method); + RESIST_CVMETHOD(approx_poly_method, "dp", CV_POLY_APPROX_DP); + + VALUE match_template_method = rb_hash_new(); + /* {:sqdiff, :sqdiff_normed, :ccorr, :ccorr_normed, :ccoeff, :ccoeff_normed}: Match template method */ + rb_define_const(rb_module, "MATCH_TEMPLATE_METHOD", match_template_method); + RESIST_CVMETHOD(match_template_method, "sqdiff", CV_TM_SQDIFF); + RESIST_CVMETHOD(match_template_method, "sqdiff_normed", CV_TM_SQDIFF_NORMED); + RESIST_CVMETHOD(match_template_method, "ccorr", CV_TM_CCORR); + RESIST_CVMETHOD(match_template_method, "ccorr_normed", CV_TM_CCORR_NORMED); + RESIST_CVMETHOD(match_template_method, "ccoeff", CV_TM_CCOEFF); + RESIST_CVMETHOD(match_template_method, "ccoeff_normed", CV_TM_CCOEFF_NORMED); + + /* color convert methods */ + rb_define_module_function(rb_module, "BGR2BGRA", RUBY_METHOD_FUNC(rb_BGR2BGRA), 1); + rb_define_module_function(rb_module, "RGB2RGBA", RUBY_METHOD_FUNC(rb_RGB2RGBA), 1); + rb_define_module_function(rb_module, "BGRA2BGR", RUBY_METHOD_FUNC(rb_BGRA2BGR), 1); + rb_define_module_function(rb_module, "RGBA2RGB", RUBY_METHOD_FUNC(rb_RGBA2RGB), 1); + rb_define_module_function(rb_module, "BGR2RGBA", RUBY_METHOD_FUNC(rb_BGR2RGBA), 1); + rb_define_module_function(rb_module, "RGB2BGRA", RUBY_METHOD_FUNC(rb_RGB2BGRA), 1); + rb_define_module_function(rb_module, "RGBA2BGR", RUBY_METHOD_FUNC(rb_RGBA2BGR), 1); + rb_define_module_function(rb_module, "BGRA2RGB", RUBY_METHOD_FUNC(rb_BGRA2RGB), 1); + rb_define_module_function(rb_module, "BGR2RGB", RUBY_METHOD_FUNC(rb_BGR2RGB), 1); + rb_define_module_function(rb_module, "RGB2BGR", RUBY_METHOD_FUNC(rb_RGB2BGR), 1); + rb_define_module_function(rb_module, "BGRA2RGBA", RUBY_METHOD_FUNC(rb_BGRA2RGBA), 1); + rb_define_module_function(rb_module, "RGBA2BGRA", RUBY_METHOD_FUNC(rb_RGBA2BGRA), 1); + rb_define_module_function(rb_module, "BGR2GRAY", RUBY_METHOD_FUNC(rb_BGR2GRAY), 1); + rb_define_module_function(rb_module, "RGB2GRAY", RUBY_METHOD_FUNC(rb_RGB2GRAY), 1); + rb_define_module_function(rb_module, "GRAY2BGR", RUBY_METHOD_FUNC(rb_GRAY2BGR), 1); + rb_define_module_function(rb_module, "GRAY2RGB", RUBY_METHOD_FUNC(rb_GRAY2RGB), 1); + rb_define_module_function(rb_module, "GRAY2BGRA", RUBY_METHOD_FUNC(rb_GRAY2BGRA), 1); + rb_define_module_function(rb_module, "GRAY2RGBA", RUBY_METHOD_FUNC(rb_GRAY2RGBA), 1); + rb_define_module_function(rb_module, "BGRA2GRAY", RUBY_METHOD_FUNC(rb_BGRA2GRAY), 1); + rb_define_module_function(rb_module, "RGBA2GRAY", RUBY_METHOD_FUNC(rb_RGBA2GRAY), 1); + rb_define_module_function(rb_module, "BGR2BGR565", RUBY_METHOD_FUNC(rb_BGR2BGR565), 1); + rb_define_module_function(rb_module, "RGB2BGR565", RUBY_METHOD_FUNC(rb_RGB2BGR565), 1); + rb_define_module_function(rb_module, "BGR5652BGR", RUBY_METHOD_FUNC(rb_BGR5652BGR), 1); + rb_define_module_function(rb_module, "BGR5652RGB", RUBY_METHOD_FUNC(rb_BGR5652RGB), 1); + rb_define_module_function(rb_module, "BGRA2BGR565", RUBY_METHOD_FUNC(rb_BGRA2BGR565), 1); + rb_define_module_function(rb_module, "RGBA2BGR565", RUBY_METHOD_FUNC(rb_RGBA2BGR565), 1); + rb_define_module_function(rb_module, "BGR5652BGRA", RUBY_METHOD_FUNC(rb_BGR5652BGRA), 1); + rb_define_module_function(rb_module, "BGR5652RGBA", RUBY_METHOD_FUNC(rb_BGR5652RGBA), 1); + rb_define_module_function(rb_module, "GRAY2BGR565", RUBY_METHOD_FUNC(rb_GRAY2BGR565), 1); + rb_define_module_function(rb_module, "BGR5652GRAY", RUBY_METHOD_FUNC(rb_BGR5652GRAY), 1); + rb_define_module_function(rb_module, "BGR2BGR555", RUBY_METHOD_FUNC(rb_BGR2BGR555), 1); + rb_define_module_function(rb_module, "RGB2BGR555", RUBY_METHOD_FUNC(rb_RGB2BGR555), 1); + rb_define_module_function(rb_module, "BGR5552BGR", RUBY_METHOD_FUNC(rb_BGR5552BGR), 1); + rb_define_module_function(rb_module, "BGR5552RGB", RUBY_METHOD_FUNC(rb_BGR5552RGB), 1); + rb_define_module_function(rb_module, "BGRA2BGR555", RUBY_METHOD_FUNC(rb_BGRA2BGR555), 1); + rb_define_module_function(rb_module, "RGBA2BGR555", RUBY_METHOD_FUNC(rb_RGBA2BGR555), 1); + rb_define_module_function(rb_module, "BGR5552BGRA", RUBY_METHOD_FUNC(rb_BGR5552BGRA), 1); + rb_define_module_function(rb_module, "BGR5552RGBA", RUBY_METHOD_FUNC(rb_BGR5552RGBA), 1); + rb_define_module_function(rb_module, "GRAY2BGR555", RUBY_METHOD_FUNC(rb_GRAY2BGR555), 1); + rb_define_module_function(rb_module, "BGR5552GRAY", RUBY_METHOD_FUNC(rb_BGR5552GRAY), 1); + rb_define_module_function(rb_module, "BGR2XYZ", RUBY_METHOD_FUNC(rb_BGR2XYZ), 1); + rb_define_module_function(rb_module, "RGB2XYZ", RUBY_METHOD_FUNC(rb_RGB2XYZ), 1); + rb_define_module_function(rb_module, "XYZ2BGR", RUBY_METHOD_FUNC(rb_XYZ2BGR), 1); + rb_define_module_function(rb_module, "XYZ2RGB", RUBY_METHOD_FUNC(rb_XYZ2RGB), 1); + rb_define_module_function(rb_module, "BGR2YCrCb", RUBY_METHOD_FUNC(rb_BGR2YCrCb), 1); + rb_define_module_function(rb_module, "RGB2YCrCb", RUBY_METHOD_FUNC(rb_RGB2YCrCb), 1); + rb_define_module_function(rb_module, "YCrCb2BGR", RUBY_METHOD_FUNC(rb_YCrCb2BGR), 1); + rb_define_module_function(rb_module, "YCrCb2RGB", RUBY_METHOD_FUNC(rb_YCrCb2RGB), 1); + rb_define_module_function(rb_module, "BGR2HSV", RUBY_METHOD_FUNC(rb_BGR2HSV), 1); + rb_define_module_function(rb_module, "RGB2HSV", RUBY_METHOD_FUNC(rb_RGB2HSV), 1); + rb_define_module_function(rb_module, "BGR2Lab", RUBY_METHOD_FUNC(rb_BGR2Lab), 1); + rb_define_module_function(rb_module, "RGB2Lab", RUBY_METHOD_FUNC(rb_RGB2Lab), 1); + rb_define_module_function(rb_module, "BayerBG2BGR", RUBY_METHOD_FUNC(rb_BayerBG2BGR), 1); + rb_define_module_function(rb_module, "BayerGB2BGR", RUBY_METHOD_FUNC(rb_BayerGB2BGR), 1); + rb_define_module_function(rb_module, "BayerRG2BGR", RUBY_METHOD_FUNC(rb_BayerRG2BGR), 1); + rb_define_module_function(rb_module, "BayerGR2BGR", RUBY_METHOD_FUNC(rb_BayerGR2BGR), 1); + rb_define_module_function(rb_module, "BayerBG2RGB", RUBY_METHOD_FUNC(rb_BayerBG2RGB), 1); + rb_define_module_function(rb_module, "BayerGB2RGB", RUBY_METHOD_FUNC(rb_BayerGB2RGB), 1); + rb_define_module_function(rb_module, "BayerRG2RGB", RUBY_METHOD_FUNC(rb_BayerRG2RGB), 1); + rb_define_module_function(rb_module, "BayerGR2RGB", RUBY_METHOD_FUNC(rb_BayerGR2RGB), 1); + rb_define_module_function(rb_module, "BGR2Luv", RUBY_METHOD_FUNC(rb_BGR2Luv), 1); + rb_define_module_function(rb_module, "RGB2Luv", RUBY_METHOD_FUNC(rb_RGB2Luv), 1); + rb_define_module_function(rb_module, "BGR2HLS", RUBY_METHOD_FUNC(rb_BGR2HLS), 1); + rb_define_module_function(rb_module, "RGB2HLS", RUBY_METHOD_FUNC(rb_RGB2HLS), 1); + rb_define_module_function(rb_module, "HSV2BGR", RUBY_METHOD_FUNC(rb_HSV2BGR), 1); + rb_define_module_function(rb_module, "HSV2RGB", RUBY_METHOD_FUNC(rb_HSV2RGB), 1); + rb_define_module_function(rb_module, "Lab2BGR", RUBY_METHOD_FUNC(rb_Lab2BGR), 1); + rb_define_module_function(rb_module, "Lab2RGB", RUBY_METHOD_FUNC(rb_Lab2RGB), 1); + rb_define_module_function(rb_module, "Luv2BGR", RUBY_METHOD_FUNC(rb_Luv2BGR), 1); + rb_define_module_function(rb_module, "Luv2RGB", RUBY_METHOD_FUNC(rb_Luv2RGB), 1); + rb_define_module_function(rb_module, "HLS2BGR", RUBY_METHOD_FUNC(rb_HLS2BGR), 1); + rb_define_module_function(rb_module, "HLS2RGB", RUBY_METHOD_FUNC(rb_HLS2RGB), 1); +} + +#define CREATE_CVTCOLOR_FUNC(rb_func_name, c_const_name, src_cn, dest_cn) \ + VALUE rb_func_name(VALUE klass, VALUE image) \ + { \ + VALUE dest; \ + if (!rb_obj_is_kind_of(image, cCvMat::rb_class())) \ + rb_raise(rb_eTypeError, "argument 1 should be %s.", rb_class2name(cCvMat::rb_class())); \ + int type = cvGetElemType(CVARR(image)); \ + if (CV_MAT_CN(type) != src_cn) \ + rb_raise(rb_eTypeError, "argument 1 should be %d-channel.", src_cn); \ + dest = cIplImage::new_object(cvGetSize(CVARR(image)), CV_MAKETYPE(CV_MAT_DEPTH(type), dest_cn)); \ + cvCvtColor(CVARR(image), CVARR(dest), c_const_name); \ + return dest; \ + } + +CREATE_CVTCOLOR_FUNC(rb_BGR2BGRA, CV_BGR2BGRA, 3, 4); +CREATE_CVTCOLOR_FUNC(rb_RGB2RGBA, CV_RGB2RGBA, 3, 4); +CREATE_CVTCOLOR_FUNC(rb_BGRA2BGR, CV_BGRA2BGR, 4, 3); +CREATE_CVTCOLOR_FUNC(rb_RGBA2RGB, CV_RGBA2RGB, 4, 3); +CREATE_CVTCOLOR_FUNC(rb_BGR2RGBA, CV_BGR2RGBA, 3, 4); +CREATE_CVTCOLOR_FUNC(rb_RGB2BGRA, CV_RGB2BGRA, 3, 4); +CREATE_CVTCOLOR_FUNC(rb_RGBA2BGR, CV_RGBA2BGR, 4, 3); +CREATE_CVTCOLOR_FUNC(rb_BGRA2RGB, CV_BGRA2RGB, 4, 3); +CREATE_CVTCOLOR_FUNC(rb_BGR2RGB, CV_BGR2RGB, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_RGB2BGR, CV_RGB2BGR, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_BGRA2RGBA, CV_BGRA2RGBA, 4, 4); +CREATE_CVTCOLOR_FUNC(rb_RGBA2BGRA, CV_RGBA2BGRA, 4, 4); +CREATE_CVTCOLOR_FUNC(rb_BGR2GRAY, CV_BGR2GRAY, 3, 1); +CREATE_CVTCOLOR_FUNC(rb_RGB2GRAY, CV_RGB2GRAY, 3, 1); +CREATE_CVTCOLOR_FUNC(rb_GRAY2BGR, CV_GRAY2BGR, 1, 3); +CREATE_CVTCOLOR_FUNC(rb_GRAY2RGB, CV_GRAY2RGB, 1, 3); +CREATE_CVTCOLOR_FUNC(rb_GRAY2BGRA, CV_GRAY2BGRA, 1, 4); +CREATE_CVTCOLOR_FUNC(rb_GRAY2RGBA, CV_GRAY2RGBA, 1, 4); +CREATE_CVTCOLOR_FUNC(rb_BGRA2GRAY, CV_BGRA2GRAY, 4, 1); +CREATE_CVTCOLOR_FUNC(rb_RGBA2GRAY, CV_RGBA2GRAY, 4, 1); +CREATE_CVTCOLOR_FUNC(rb_BGR2BGR565, CV_BGR2BGR565, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_RGB2BGR565, CV_RGB2BGR565, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_BGR5652BGR, CV_BGR5652BGR, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_BGR5652RGB, CV_BGR5652RGB, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_BGRA2BGR565, CV_BGRA2BGR565, 4, 3); +CREATE_CVTCOLOR_FUNC(rb_RGBA2BGR565, CV_RGBA2BGR565, 4, 3); +CREATE_CVTCOLOR_FUNC(rb_BGR5652BGRA, CV_BGR5652BGRA, 3, 4); +CREATE_CVTCOLOR_FUNC(rb_BGR5652RGBA, CV_BGR5652RGBA, 3, 4); +CREATE_CVTCOLOR_FUNC(rb_GRAY2BGR565, CV_GRAY2BGR565, 1, 3); +CREATE_CVTCOLOR_FUNC(rb_BGR5652GRAY, CV_BGR5652GRAY, 3, 1); +CREATE_CVTCOLOR_FUNC(rb_BGR2BGR555, CV_BGR2BGR555, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_RGB2BGR555, CV_RGB2BGR555, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_BGR5552BGR, CV_BGR5552BGR, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_BGR5552RGB, CV_BGR5552RGB, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_BGRA2BGR555, CV_BGRA2BGR555, 4, 3); +CREATE_CVTCOLOR_FUNC(rb_RGBA2BGR555, CV_RGBA2BGR555, 4, 3); +CREATE_CVTCOLOR_FUNC(rb_BGR5552BGRA, CV_BGR5552BGRA, 3, 4); +CREATE_CVTCOLOR_FUNC(rb_BGR5552RGBA, CV_BGR5552RGBA, 3, 4); +CREATE_CVTCOLOR_FUNC(rb_GRAY2BGR555, CV_GRAY2BGR555, 1, 3); +CREATE_CVTCOLOR_FUNC(rb_BGR5552GRAY, CV_BGR5552GRAY, 3, 1); +CREATE_CVTCOLOR_FUNC(rb_BGR2XYZ, CV_BGR2XYZ, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_RGB2XYZ, CV_RGB2XYZ, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_XYZ2BGR, CV_XYZ2BGR, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_XYZ2RGB, CV_XYZ2RGB, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_BGR2YCrCb, CV_BGR2YCrCb, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_RGB2YCrCb, CV_RGB2YCrCb, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_YCrCb2BGR, CV_YCrCb2BGR, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_YCrCb2RGB, CV_YCrCb2RGB, 0, 3); +CREATE_CVTCOLOR_FUNC(rb_BGR2HSV, CV_BGR2HSV, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_RGB2HSV, CV_RGB2HSV, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_BGR2Lab, CV_BGR2Lab, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_RGB2Lab, CV_RGB2Lab, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_BayerBG2BGR, CV_BayerBG2BGR, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_BayerGB2BGR, CV_BayerGB2BGR, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_BayerRG2BGR, CV_BayerRG2BGR, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_BayerGR2BGR, CV_BayerGR2BGR, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_BayerBG2RGB, CV_BayerBG2RGB, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_BayerGB2RGB, CV_BayerGB2RGB, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_BayerRG2RGB, CV_BayerRG2RGB, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_BayerGR2RGB, CV_BayerGR2RGB, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_BGR2Luv, CV_BGR2Luv, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_RGB2Luv, CV_RGB2Luv, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_BGR2HLS, CV_BGR2HLS, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_RGB2HLS, CV_RGB2HLS, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_HSV2BGR, CV_HSV2BGR, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_HSV2RGB, CV_HSV2RGB, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_Lab2BGR, CV_Lab2BGR, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_Lab2RGB, CV_Lab2RGB, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_Luv2BGR, CV_Luv2BGR, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_Luv2RGB, CV_Luv2RGB, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_HLS2BGR, CV_HLS2BGR, 3, 3); +CREATE_CVTCOLOR_FUNC(rb_HLS2RGB, CV_HLS2RGB, 3, 3); + +__NAMESPACE_END_OPENCV + +extern "C"{ + void + Init_opencv() + { + cvRedirectError((CvErrorCallback)mOpenCV::error_callback); + + mOpenCV::define_ruby_module(); + + mOpenCV::mCvError::define_ruby_module(); + mOpenCV::cCvPoint::define_ruby_class(); + mOpenCV::cCvPoint2D32f::define_ruby_class(); + mOpenCV::cCvPoint3D32f::define_ruby_class(); + mOpenCV::cCvSize::define_ruby_class(); + mOpenCV::cCvSize2D32f::define_ruby_class(); + mOpenCV::cCvRect::define_ruby_class(); + mOpenCV::cCvScalar::define_ruby_class(); + mOpenCV::cCvSlice::define_ruby_class(); + mOpenCV::cCvTermCriteria::define_ruby_class(); + mOpenCV::cCvBox2D::define_ruby_class(); + mOpenCV::cCvFont::define_ruby_class(); + mOpenCV::cIplConvKernel::define_ruby_class(); + mOpenCV::cCvMoments::define_ruby_class(); + mOpenCV::cCvConvexityDefect::define_ruby_class(); + + mOpenCV::cCvMemStorage::define_ruby_class(); + + mOpenCV::cCvSeq::define_ruby_class(); + mOpenCV::mCurve::define_ruby_module(); + mOpenCV::mPointSet::define_ruby_module(); + mOpenCV::mPoint3DSet::define_ruby_module(); + mOpenCV::cCvSet::define_ruby_class(); + mOpenCV::cCvChain::define_ruby_class(); + mOpenCV::cCvChainCode::define_ruby_class(); + mOpenCV::cCvContour::define_ruby_class(); + mOpenCV::cCvContourTree::define_ruby_class(); + + mOpenCV::cCvMat::define_ruby_class(); + mOpenCV::cIplImage::define_ruby_class(); + mOpenCV::cCvMatND::define_ruby_class(); + mOpenCV::cCvSparseMat::define_ruby_class(); + mOpenCV::cCvHistogram::define_ruby_class(); + mOpenCV::cCvCapture::define_ruby_class(); + + mOpenCV::cCvIndex::define_ruby_class(); + mOpenCV::cCvLine::define_ruby_class(); + mOpenCV::cCvTwoPoints::define_ruby_class(); + mOpenCV::cCvCircle32f::define_ruby_class(); + + mOpenCV::cCvConDensation::define_ruby_class(); + + mOpenCV::cCvConnectedComp::define_ruby_class(); + mOpenCV::cCvAvgComp::define_ruby_class(); + mOpenCV::cCvHaarClassifierCascade::define_ruby_class(); +#ifdef HAVE_CALLBACK_H + mOpenCV::mGUI::define_ruby_module(); + mOpenCV::mGUI::cWindow::define_ruby_class(); + mOpenCV::mGUI::cTrackbar::define_ruby_class(); + mOpenCV::mGUI::cMouseEvent::define_ruby_class(); +#endif + +#ifdef HAVE_ML_H + /* feature support. + mOpenCV::mMachineLearning::define_ruby_module(); + */ +#endif + } +} diff --git a/ext/opencv.h b/ext/opencv.h new file mode 100644 index 00000000..05bcfef2 --- /dev/null +++ b/ext/opencv.h @@ -0,0 +1,356 @@ +/************************************************************ + + opencv.h - + + $Author: lsxi $ + + Copyright (C) 2005-2007 Masakazu Yonekura + + ************************************************************/ +#ifndef RUBY_OPENCV_H +#define RUBY_OPENCV_H + +#define __NAMESPACE_BEGIN_OPENCV namespace mOpenCV{ +#define __NAMESPACE_END_OPENCV } + +/* include headers */ +#include +#include + +#ifdef RUBY_WIN32_H +#ifdef write +#undef write +#endif // write +#endif // RUBY_WIN32_H + +#ifndef ANYARGS +#define ANYARGS () +#endif + +extern "C"{ +#include +#ifdef HAVE_CALLBACK_H +#include // callhack.h is ffcall header +#endif + +#ifdef HAVE_STDARG_H +#include +#define va_init_list(a,b) va_start(a,b) +#else +#include +#define va_init_list(a,b) va_start(a) +#endif +} + +// standard c headers +#include +#include +#include +#include + +// OpenCV headers +#include +#include +#include +#include +#ifdef HAVE_ML_H +#include +#endif + +// Ruby/OpenCV headers +#include "cverror.h" +#include "cvpoint.h" +#include "cvpoint2d32f.h" +#include "cvsize.h" +#include "cvsize2d32f.h" +#include "cvrect.h" +#include "cvscalar.h" +#include "cvslice.h" +#include "cvtermcriteria.h" +#include "cvbox2d.h" +#include "cvfont.h" +#include "iplconvkernel.h" +#include "cvmoments.h" +#include "cvconvexitydefect.h" +#include "cvpoint3d32f.h" + +#include "cvmemstorage.h" + +#include "cvseq.h" +#include "curve.h" +#include "pointset.h" +#include "point3dset.h" +#include "cvset.h" +#include "cvchain.h" +#include "cvchaincode.h" +#include "cvcontour.h" +#include "cvcontourtree.h" + +#include "cvmat.h" +#include "iplimage.h" +#include "cvmatnd.h" +#include "cvsparsemat.h" +#include "cvhistogram.h" +#include "cvcapture.h" + +#include "cvindex.h" +#include "cvline.h" +#include "cvtwopoints.h" +#include "cvcircle32f.h" + +#include "cvcondensation.h" + +#include "cvconnectedcomp.h" +#include "cvavgcomp.h" +#include "cvhaarclassifiercascade.h" + +// GUI +#include "gui.h" +#include "window.h" +#include "trackbar.h" +#include "mouseevent.h" + +// memory management wrapper +#define CVALLOC(type) (type*)cvAlloc(sizeof(type)) + +// useful macros +#define IF_INT(val, ifnone) NIL_P(val) ? ifnone : NUM2INT(val) +#define IF_DBL(val, ifnone) NIL_P(val) ? ifnone : NUM2DBL(val) +#define IF_STRING(str) NIL_P(str) ? NULL : TYPE(str) == T_STRING ? rb +#define IF_BOOL(val, t, f, ifnone) val == Qtrue ? t : val == Qfalse ? f : ifnone + +#define IF_DEPTH(val, ifnone) NIL_P(val) ? ifnone : FIX2INT(val) + +#define RESIST_CVMETHOD(hash, str, value) rb_hash_aset(hash, ID2SYM(rb_intern(str)), INT2FIX(value)) + +#define maxint(a,b) ({int _a = (a), _b = (b); _a > _b ? _a : _b; }) + +// OpenCV module +__NAMESPACE_BEGIN_OPENCV + +void mark_root_object(void *ptr); +VALUE lookup_root_object(void *ptr); +void resist_root_object(void *ptr, VALUE root); +void unresist_object(void *ptr); +void free_object(void *ptr); +void release_object(void *ptr); + +VALUE rb_module_opencv(); +void define_ruby_module(); + +// Ruby/OpenCV inline functions +inline CvArr* +CVARR(VALUE object) +{ + CvArr *ptr; + Data_Get_Struct(object, CvArr, ptr); + return ptr; +} + +inline VALUE +OPENCV_OBJECT(VALUE klass, void *ptr) +{ + return Data_Wrap_Struct(klass, 0, release_object, ptr); +} + +inline VALUE +GENERIC_OBJECT(VALUE klass, void *ptr) +{ + return Data_Wrap_Struct(klass, 0, 0, ptr); +} + +inline VALUE +DEPEND_OBJECT(VALUE klass, void *ptr, VALUE root) +{ + resist_root_object(ptr, root); + return Data_Wrap_Struct(klass, mark_root_object, free_object, ptr); +} + +inline VALUE +REFER_OBJECT(VALUE klass, void *ptr, VALUE root) +{ + resist_root_object(ptr, root); + return Data_Wrap_Struct(klass, mark_root_object, unresist_object, ptr); +} + +inline VALUE +CONVERT(VALUE object, VALUE klass) +{ + VALUE method_name = rb_str_concat(rb_str_new2("from_"), rb_str_new2(rb_obj_classname(object))); + VALUE result = rb_funcall(klass, rb_intern(StringValueCStr(method_name)), 1, object); + if(CLASS_OF(result) != klass) + rb_raise(rb_eTypeError, "require %s, but return %s.", rb_class2name(klass), rb_class2name(CLASS_OF(result))); + return result; +} + +inline int +CVMETHOD(const char *name, VALUE method, int ifnone = 0) +{ + VALUE value; + switch(TYPE(method)){ + case T_NIL: + return ifnone; + case T_FIXNUM: + return FIX2INT(method); + case T_STRING: + method = rb_str_intern(method); + case T_SYMBOL: + value = rb_hash_aref(rb_const_get(rb_module_opencv(), rb_intern(name)), method); + if(NIL_P(value)){ + rb_warn("invalid opencv method type (see OpenCV::%s)", name); + return ifnone; + }else{ + return FIX2INT(value); + }if (rb_obj_is_kind_of(value, rb_cNumeric)) + default: + rb_raise(rb_eTypeError, ""); + } + return 0; +} + +inline int +TRUE_OR_FALSE(VALUE object, int ifnone) +{ + int value = ifnone; + switch (TYPE(object)) { + case T_TRUE: + value = 1; + break; + case T_FALSE: + value = 0; + break; + case T_NIL: + break; + default: + rb_warn("argument should be true or false."); + } + return value; +} + +VALUE rb_BGR2BGRA(VALUE klass, VALUE image); +VALUE rb_RGB2RGBA(VALUE klass, VALUE image); +VALUE rb_BGRA2BGR(VALUE klass, VALUE image); +VALUE rb_RGBA2RGB(VALUE klass, VALUE image); +VALUE rb_BGR2RGBA(VALUE klass, VALUE image); +VALUE rb_RGB2BGRA(VALUE klass, VALUE image); +VALUE rb_RGBA2BGR(VALUE klass, VALUE image); +VALUE rb_BGRA2RGB(VALUE klass, VALUE image); +VALUE rb_BGR2RGB(VALUE klass, VALUE image); +VALUE rb_RGB2BGR(VALUE klass, VALUE image); +VALUE rb_BGRA2RGBA(VALUE klass, VALUE image); +VALUE rb_RGBA2BGRA(VALUE klass, VALUE image); +VALUE rb_BGR2GRAY(VALUE klass, VALUE image); +VALUE rb_RGB2GRAY(VALUE klass, VALUE image); +VALUE rb_GRAY2BGR(VALUE klass, VALUE image); +VALUE rb_GRAY2RGB(VALUE klass, VALUE image); +VALUE rb_GRAY2BGRA(VALUE klass, VALUE image); +VALUE rb_GRAY2RGBA(VALUE klass, VALUE image); +VALUE rb_BGRA2GRAY(VALUE klass, VALUE image); +VALUE rb_RGBA2GRAY(VALUE klass, VALUE image); +VALUE rb_BGR2BGR565(VALUE klass, VALUE image); +VALUE rb_RGB2BGR565(VALUE klass, VALUE image); +VALUE rb_BGR5652BGR(VALUE klass, VALUE image); +VALUE rb_BGR5652RGB(VALUE klass, VALUE image); +VALUE rb_BGRA2BGR565(VALUE klass, VALUE image); +VALUE rb_RGBA2BGR565(VALUE klass, VALUE image); +VALUE rb_BGR5652BGRA(VALUE klass, VALUE image); +VALUE rb_BGR5652RGBA(VALUE klass, VALUE image); +VALUE rb_GRAY2BGR565(VALUE klass, VALUE image); +VALUE rb_BGR5652GRAY(VALUE klass, VALUE image); +VALUE rb_BGR2BGR555(VALUE klass, VALUE image); +VALUE rb_RGB2BGR555(VALUE klass, VALUE image); +VALUE rb_BGR5552BGR(VALUE klass, VALUE image); +VALUE rb_BGR5552RGB(VALUE klass, VALUE image); +VALUE rb_BGRA2BGR555(VALUE klass, VALUE image); +VALUE rb_RGBA2BGR555(VALUE klass, VALUE image); +VALUE rb_BGR5552BGRA(VALUE klass, VALUE image); +VALUE rb_BGR5552RGBA(VALUE klass, VALUE image); +VALUE rb_GRAY2BGR555(VALUE klass, VALUE image); +VALUE rb_BGR5552GRAY(VALUE klass, VALUE image); +VALUE rb_BGR2XYZ(VALUE klass, VALUE image); +VALUE rb_RGB2XYZ(VALUE klass, VALUE image); +VALUE rb_XYZ2BGR(VALUE klass, VALUE image); +VALUE rb_XYZ2RGB(VALUE klass, VALUE image); +VALUE rb_BGR2YCrCb(VALUE klass, VALUE image); +VALUE rb_RGB2YCrCb(VALUE klass, VALUE image); +VALUE rb_YCrCb2BGR(VALUE klass, VALUE image); +VALUE rb_YCrCb2RGB(VALUE klass, VALUE image); +VALUE rb_BGR2HSV(VALUE klass, VALUE image); +VALUE rb_RGB2HSV(VALUE klass, VALUE image); +VALUE rb_BGR2Lab(VALUE klass, VALUE image); +VALUE rb_RGB2Lab(VALUE klass, VALUE image); +VALUE rb_BayerBG2BGR(VALUE klass, VALUE image); +VALUE rb_BayerGB2BGR(VALUE klass, VALUE image); +VALUE rb_BayerRG2BGR(VALUE klass, VALUE image); +VALUE rb_BayerGR2BGR(VALUE klass, VALUE image); +VALUE rb_BayerBG2RGB(VALUE klass, VALUE image); +VALUE rb_BayerGB2RGB(VALUE klass, VALUE image); +VALUE rb_BayerRG2RGB(VALUE klass, VALUE image); +VALUE rb_BayerGR2RGB(VALUE klass, VALUE image); +VALUE rb_BGR2Luv(VALUE klass, VALUE image); +VALUE rb_RGB2Luv(VALUE klass, VALUE image); +VALUE rb_BGR2HLS(VALUE klass, VALUE image); +VALUE rb_RGB2HLS(VALUE klass, VALUE image); +VALUE rb_HSV2BGR(VALUE klass, VALUE image); +VALUE rb_HSV2RGB(VALUE klass, VALUE image); +VALUE rb_Lab2BGR(VALUE klass, VALUE image); +VALUE rb_Lab2RGB(VALUE klass, VALUE image); +VALUE rb_Luv2BGR(VALUE klass, VALUE image); +VALUE rb_Luv2RGB(VALUE klass, VALUE image); +VALUE rb_HLS2BGR(VALUE klass, VALUE image); +VALUE rb_HLS2RGB(VALUE klass, VALUE image); + +__NAMESPACE_END_OPENCV + +inline VALUE +extract_options_from_args_bang(VALUE ary) +{ + return (RARRAY(ary)->len > 0 && rb_obj_is_kind_of(RARRAY(ary)->ptr[RARRAY(ary)->len -1], rb_cHash)) ? rb_ary_pop(ary) : rb_hash_new(); +} + +/* +inline VALUE +assert_valid_keys(VALUE keys, VALUE valid_keys) +{ + VALUE unknown_keys = rb_funcall(keys, rb_intern("-"), 1, rb_funcall(valid_keys, rb_intern("flatten"), 0)); + if (NUM2INT(rb_funcall(unknown_keys, rb_intern("empty?"), 0)) != 0){ + rb_raise(rb_eArgError, "Unknown key(s): %s", + RSTRING(rb_funcall(unknown_keys, rb_intern("join"), 1, rb_str_new2(", ")))->ptr); + } + return Qnil; +} +*/ + /* +inline void +assert_valid_keys(VALUE options, int n, ...){ + va_list valid_keys; + if (!(n > 0)) {return;} + VALUE unknown_keys = rb_funcall(options, rb_intern("keys"), 0); + va_start(valid_keys, n); + for (int i = 0; i < n; i++) + rb_ary_delete(unknown_keys, ID2SYM(rb_intern(va_arg(valid_keys, char*)))); + if (RARRAY(unknown_keys)->len > 0) + rb_raise(rb_eArgError, "Unknown key(s): %s", + RSTRING(rb_funcall(unknown_keys, rb_intern("join"), 1, rb_str_new2(", ")))->ptr); + va_end(valid_keys); +} + +inline VALUE +validate_option(VALUE options, const *char key, char *ifnone, int n, ...){ + va_list valid_values; + VALUE value = rb_hash_aref(options, ID2SYM(rb_intern(key))); + if (!value || !(n > 0)) {return ifnone;} + va_start(valid_values, n); + for (int i = 0; i < n; i++){ + if (!strcmp(StringValueCStr(value), va_arg(valid_values, char*))){ + rb_warn("Option :%s value :%s does not defined. Default value :%s is used.", StringValueCStr(value), ); + return ifnone; + } + } + va_end(valid_values); + return value; +} + +#define OPTIONS(value, hash, key, default) value = ((value = rb_hash_aref(hash, ID2SYM(rb_intern(key)))) ? value : default) + */ +#endif // RUBY_OPENCV_H diff --git a/ext/point3dset.cpp b/ext/point3dset.cpp new file mode 100644 index 00000000..fe078f63 --- /dev/null +++ b/ext/point3dset.cpp @@ -0,0 +1,41 @@ +/************************************************************ + + point3dset.cpp - + + $Author: lsxi $ + + Copyright (C) 2008 Masakazu Yonekura + +************************************************************/ +#include"point3dset.h" +/* + * Document-class: OpenCV::Point3DSet + */ + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_POINT3D_SET + +VALUE module; + +VALUE +rb_module() +{ + return module; +} + +void +define_ruby_module() +{ + if(module) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + module = rb_define_module_under(opencv, "Point3DSet"); +} + +__NAMESPACE_END_POINT3D_SET +__NAMESPACE_END_OPENCV diff --git a/ext/point3dset.h b/ext/point3dset.h new file mode 100644 index 00000000..964cdc34 --- /dev/null +++ b/ext/point3dset.h @@ -0,0 +1,31 @@ +/************************************************************ + + point3dset.h - + + $Author: lsxi $ + + Copyright (C) 2008 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_POINT3DSET_H +#define RUBY_OPENCV_POINT3DSET_H + +#define __NAMESPACE_BEGIN_POINT3D_SET namespace mPoint3DSet{ +#define __NAMESPACE_END_POINT3D_SET } + +#include"opencv.h" + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_POINT3D_SET + +VALUE rb_module(); + +void define_ruby_module(); + +__NAMESPACE_END_POINT3D_SET + +#define POINT3D_SET_P(object) rb_obj_is_kind_of(object, cCvSeq::rb_class()) && CV_IS_SEQ_POINT3D_SET(CVSEQ(object)) + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_POINT3DSET_H diff --git a/ext/pointset.cpp b/ext/pointset.cpp new file mode 100644 index 00000000..e8072826 --- /dev/null +++ b/ext/pointset.cpp @@ -0,0 +1,238 @@ +/************************************************************ + + pointset.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#include"pointset.h" +/* + * Document-class: OpenCV::PointSet + */ + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_POINT_SET + +VALUE module; + +VALUE +rb_module() +{ + return module; +} + +void +define_ruby_module() +{ + if(module) + return; + /* + * opencv = rb_define_module("OpenCV"); + * + * note: this comment is used by rdoc. + */ + VALUE opencv = rb_module_opencv(); + module = rb_define_module_under(opencv, "PointSet"); + rb_define_method(module, "contour_area", RUBY_METHOD_FUNC(rb_contour_area), -1); + rb_define_method(module, "fit_ellipse", RUBY_METHOD_FUNC(rb_fit_ellipse), 0); + + rb_define_method(module, "convex_hull", RUBY_METHOD_FUNC(rb_convex_hull), -1); + rb_define_method(module, "check_contour_convexity", RUBY_METHOD_FUNC(rb_check_contour_convexity), 0); + rb_define_alias(module, "convexity?", "check_contour_convexity"); + rb_define_method(module, "convexity_defects", RUBY_METHOD_FUNC(rb_convexity_defects), -1); + rb_define_method(module, "min_area_rect", RUBY_METHOD_FUNC(rb_min_area_rect), 0); + rb_define_method(module, "min_enclosing_circle", RUBY_METHOD_FUNC(rb_min_enclosing_circle), 0); +} + +VALUE +rb_extend_object(VALUE self, VALUE object) +{ + CvSeq *seq = 0; + if(!rb_obj_is_kind_of(object, cCvSeq::rb_class())) + rb_raise(rb_eTypeError, "object is not %s.\n", rb_class2name(cCvSeq::rb_class())); + + if(!CV_IS_SEQ(seq)) + rb_raise(rb_eTypeError, "object is not sequence."); + return rb_call_super(1, &object); +} + +/* + * call-seq: + * contour_area -> float + * + * Calculates area of the whole contour or contour section. + * + * note: Orientation of the contour affects the area sign, thus the method may return negative result. + */ +VALUE +rb_contour_area(int argc, VALUE *argv, VALUE self) +{ + VALUE slice; + rb_scan_args(argc, argv, "01", &slice); + return rb_float_new(cvContourArea(CVARR(self), NIL_P(slice) ? CV_WHOLE_SEQ : VALUE_TO_CVSLICE(slice))); +} + +/* + * call-seq: + * fit_ellipse -> cvbox2d + * + * Return fits ellipse to set of 2D points. + */ +VALUE +rb_fit_ellipse(VALUE self) +{ + return cCvBox2D::new_object(cvFitEllipse2(CVARR(self))); +} + +/* + * call-seq: + * convex_hull([reverse = fasle]) -> cvcontour + * + * Finds convex hull of 2D point set using Sklansky's algorithm. + * + * reverse is desired orientation of convex hull. + * If reverse is false mean clockwise, otherwise counter clockwise. + */ +VALUE +rb_convex_hull(int argc, VALUE *argv, VALUE self) +{ + VALUE reverse, storage; + rb_scan_args(argc, argv, "01", &reverse); + storage = cCvMemStorage::new_object(); + CvSeq *hull = cvConvexHull2(CVSEQ(self), CVMEMSTORAGE(storage), TRUE_OR_FALSE(reverse, 0) ? CV_COUNTER_CLOCKWISE : CV_CLOCKWISE, 1); + if(CV_IS_SEQ_HOLE(CVSEQ(self))) + hull->flags |= CV_SEQ_FLAG_HOLE; + return cCvSeq::new_sequence(cCvContour::rb_class(), hull, cCvPoint::rb_class(), storage); +} + +/* + * call-seq: + * check_contour_convexity -> true or false + * + * Tests whether the input contour is convex or not. The contour must be simple, i.e. without self-intersections. + */ +VALUE +rb_check_contour_convexity(VALUE self) +{ + return cvCheckContourConvexity(CVARR(self)) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * convexity_defects([reverse = false]) -> cvseq(include CvConvexityDefect) + * + * Finds convexity defects of contour. + */ +VALUE +rb_convexity_defects(int argc, VALUE *argv, VALUE self) +{ + VALUE reverse, storage; + rb_scan_args(argc, argv, "01", &reverse); + storage = cCvMemStorage::new_object(); + CvSeq *hull, *convex; + hull = cvConvexHull2(CVSEQ(self), CVMEMSTORAGE(storage), TRUE_OR_FALSE(reverse, 0) ? CV_COUNTER_CLOCKWISE : CV_CLOCKWISE, 0); + convex = cvConvexityDefects(CVSEQ(self), hull, CVMEMSTORAGE(storage)); + return cCvSeq::new_sequence(cCvSeq::rb_class(), convex, cCvConvexityDefect::rb_class(), storage); +} + +/* + * call-seq: + * min_area_rect -> cvbox2d + * + * Finds circumscribed rectangle of minimal area for given 2D point set. + */ +VALUE +rb_min_area_rect(VALUE self) +{ + VALUE storage = cCvMemStorage::new_object(); + return cCvBox2D::new_object(cvMinAreaRect2(CVARR(self), CVMEMSTORAGE(storage))); +} + +/* + * call-seq: + * min_enclosing_circle -> cvcircle32f + * + * Finds circumscribed circle of minimal area for given 2D point set. + */ +VALUE +rb_min_enclosing_circle(VALUE self) +{ + VALUE circle = cCvCircle32f::rb_allocate(cCvCircle32f::rb_class()); + cvMinEnclosingCircle(CVARR(self), &CVCIRCLE32F(circle)->center, &CVCIRCLE32F(circle)->radius); + return circle; +} + +VALUE +rb_calc_pgh(VALUE self) +{ + /* not yet */ + return Qnil; +} + +__NAMESPACE_END_POINT_SET + +int +CVPOINTS_FROM_POINT_SET(VALUE object, CvPoint **pointset) +{ + VALUE storage; + CvSeq *seq = 0; + CvPoint2D32f p32; + if(rb_obj_is_kind_of(object, cCvSeq::rb_class())){ + if(CV_IS_SEQ_POINT_SET(CVSEQ(object))){ + *pointset = (CvPoint*)cvCvtSeqToArray(CVSEQ(object), cvAlloc(CVSEQ(object)->total * CVSEQ(object)->elem_size)); + return CVSEQ(object)->total; + }else{ + rb_raise(rb_eTypeError, "sequence is not contain %s or %s.", rb_class2name(cCvPoint::rb_class()), rb_class2name(cCvPoint2D32f::rb_class())); + } + }else if(rb_obj_is_kind_of(object, cCvMat::rb_class())){ + /* to do */ + rb_raise(rb_eNotImpError, "CvMat to CvSeq conversion not implemented."); + }else if(rb_obj_is_kind_of(object, rb_cArray)){ + *pointset = (CvPoint*)cvAlloc(RARRAY(object)->len * sizeof(CvPoint)); + for(int i = 0; i < RARRAY(object)->len; i++){ + (*pointset)[i].x = NUM2INT(rb_funcall(rb_ary_entry(object, i), rb_intern("x"), 0)); + (*pointset)[i].y = NUM2INT(rb_funcall(rb_ary_entry(object, i), rb_intern("y"), 0)); + } + return RARRAY(object)->len; + }else{ + rb_raise(rb_eTypeError, "Can't convert CvSeq(PointSet)."); + } +} + +CvSeq* +VALUE_TO_POINT_SET(VALUE object) +{ + CvSeq *seq = 0; + VALUE tmp, storage; + int length; + CvPoint2D32f p32; + if(rb_obj_is_kind_of(object, cCvSeq::rb_class())){ + seq = CVSEQ(object); + if(CV_IS_SEQ_POINT_SET(seq)){ + return seq; + }else{ + rb_raise(rb_eTypeError, "sequence is not contain %s or %s.", rb_class2name(cCvPoint::rb_class()), rb_class2name(cCvPoint2D32f::rb_class())); + } + }else if(rb_obj_is_kind_of(object, cCvMat::rb_class())){ + /* to do */ + rb_raise(rb_eNotImpError, "CvMat to CvSeq conversion not implemented."); + }else if(rb_obj_is_kind_of(object, rb_cArray)){ + //pointset = cCvSeq::new_sequence(cCvSeq::rb_class(), ) + length = RARRAY(object)->len; + storage = cCvMemStorage::new_object(); + seq = cvCreateSeq(CV_SEQ_POINT_SET, sizeof(CvSeq), sizeof(CvPoint), CVMEMSTORAGE(storage)); + for(int i = 0; i < RARRAY(object)->len; i++){ + p32.x = NUM2DBL(rb_funcall(rb_ary_entry(object, i), rb_intern("x"), 0)); + p32.y = NUM2DBL(rb_funcall(rb_ary_entry(object, i), rb_intern("y"), 0)); + cvSeqPush(seq, &p32); + } + tmp = cCvSeq::new_sequence(cCvSeq::rb_class(), seq, cCvPoint2D32f::rb_class(), storage); + return seq; + }else{ + rb_raise(rb_eTypeError, "Can't convert CvSeq(PointSet)."); + } +} + +__NAMESPACE_END_OPENCV diff --git a/ext/pointset.h b/ext/pointset.h new file mode 100644 index 00000000..4eebc4e3 --- /dev/null +++ b/ext/pointset.h @@ -0,0 +1,69 @@ +/************************************************************ + + pointset.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifndef RUBY_OPENCV_POINTSET_H +#define RUBY_OPENCV_POINTSET_H + +#define __NAMESPACE_BEGIN_POINT_SET namespace mPointSet{ +#define __NAMESPACE_END_POINT_SET } + +#include"opencv.h" + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_POINT_SET + +VALUE rb_module(); + +void define_ruby_module(); +VALUE rb_contour_area(int argc, VALUE *argv, VALUE self); +VALUE rb_fit_ellipse(VALUE self); +VALUE rb_fit_line(int argc, VALUE *argv, VALUE self); +VALUE rb_convex_hull(int argc, VALUE *argv, VALUE self); +VALUE rb_check_contour_convexity(VALUE self); +VALUE rb_convexity_defects(int argc, VALUE *argv, VALUE self); +VALUE rb_min_area_rect(VALUE self); +VALUE rb_min_enclosing_circle(VALUE self); +VALUE rb_calc_pgh(VALUE self); + +__NAMESPACE_END_POINT_SET + +#define POINT_SET_P(object) rb_obj_is_kind_of(object, cCvSeq::rb_class()) && CV_IS_SEQ_POINT_SET(CVSEQ(object)) + +/* +inline CvPoint* +POINTSET(VALUE object) +{ + CvPoint *pointset = (CvPoint*)cvAlloc(CVSEQ(object)->total * sizeof(CvPoint)); + cvCvtSeqToArray(CVSEQ(object), pointset, CV_WHOLE_SEQ); + if (cCvSeq::seqblock_class(CVSEQ(object)) == cCvPoint2D32f::rb_class()) { + for(int i =0; i < CVSEQ(object)->total; i++) + pointset[i] = cvPointFrom32f(((CvPoint2D32f*)pointset)[i]); + } + return pointset; +} + +inline CvPoint2D32f* +POINTSET2D32f(VALUE object) +{ + CvPoint2D32f *pointset = (CvPoint2D32f*)cvAlloc(CVSEQ(object)->total * sizeof(CvPoint2D32f)); + cvCvtSeqToArray(CVSEQ(object), pointset, CV_WHOLE_SEQ); + if (cCvSeq::seqblock_class(CVSEQ(object)) == cCvPoint::rb_class()) { + for(int i = 0; i < CVSEQ(object)->total; i++) + pointset[i] = cvPointTo32f(((CvPoint*)pointset)[i]); + } + return pointset; +} +*/ + +int CVPOINTS_FROM_POINT_SET(VALUE object, CvPoint **pointset); +CvSeq* VALUE_TO_POINT_SET(VALUE object); + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_POINTSET_H diff --git a/ext/trackbar.cpp b/ext/trackbar.cpp new file mode 100644 index 00000000..4d4e2eb9 --- /dev/null +++ b/ext/trackbar.cpp @@ -0,0 +1,122 @@ +/************************************************************ + + trackbar.cpp - + + $Author: lsxi $ + + Copyright (C) 2005 Masakazu Yonekura + +************************************************************/ +#ifdef HAVE_CALLBACK_H + +#include"trackbar.h" +/* + * Document-class: OpenCV::GUI::Trackbar + * + * Simple Trackbar wedget. OpenCV::GUI::Window can treat trackbar. + * Trackbar can treat only positive-integer value. + */ + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_GUI +__NAMESPACE_BEGIN_TRACKBAR + +VALUE rb_klass; + +VALUE rb_class(){ + return rb_klass; +} + +void define_ruby_class(){ + if(rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * GUI = rb_define_module_under(opencv, "GUI"); + * + * note: this comment is used by rdoc. + */ + VALUE GUI = rb_module_GUI(); + rb_klass = rb_define_class_under(GUI, "Trackbar", rb_cObject); + rb_define_alloc_func(rb_klass, rb_allocate); + rb_define_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); + rb_define_method(rb_klass, "name", RUBY_METHOD_FUNC(rb_name), 0); + rb_define_method(rb_klass, "max", RUBY_METHOD_FUNC(rb_max), 0); + rb_define_method(rb_klass, "value", RUBY_METHOD_FUNC(rb_value), 0); + rb_define_method(rb_klass, "value=", RUBY_METHOD_FUNC(rb_set_value), 1); +} + +VALUE rb_allocate(VALUE klass){ + Trackbar *ptr; + return Data_Make_Struct(klass, Trackbar, mark, free, ptr); +} + +void mark(void *ptr){ + rb_gc_mark(((Trackbar*)ptr)->block); +} + +void free(void *ptr){ + //::free(((Trackbar*)ptr)->name); + ::free(ptr); +} + +/* + * call-seq: + * new(name,maxval[,val],&block) + * new(name,maxval[,val]){|value| ... } + * + * Create new Trackbar. + * name should be String. + * maxval and val should be Fixnum. + * When Trackbar adjuster changed, block will be called. + */ +VALUE rb_initialize(int argc, VALUE *argv, VALUE self){ + VALUE name, maxval, val, block; + rb_scan_args(argc, argv, "21&", &name, &maxval, &val, &block); + if(NIL_P(block)){rb_raise(rb_eArgError, "block not given.");} + Check_Type(name, T_STRING); + Trackbar *trackbar = TRACKBAR(self); + trackbar->name = strcpy(ALLOC_N(char, RSTRING(name)->len), StringValueCStr(name)); + trackbar->maxval = NUM2INT(maxval); + trackbar->val = IF_INT(val, 0); + trackbar->block = block; + return self; +} + +/* + * Return trackbar name. + */ +VALUE rb_name(VALUE self){ + return rb_str_new2(TRACKBAR(self)->name); +} + +/* + * Return the maximum value that can be taken this trackbar. + */ +VALUE rb_max(VALUE self){ + return INT2FIX(TRACKBAR(self)->maxval); +} + +/* + * Return the value of this trackbar. + */ +VALUE rb_value(VALUE self){ + return INT2FIX(TRACKBAR(self)->val); +} + +/* + * call-seq: + * value = val + * + * Set trackbar value. + */ +VALUE rb_set_value(VALUE self, VALUE val){ + TRACKBAR(self)->val = NUM2INT(val); + return self; +} + +__NAMESPACE_END_TRACKBAR +__NAMESPACE_END_GUI +__NAMESPACE_END_OPENCV + +#endif // HAVE_CALLBACK_H diff --git a/ext/trackbar.h b/ext/trackbar.h new file mode 100644 index 00000000..f404a714 --- /dev/null +++ b/ext/trackbar.h @@ -0,0 +1,65 @@ +/************************************************************ + + trackbar.h - + + $Author: lsxi $ + + Copyright (C) 2005 Masakazu Yonekura + +************************************************************/ +#ifdef HAVE_CALLBACK_H + +#ifndef RUBY_OPENCV_GUI_H +#include "gui.h" +#endif + +#ifndef RUBY_OPENCV_GUI_TRACKBAR_H +#define RUBY_OPENCV_GUI_TRACKBAR_H + +#include"opencv.h" + +#define __NAMESPACE_BEGIN_TRACKBAR namespace cTrackbar{ +#define __NAMESPACE_END_TRACKBAR } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_GUI + +typedef struct Trackbar{ + char *name; + int maxval; + int val; + VALUE block; +}Trackbar; + +__NAMESPACE_BEGIN_TRACKBAR + +VALUE rb_class(); + +void define_ruby_class(); +VALUE rb_allocate(VALUE klass); + +void mark(void *ptr); +void free(void *ptr); + +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); +VALUE rb_name(VALUE self); +VALUE rb_max(VALUE self); +VALUE rb_value(VALUE self); +VALUE rb_set_value(VALUE self, VALUE val); + +__NAMESPACE_END_TRACKBAR + + +inline Trackbar *TRACKBAR(VALUE object){ + Trackbar *ptr; + Data_Get_Struct(object, Trackbar, ptr); + return ptr; +} + +__NAMESPACE_END_GUI + +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_GUI_TRACKBAR_H + +#endif // HAVE_CALLBACK_H diff --git a/ext/window.cpp b/ext/window.cpp new file mode 100644 index 00000000..cff0ae86 --- /dev/null +++ b/ext/window.cpp @@ -0,0 +1,368 @@ +/************************************************************ + + window.cpp - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifdef HAVE_CALLBACK_H + +#include "window.h" +/* + * Document-class: OpenCV::GUI::Window + * + * Simple Window wedget. Window can show image(CvMat/IplImage). + * + * view image sample: + * image = OpenCV::IplImage::load("opencv.bmp") #=> load image + * window = OpenCV::GUI::Window.new("simple viewer")#=> create new window named "simaple viewer" + * window.show(image) #=> show image + */ +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_GUI +__NAMESPACE_BEGIN_WINDOW + +const char* +GET_WINDOW_NAME(VALUE object) +{ + void *handle = DATA_PTR(object); + if (!handle) + rb_raise(rb_eStandardError, "window handle error"); + const char *window_name = cvGetWindowName(handle); + return window_name; +} + +st_table *windows = st_init_numtable(); + +VALUE rb_klass; + +VALUE +rb_class() +{ + return rb_klass; +} + +void +define_ruby_class() +{ + if (rb_klass) + return; + /* + * opencv = rb_define_module("OpenCV"); + * GUI = rb_define_module_under(opencv, "GUI"); + * + * note: this comment is used by rdoc. + */ + VALUE GUI = rb_module_GUI(); + rb_klass = rb_define_class_under(GUI, "Window", rb_cObject); + rb_define_singleton_method(rb_klass, "[]", RUBY_METHOD_FUNC(rb_aref), 1); + rb_define_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); + rb_define_method(rb_klass, "alive?", RUBY_METHOD_FUNC(rb_alive_q), 0); + rb_define_method(rb_klass, "destroy", RUBY_METHOD_FUNC(rb_destroy), 0); + rb_define_singleton_method(rb_klass, "destroy_all", RUBY_METHOD_FUNC(rb_destroy_all), 0); + rb_define_method(rb_klass, "resize", RUBY_METHOD_FUNC(rb_resize), -1); + rb_define_method(rb_klass, "move", RUBY_METHOD_FUNC(rb_move), -1); + rb_define_method(rb_klass, "show_image", RUBY_METHOD_FUNC(rb_show_image), 1); + rb_define_alias(rb_klass, "show", "show_image"); + rb_define_method(rb_klass, "set_trackbar", RUBY_METHOD_FUNC(rb_set_trackbar), -1); + rb_define_method(rb_klass, "set_mouse_callback", RUBY_METHOD_FUNC(rb_set_mouse_callback), 0); + rb_define_alias(rb_klass, "on_mouse", "set_mouse_callback"); +} + +VALUE +rb_allocate(VALUE klass) +{ + return Data_Wrap_Struct(klass, mark, free, 0); +} + +void +mark(void *ptr) +{ + st_table *holder; + if (st_lookup(windows, (st_data_t)ptr, (st_data_t*)&holder)) { + st_foreach(holder, (int (*)(ANYARGS))each_protect, 0); + } +} + +VALUE +each_protect(VALUE key, VALUE value) +{ + rb_gc_mark(value); + return ST_CONTINUE; +} + +void +free(void *ptr) +{ + cvFree(&ptr); +} + +/* + * call-seq: + * [name] + * + * Return window named name if exist, otherwise nil. + */ +VALUE +rb_aref(VALUE klass, VALUE name) +{ + VALUE window; + Check_Type(name, T_STRING); + void *handle = cvGetWindowHandle(StringValueCStr(name)); + st_table *holder; + if (st_lookup(windows, (st_data_t)handle, (st_data_t*)&holder) && + st_lookup(holder, 0, (st_data_t*)&window)) { + return window; + } + return Qnil; +} + +/* + * call-seq: + * new(name[,autosize]) + * + * Create new window named name. + * If autoresize is true(default), window size automatically resize when image given. + */ +VALUE +rb_initialize(int argc, VALUE *argv, VALUE self) +{ + VALUE name, autosize; + rb_scan_args(argc, argv, "11", &name, &autosize); + Check_Type(name, T_STRING); + int mode; + if (argc < 2) + mode = CV_WINDOW_AUTOSIZE; + else{ + switch (TYPE(autosize)) { + case T_TRUE: + mode = CV_WINDOW_AUTOSIZE; + break; + case T_FALSE: + mode = 0; + break; + default: + rb_raise(rb_eTypeError, "argument 2 (auto-size) should be true or false."); + } + } + cvNamedWindow(StringValueCStr(name), mode); + void *handle = cvGetWindowHandle(StringValueCStr(name)); + if (st_lookup(windows, (st_data_t)handle, 0)) { + rb_raise(rb_eStandardError, "window name should be unique."); + } + DATA_PTR(self) = handle; + st_table *holder = st_init_numtable(); + st_insert(holder, (st_data_t)0, (st_data_t)self); + st_insert(windows, (st_data_t)handle, (st_data_t)holder); + return self; +} + +/* + * Return alive status of window. Return true if alive, otherwise return false. + */ +VALUE +rb_alive_q(VALUE self) +{ + if (st_lookup(windows, (st_data_t)DATA_PTR(self), 0)) { + return Qtrue; + } + return Qfalse; +} + +/* + * Destroys a window. alive status of window be false. + */ +VALUE +rb_destroy(VALUE self) +{ + void *handle = DATA_PTR(self); + st_table *holder; + if (st_delete(windows, (st_data_t*)&handle, (st_data_t*)&holder)) { + st_free_table(holder); + } + cvDestroyWindow(GET_WINDOW_NAME(self)); + return self; +} + +/* + * Destorys all the windows. + */ +VALUE +rb_destroy_all(VALUE klass) +{ + st_free_table(windows); + windows = st_init_numtable(); + cvDestroyAllWindows(); + return Qnil; +} + +/* + * call-seq: + * resize(size) + * resize(width, height) + * + * Set window size. + */ +VALUE +rb_resize(int argc, VALUE *argv, VALUE self) +{ + CvSize size; + switch (argc) { + case 1: + size = VALUE_TO_CVSIZE(argv[0]); + break; + case 2: + size = cvSize(FIX2INT(argv[0]), FIX2INT(argv[1])); + break; + default: + rb_raise(rb_eArgError, "wrong number of arguments (1 or 2)"); + } + cvResizeWindow(GET_WINDOW_NAME(self), size.width, size.height); + return self; +} + +/* + * call-seq: + * move(point) + * move(x, y) + * + * Set window position. + */ +VALUE +rb_move(int argc, VALUE *argv, VALUE self) +{ + CvPoint point; + switch (argc) { + case 1: + point = VALUE_TO_CVPOINT(argv[0]); + break; + case 2: + point = cvPoint(FIX2INT(argv[0]), FIX2INT(argv[1])); + break; + default: + rb_raise(rb_eArgError, "wrong number of arguments (1 or 2)"); + } + cvMoveWindow(GET_WINDOW_NAME(self), point.x, point.y); + return self; +} + +/* + * call-seq: + * show_image(image) + * + * Show the image. If the window was created with autosize = true then the image is shown + * with its original size, otherwize the image is scaled to fit the window. + */ +VALUE +rb_show_image(VALUE self, VALUE image) +{ + if (!rb_obj_is_kind_of(image, cCvMat::rb_class())) { + rb_raise(rb_eTypeError, "argument should be %s.", rb_class2name(cCvMat::rb_class())); + } + cvShowImage(GET_WINDOW_NAME(self), CVARR(image)); + st_table *holder; + if (st_lookup(windows, (st_data_t)DATA_PTR(self), (st_data_t*)&holder)) { + st_insert(holder, cCvMat::rb_class(), image); + return self; + }else + rb_raise(rb_eFatal, "invalid window operation."); + return self; +} + +/* + * call-seq: + * set_trackbar(trackbar) + * set_trackbar(name,maxval[,val],&block) + * set_trackbar(name,maxval[,val]){|value| ... } + * + * Create Trackbar on this window. Return new Trackbar. + * see Trackbar.new + */ +VALUE +rb_set_trackbar(int argc, VALUE *argv, VALUE self) +{ + VALUE instance; + if (argc == 1 && rb_obj_is_kind_of(argv[0], cTrackbar::rb_class())) { + instance = argv[0]; + }else{ + instance = cTrackbar::rb_initialize(argc, argv, cTrackbar::rb_allocate(cTrackbar::rb_class())); + } + Trackbar *trackbar = TRACKBAR(instance); + void *callback = (void *)alloc_callback(&trackbar_callback, trackbar->block); + cvCreateTrackbar(trackbar->name, GET_WINDOW_NAME(self), &trackbar->val, trackbar->maxval, (CvTrackbarCallback)callback); + st_table *holder; + if (st_lookup(windows, (st_data_t)DATA_PTR(self), (st_data_t*)&holder)) { + st_insert(holder, (st_data_t)&trackbar->name, (st_data_t)instance); + } + return instance; +} + +/* + * call-seq: + * set_mouse_callback(&block) + * set_mouse_callback{|| ... } + * + * Set mouse callback. + * When the mouse is operated on the window, block will be called. + * Return Proc object. + * block given mouse event object, see GUI::Window::MouseEvent + * + * e.g. display mouse event on console. + * window = OpenCV::GUI::Window.new "sample window" + * image = OpenCV::IplImage::load "sample.png" + * window.show(image) + * window.set_mouse_callback{|mouse| + * e = "#{mouse.x}, #{mouse.y} : #{mouse.event} : " + * e << "" if mouse.left_button? + * e << "" if mouse.right_button? + * e << "" if mouse.middle_button? + * e << "[CTRL]" if mouse.ctrl_key? + * e << "[SHIFT]" if mouse.shift_key? + * e << "[ALT]" if mouse.alt_key? + * puts e + * } + * OpenCV::GUI::wait_key + */ +VALUE +rb_set_mouse_callback(VALUE self) +{ + VALUE block = rb_block_given_p() ? rb_block_proc() : 0; + if (!block) {rb_raise(rb_eArgError, "block not given.");} + void *callback = (void *)alloc_callback(&mouse_callback, block); + cvSetMouseCallback(GET_WINDOW_NAME(self), (CvMouseCallback)callback); + st_table *holder; + if (st_lookup(windows, (st_data_t)DATA_PTR(self), (st_data_t*)&holder)) { + st_insert(holder, rb_cProc, block); + }else{ + rb_raise(rb_eStandardError, "window is destroied."); + } + return block; +} + +void +trackbar_callback(VALUE block, va_alist ap) +{ + va_start_void(ap); + rb_funcall(block, rb_intern("call"), 1, INT2FIX(va_arg_int(ap))); + va_return_void(ap); +} + +void +mouse_callback(VALUE block, va_alist ap) +{ + va_start_void(ap); + //VALUE ary = rb_ary_new2(4); + //for (int i = 0; i < 4; i++) + // rb_ary_store(ary, i, INT2FIX(va_arg_int(ap))); + //rb_apply(block, rb_intern("call"), ary); + rb_funcall(block, rb_intern("call"), 1, cMouseEvent::new_object(va_arg_int(ap),va_arg_int(ap),va_arg_int(ap),va_arg_int(ap))); + va_return_void(ap); +} + +__NAMESPACE_END_WINDOW +__NAMESPACE_END_GUI +__NAMESPACE_END_OPENCV + +#endif // HAVE_CALLBACK_H diff --git a/ext/window.h b/ext/window.h new file mode 100644 index 00000000..6b72cbeb --- /dev/null +++ b/ext/window.h @@ -0,0 +1,56 @@ +/************************************************************ + + window.h - + + $Author: lsxi $ + + Copyright (C) 2005-2006 Masakazu Yonekura + +************************************************************/ +#ifdef HAVE_CALLBACK_H + +#ifndef RUBY_OPENCV_GUI_H +#include "gui.h" +#endif + +#ifndef RUBY_OPENCV_GUI_WINDOW_H +#define RUBY_OPENCV_GUI_WINDOW_H + +#include "opencv.h" +#define __NAMESPACE_BEGIN_WINDOW namespace cWindow{ +#define __NAMESPACE_END_WINDOW } + +__NAMESPACE_BEGIN_OPENCV +__NAMESPACE_BEGIN_GUI +__NAMESPACE_BEGIN_WINDOW + +void define_ruby_class(); + +VALUE rb_allocate(VALUE klass); + +void mark(void *ptr); +VALUE each_protect(VALUE key, VALUE value); +//VALUE each_protect(void *key, VALUE value); +void free(void *ptr); + +VALUE rb_aref(VALUE klass, VALUE name); +VALUE rb_initialize(int argc, VALUE *argv, VALUE self); +VALUE rb_alive_q(VALUE self); +VALUE rb_destroy(VALUE self); +VALUE rb_destroy_all(VALUE klass); +VALUE rb_resize(int argc, VALUE *argv, VALUE self); +VALUE rb_move(int argc, VALUE *argv, VALUE self); +VALUE rb_show_image(VALUE self, VALUE image); +VALUE rb_set_trackbar(int argc, VALUE *argv, VALUE self); +VALUE rb_set_mouse_callback(VALUE self); + +void trackbar_callback(VALUE block, va_alist ap); +void mouse_callback(VALUE block, va_alist ap); + +__NAMESPACE_END_WINDOW +__NAMESPACE_END_GUI +__NAMESPACE_END_OPENCV + +#endif // RUBY_OPENCV_GUI_WINDOW_H + +#endif // HAVE_CALLBACK_H diff --git a/images/CvMat_sobel.png b/images/CvMat_sobel.png new file mode 100644 index 00000000..91d64e97 --- /dev/null +++ b/images/CvMat_sobel.png @@ -0,0 +1,2 @@ +‰PNG + diff --git a/images/CvMat_sub_rect.png b/images/CvMat_sub_rect.png new file mode 100644 index 00000000..91d64e97 --- /dev/null +++ b/images/CvMat_sub_rect.png @@ -0,0 +1,2 @@ +‰PNG + diff --git a/images/CvSeq_relationmap.png b/images/CvSeq_relationmap.png new file mode 100644 index 00000000..91d64e97 --- /dev/null +++ b/images/CvSeq_relationmap.png @@ -0,0 +1,2 @@ +‰PNG + diff --git a/images/face_detect_from_lena.jpg b/images/face_detect_from_lena.jpg new file mode 100644 index 00000000..6255ad5e --- /dev/null +++ b/images/face_detect_from_lena.jpg @@ -0,0 +1 @@ +ÿØÿà \ No newline at end of file diff --git a/lib/opencv.rb b/lib/opencv.rb new file mode 100755 index 00000000..61058dec --- /dev/null +++ b/lib/opencv.rb @@ -0,0 +1,3 @@ +require (File.dirname(__FILE__) + '/version') +require 'opencv.so' + diff --git a/lib/version.rb b/lib/version.rb new file mode 100755 index 00000000..54f73d40 --- /dev/null +++ b/lib/version.rb @@ -0,0 +1,3 @@ +module OpenCV + VERSION = '0.0.6' +end diff --git a/metadata b/metadata new file mode 100644 index 00000000..c005e75a --- /dev/null +++ b/metadata @@ -0,0 +1,191 @@ +--- !ruby/object:Gem::Specification +name: opencv +version: !ruby/object:Gem::Version + version: 0.0.6 +platform: ruby +authors: +- Masakazu Yonekura +- lsxi +autorequire: +bindir: bin +cert_chain: [] + +date: 2008-06-29 00:00:00 +09:00 +default_executable: +dependencies: +- !ruby/object:Gem::Dependency + name: hoe + version_requirement: + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: "0" + version: +- !ruby/object:Gem::Dependency + name: hoe + version_requirement: + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: 1.6.0 + version: +description: OpenCV wrapper for Ruby +email: +- masakazu.yonekura@gmail.com +executables: [] + +extensions: +- ext/extconf.rb +extra_rdoc_files: +- History.txt +- Manifest.txt +- README.txt +- License.txt +files: +- History.txt +- Manifest.txt +- README.txt +- License.txt +- Rakefile +- examples/convexhull.rb +- examples/face_detect.rb +- examples/houghcircle.rb +- examples/inpaint.png +- examples/inpaint.rb +- examples/paint.rb +- examples/snake.rb +- examples/stuff.jpg +- ext/curve.cpp +- ext/curve.h +- ext/cvavgcomp.cpp +- ext/cvavgcomp.h +- ext/cvbox2d.cpp +- ext/cvbox2d.h +- ext/cvcapture.cpp +- ext/cvcapture.h +- ext/cvchain.cpp +- ext/cvchain.h +- ext/cvchaincode.cpp +- ext/cvchaincode.h +- ext/cvcircle32f.cpp +- ext/cvcircle32f.h +- ext/cvcondensation.cpp +- ext/cvcondensation.h +- ext/cvconnectedcomp.cpp +- ext/cvconnectedcomp.h +- ext/cvcontour.cpp +- ext/cvcontour.h +- ext/cvcontourtree.cpp +- ext/cvcontourtree.h +- ext/cvconvexitydefect.cpp +- ext/cvconvexitydefect.h +- ext/cverror.cpp +- ext/cverror.h +- ext/cvfont.cpp +- ext/cvfont.h +- ext/cvhaarclassifiercascade.cpp +- ext/cvhaarclassifiercascade.h +- ext/cvhistogram.cpp +- ext/cvhistogram.h +- ext/cvindex.cpp +- ext/cvindex.h +- ext/cvline.cpp +- ext/cvline.h +- ext/cvmat.cpp +- ext/cvmat.h +- ext/cvmatnd.cpp +- ext/cvmatnd.h +- ext/cvmemstorage.cpp +- ext/cvmemstorage.h +- ext/cvmoments.cpp +- ext/cvmoments.h +- ext/cvpoint.cpp +- ext/cvpoint.h +- ext/cvpoint2d32f.cpp +- ext/cvpoint2d32f.h +- ext/cvpoint3d32f.cpp +- ext/cvpoint3d32f.h +- ext/cvrect.cpp +- ext/cvrect.h +- ext/cvscalar.cpp +- ext/cvscalar.h +- ext/cvseq.cpp +- ext/cvseq.h +- ext/cvset.cpp +- ext/cvset.h +- ext/cvsize.cpp +- ext/cvsize.h +- ext/cvsize2d32f.cpp +- ext/cvsize2d32f.h +- ext/cvslice.cpp +- ext/cvslice.h +- ext/cvsparsemat.cpp +- ext/cvsparsemat.h +- ext/cvtermcriteria.cpp +- ext/cvtermcriteria.h +- ext/cvtwopoints.cpp +- ext/cvtwopoints.h +- ext/cvvector.cpp +- ext/cvvector.h +- ext/cvvideowriter.cpp +- ext/cvvideowriter.h +- ext/extconf.rb +- ext/gui.cpp +- ext/gui.h +- ext/iplconvkernel.cpp +- ext/iplconvkernel.h +- ext/iplimage.cpp +- ext/iplimage.h +- ext/mouseevent.cpp +- ext/mouseevent.h +- ext/opencv.cpp +- ext/opencv.h +- ext/point3dset.cpp +- ext/point3dset.h +- ext/pointset.cpp +- ext/pointset.h +- ext/trackbar.cpp +- ext/trackbar.h +- ext/window.cpp +- ext/window.h +- images/CvMat_sobel.png +- images/CvMat_sub_rect.png +- images/CvSeq_relationmap.png +- images/face_detect_from_lena.jpg +- lib/opencv.rb +- lib/version.rb +- setup/setup.cygwin.rb +- setup/setup.mingw.rb +- setup/setup.mswin32.rb +has_rdoc: true +homepage: http://blueruby.mydns.jp/opencv +post_install_message: +rdoc_options: +- --main +- README.txt +require_paths: +- lib +- ext +required_ruby_version: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: "0" + version: +required_rubygems_version: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: "0" + version: +requirements: [] + +rubyforge_project: opencv +rubygems_version: 1.0.1 +signing_key: +specification_version: 2 +summary: OpenCV wrapper for Ruby. +test_files: +- test/test_opencv.rb diff --git a/setup/setup.cygwin.rb b/setup/setup.cygwin.rb new file mode 100755 index 00000000..a5efcdd2 --- /dev/null +++ b/setup/setup.cygwin.rb @@ -0,0 +1,120 @@ +#!/usr/env ruby +# Create OpenCV cygwin library from Windows DLLs. +require 'pathname' +opencv_installed_dir = "C:/Program\ Files/OpenCV" +install_bindir = "/usr/local/bin" +install_libdir = "/usr/local/lib" +install_includedir = "/usr/local/include/opencv" + +STDOUT.sync = true +puts ">> Please tell me path installed OpenCV." +puts ">> note: default is #{opencv_installed_dir}" +print "opencv installed directory : " +input = gets.chomp! +opencv_installed_dir = input unless input.empty? +opencv_installed_dir = `cygpath -u "#{opencv_installed_dir}"`.chomp! + +puts "[step.1]" +puts ">> Checking directory..." +basedir = Pathname(opencv_installed_dir) +print ">> basedir #{basedir}" +raise "error: directory #{basedir} does not exist." unless File.directory?(basedir) +bindir = basedir + 'bin' +puts "...ok" +print ">> bindir #{bindir}" +raise "error: directory #{bindir} does not exist." unless File.directory?(bindir) +puts "...ok" +libdir = basedir + 'lib' +print ">> libdir #{libdir}" +raise "error: directory #{libdir} does not exist." unless File.directory?(libdir) +puts "...ok" + +puts "[step.2]" +puts ">> Searching OpenCV Windows DLLs..." +Dir.foreach(bindir){|filename| + next unless filename =~ /\d\d\d\.dll\Z/ + dllname = filename.scan(/(\D+)\d+\.dll/) + `echo EXPORTS > #{dllname}.def` + `nm "#{libdir + "#{dllname}.lib"}" | grep ' T _' | sed 's/.* T _//' >> #{dllname}.def` + `dlltool --def #{dllname}.def --dllname "#{filename}" --output-lib lib#{dllname}.dll.a` + `rm #{dllname}.def` + puts ">> Create lib#{dllname}.dll.a success." +} + +puts "[step.3]" +puts ">> Move libs to target directory" +puts ">> note: default is #{install_libdir}" +print "target directory : " +input = gets.chomp! +install_libdir = input unless input.empty? +if File.exist?(install_libdir) + raise "#{install_libdir} is exist. but it is not directory." unless File.directory?(install_libdir) +else + print "Directory #{install_libdir} does not exist. Create it? [y/n]:" + raise "Please create directory #{install_libdir}" unless gets.chomp! == 'y' + `mkdir -p #{install_libdir}` +end +`mv *.dll.a #{install_libdir}` + + +puts "[step.4]" +puts ">> Copy OpenCV header files(*.h / *.hpp) to target directory" +puts ">> note: default is #{install_includedir}" +print "target directory : " +input = gets.chomp! +install_includedir = input unless input.empty? +if File.exist?(install_includedir) + raise "#{install_includedir} is exist. but it is not directory." unless File.directory?(install_libdir) +else + print "Directory #{install_includedir} does not exist. Create it? [y/n]:" + raise "Please create directory #{install_includedir}" unless gets.chomp! == 'y' + `mkdir -p #{install_includedir}` +end +puts ">> Copying header files..." +[ + "cxcore/include", + "cv/include", + "cvaux/include", + "ml/include", + "otherlibs/cvcam/include", + "otherlibs/highgui" +].each{|i| + if File.directory?(basedir + i) + Dir.foreach(basedir + i){|filename| + next unless (File.extname(filename) == ".h" || File.extname(filename) == ".hpp") + `cp "#{basedir + i + filename}" #{install_includedir}` + } + end +} + + +puts "[step.5]" +puts ">> Copy OpenCV dll files (*.dll) to target directory" +puts ">> note: default is #{install_bindir}" +print "target directory : " +input = gets.chomp! +install_bindir = input unless input.empty? +if File.exist?(install_includedir) + raise "#{install_bindir} is exist. but it is not directory." unless File.directory?(install_libdir) +else + print "Directory #{install_bindir} does not exist. Create it? [y/n]:" + raise "Please create directory #{install_bindir}" unless gets.chomp! == 'y' + `mkdir -p #{install_bindir}` +end +puts ">> Copying dll files..." +Dir.foreach(bindir){|filename| + next if File.extname(filename) != ".dll" + `cp "#{bindir + filename}" #{install_bindir}` +} + +puts "Congratulation! Setup complete." +puts <> Please tell me path installed OpenCV." +puts ">> note: default is #{opencv_installed_dir}" +print "opencv installed directory : " +input = gets.chomp! +opencv_installed_dir = input unless input.empty? +#opencv_installed_dir = opencv_installed_dir.chomp! + +puts "[step.1]" +puts ">> Checking directory..." +basedir = Pathname(opencv_installed_dir) +print ">> basedir #{basedir}" +raise "error: directory #{basedir} does not exist." unless File.directory?(basedir) +bindir = basedir + 'bin' +puts "...ok" +print ">> bindir #{bindir}" +raise "error: directory #{bindir} does not exist." unless File.directory?(bindir) +puts "...ok" +libdir = basedir + 'lib' +print ">> libdir #{libdir}" +raise "error: directory #{libdir} does not exist." unless File.directory?(libdir) +puts "...ok" + +puts "[step.2]" +puts ">> Searching OpenCV Windows DLLs..." +Dir.foreach(bindir){|filename| + next unless filename =~ /\d\d\d\.dll\Z/ + dllname = filename.scan(/(\D+)\d+\.dll/) + `echo EXPORTS > #{dllname}.def` + `nm "#{libdir + "#{dllname}.lib"}" | grep ' T _' | sed 's/.* T _//' >> #{dllname}.def` + `dlltool --def #{dllname}.def --dllname "#{filename}" --output-lib #{dllname}.lib` + `rm #{dllname}.def` + puts ">> Create #{dllname}.lib success." +} + +puts "[step.3]" +puts ">> Move libs to target directory" +puts ">> note: default is #{install_libdir}" +print "target directory : " +input = gets.chomp! +install_libdir = input unless input.empty? +if File.exist?(install_libdir) + raise "#{install_libdir} is exist. but it is not directory." unless File.directory?(install_libdir) +else + print "Directory #{install_libdir} does not exist. Create it? [y/n]:" + raise "Please create directory #{install_libdir}" unless gets.chomp! == 'y' + `mkdir -p #{install_libdir}` +end +`mv *.lib #{install_libdir}` + + +puts "[step.4]" +puts ">> Copy OpenCV header files(*.h / *.hpp) to target directory" +puts ">> note: default is #{install_includedir}" +print "target directory : " +input = gets.chomp! +install_includedir = input unless input.empty? +if File.exist?(install_includedir) + raise "#{install_includedir} is exist. but it is not directory." unless File.directory?(install_libdir) +else + print "Directory #{install_includedir} does not exist. Create it? [y/n]:" + raise "Please create directory #{install_includedir}" unless gets.chomp! == 'y' + `mkdir -p #{install_includedir}` +end +puts ">> Copying header files..." +[ + "cxcore/include", + "cv/include", + "cvaux/include", + "ml/include", + "otherlibs/cvcam/include", + "otherlibs/highgui" +].each{|i| + if File.directory?(basedir + i) + Dir.foreach(basedir + i){|filename| + next unless (File.extname(filename) == ".h" || File.extname(filename) == ".hpp") + `cp "#{basedir + i + filename}" #{install_includedir}` + } + end +} + +puts "Congratulation! Setup complete." +puts <> Please tell me CPU archtecture." +archs = ["x86", "amd64", "ia64"] +archs.each_with_index{|v, i| + puts "[#{i}].#{v}" +} +print "CPU archtecture : " +input = gets.chomp!.to_i +arch = archs[input] +puts "you choose #{arch}" + +puts ">> Please tell me path installed OpenCV." +puts ">> note: default is #{opencv_installed_dir}" +print "opencv installed directory : " +input = gets.chomp! +opencv_installed_dir = input unless input.empty? + +puts "[step.1]" +puts ">> Checking directory..." +basedir = Pathname(opencv_installed_dir) +print ">> basedir #{basedir}" +raise "error: directory #{basedir} does not exist." unless File.directory?(basedir) +bindir = basedir + 'bin' +puts "...ok" +print ">> bindir #{bindir}" +raise "error: directory #{bindir} does not exist." unless File.directory?(bindir) +puts "...ok" +libdir = basedir + 'lib' +print ">> libdir #{libdir}" +raise "error: directory #{libdir} does not exist." unless File.directory?(libdir) +puts "...ok" + +puts "[step.2]" +puts ">> Searching OpenCV Windows DLLs..." +Dir.foreach(bindir){|filename| + next unless filename =~ /\d\d\d\.dll\Z/ + dllname = filename.scan(/(\D+)\d+\.dll/) + open("#{dllname}.def", "w"){|def_file| + def_file.puts "LIBRARY #{filename}" + def_file.puts "EXPORTS" + `dumpbin.exe /exports "#{bindir + filename}"`.split("\n").each{|line| + f = line.scan(/\A\s+\d+\s+[0-9A-F]+\s+[0-9A-F]+\s+(.*)/).first + def_file.puts f if f + } + } + `lib.exe /def:#{dllname}.def /machine:#{arch}` + File.unlink("#{dllname}.def") + puts ">> Create #{dllname}.lib success." +} + +puts "[step.3]" +puts ">> Move libs to target directory" +puts ">> note: default is #{install_libdir}" +print "target directory : " +input = gets.chomp! +install_libdir = input unless input.empty? +if File.exist?(install_libdir) + raise "#{install_libdir} is exist. but it is not directory." unless File.directory?(install_libdir) +else + print "Directory #{install_libdir} does not exist. Create it? [y/n]:" + raise "Please create directory #{install_libdir}" unless gets.chomp! == 'y' + `md #{install_libdir}` +end +puts "move" +`move *.lib #{install_libdir}` + +puts "[step.4]" +puts ">> Copy OpenCV header files(*.h / *.hpp) to target directory" +puts ">> note: default is #{install_includedir}" +print "target directory : " +input = gets.chomp! +install_includedir = input unless input.empty? +if File.exist?(install_includedir) + raise "#{install_includedir} is exist. but it is not directory." unless File.directory?(install_libdir) +else + print "Directory #{install_includedir} does not exist. Create it? [y/n]:" + raise "Please create directory #{install_includedir}" unless gets.chomp! == 'y' + `md #{install_includedir}` +end +puts ">> Copying header files..." +[ + "cxcore/include", + "cv/include", + "cvaux/include", + "ml/include", + "otherlibs/cvcam/include", + "otherlibs/highgui" +].each{|i| + if File.directory?(basedir + i) + Dir.foreach(basedir + i){|filename| + next unless (File.extname(filename) == ".h" || File.extname(filename) == ".hpp") + `copy \"#{(basedir + i + filename).to_s.gsub("/", "\\")}\" #{install_includedir}` + } + end +} diff --git a/test/test_opencv.rb b/test/test_opencv.rb new file mode 100755 index 00000000..4c57e7f7 --- /dev/null +++ b/test/test_opencv.rb @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby + +$:.unshift(File.dirname(__FILE__) + '/../lib') + +require 'opencv' +