From 6897ffd462675d95a5aef4f54e89c1c1df339a92 Mon Sep 17 00:00:00 2001 From: Cyrille Henry Date: Wed, 27 Jul 2011 13:10:27 +0000 Subject: adding object allowing multiple cameras calibration svn path=/trunk/externals/pix_opencv/; revision=15169 --- Makefile.in | 2 +- pix_opencv_findchessboardcorners-help.pd | 174 ++++++++++++++++ pix_opencv_findchessboardcorners.cc | 226 +++++++++++++++++++++ pix_opencv_findchessboardcorners.h | 98 +++++++++ pix_opencv_warpperspective-help.pd | 232 +++++++++++++++++++++ pix_opencv_warpperspective.cc | 335 +++++++++++++++++++++++++++++++ pix_opencv_warpperspective.h | 95 +++++++++ 7 files changed, 1161 insertions(+), 1 deletion(-) create mode 100644 pix_opencv_findchessboardcorners-help.pd create mode 100644 pix_opencv_findchessboardcorners.cc create mode 100644 pix_opencv_findchessboardcorners.h create mode 100644 pix_opencv_warpperspective-help.pd create mode 100644 pix_opencv_warpperspective.cc create mode 100644 pix_opencv_warpperspective.h diff --git a/Makefile.in b/Makefile.in index 3384504..ef8ad0b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -30,7 +30,7 @@ endif .SUFFIXES = $(EXTENSION) -SOURCES = pix_opencv_edge.cc pix_opencv_laplace.cc pix_opencv_morphology.cc pix_opencv_distrans.cc pix_opencv_motempl.cc pix_opencv_haarcascade.cc pix_opencv_contours_boundingrect.cc pix_opencv_bgsubstract.cc pix_opencv_contours_convexity.cc pix_opencv_dft.cc pix_opencv_lk.cc pix_opencv_hist_compare.cc pix_opencv_knear.cc pix_opencv_threshold.cc pix_opencv_floodfill.cc pix_opencv_athreshold.cc pix_opencv_bgstats.cc pix_opencv_camshift.cc pix_opencv_hu_compare.cc pix_opencv_pgh_compare.cc pix_opencv_hough_circles.cc pix_opencv_hough_lines.cc pix_opencv_hu_moments.cc pix_opencv_contours_convexhull.cc pix_opencv_colorfilt.cc pix_opencv_of_bm.cc pix_opencv_of_hs.cc pix_opencv_of_lk.cc pix_opencv_calibration.cc +SOURCES = pix_opencv_edge.cc pix_opencv_laplace.cc pix_opencv_morphology.cc pix_opencv_distrans.cc pix_opencv_motempl.cc pix_opencv_haarcascade.cc pix_opencv_contours_boundingrect.cc pix_opencv_bgsubstract.cc pix_opencv_contours_convexity.cc pix_opencv_dft.cc pix_opencv_lk.cc pix_opencv_hist_compare.cc pix_opencv_knear.cc pix_opencv_threshold.cc pix_opencv_floodfill.cc pix_opencv_athreshold.cc pix_opencv_bgstats.cc pix_opencv_camshift.cc pix_opencv_hu_compare.cc pix_opencv_pgh_compare.cc pix_opencv_hough_circles.cc pix_opencv_hough_lines.cc pix_opencv_hu_moments.cc pix_opencv_contours_convexhull.cc pix_opencv_colorfilt.cc pix_opencv_of_bm.cc pix_opencv_of_hs.cc pix_opencv_of_lk.cc pix_opencv_calibration.cc pix_opencv_warpperspective.cc pix_opencv_findchessboardcorners.cc all: $(SOURCES:.cc=.$(EXTENSION)) $(SOURCES_OPT:.cc=.$(EXTENSION)) diff --git a/pix_opencv_findchessboardcorners-help.pd b/pix_opencv_findchessboardcorners-help.pd new file mode 100644 index 0000000..1128ea5 --- /dev/null +++ b/pix_opencv_findchessboardcorners-help.pd @@ -0,0 +1,174 @@ +#N canvas 227 24 1228 719 10; +#X obj 583 433 cnv 15 550 120 empty empty empty 20 12 0 14 -24198 -66577 +0; +#X obj 715 -18 gemhead; +#X obj 596 579 pix_texture; +#X obj 33 40 cnv 15 220 70 empty empty empty 20 12 0 14 -195568 -66577 +0; +#N canvas 0 22 454 304 gemwin 0; +#X obj 67 89 outlet; +#X obj 67 10 inlet; +#X obj 65 41 route create; +#X msg 67 70 set destroy; +#X msg 182 68 set create; +#N canvas 87 154 247 179 Gem.init 0; +#X obj 118 46 loadbang; +#X msg 118 81 reset; +#X obj 118 113 outlet; +#X connect 0 0 1 0; +#X connect 1 0 2 0; +#X restore 289 80 pd Gem.init; +#X obj 162 241 gemwin; +#X msg 161 188 create \, 1; +#X msg 237 189 destroy; +#X msg 283 161 frame 25; +#X obj 164 126 t b b b; +#X connect 1 0 2 0; +#X connect 2 0 3 0; +#X connect 2 0 10 0; +#X connect 2 1 4 0; +#X connect 2 1 8 0; +#X connect 3 0 0 0; +#X connect 4 0 0 0; +#X connect 7 0 6 0; +#X connect 8 0 6 0; +#X connect 9 0 6 0; +#X connect 10 0 7 0; +#X connect 10 2 9 0; +#X restore 43 84 pd gemwin; +#X msg 43 66 destroy; +#X obj 444 578 pix_texture; +#X obj 596 371 separator; +#X obj 727 9 bng 25 250 50 0 load empty empty 0 -6 0 8 -262144 -1 -1 +; +#X obj 784 184 bng 15 250 50 0 empty empty end_reached 20 7 0 10 -262144 +-1 -1; +#X floatatom 766 149 5 0 10000 1 frame# - -; +#X obj 727 38 openpanel; +#X msg 727 58 open \$1; +#X obj 715 167 pix_film; +#X msg 733 101 auto \$1; +#X obj 733 83 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 +; +#X text 41 46 Create window and render; +#X msg 596 109 colorspace RGBA; +#X msg 750 124 colorspace Grey; +#X obj 596 34 loadbang; +#X obj 595 342 pix_separator; +#X obj 444 374 separator; +#X obj 444 345 pix_separator; +#X obj 444 409 translateXYZ -2 0 0; +#X obj 596 406 translateXYZ 2 0 0; +#N canvas 0 22 450 300 vswitch 0; +#X obj 144 263 outlet; +#X obj 36 26 inlet; +#X obj 260 29 inlet; +#X obj 36 133 spigot; +#X obj 260 141 spigot; +#X obj 119 64 loadbang; +#X msg 83 93 0; +#X msg 113 93 1; +#X msg 296 104 0; +#X msg 326 104 1; +#X obj 399 34 inlet; +#X obj 399 67 select 0; +#X connect 1 0 3 0; +#X connect 2 0 4 0; +#X connect 3 0 0 0; +#X connect 4 0 0 0; +#X connect 5 0 7 0; +#X connect 5 0 8 0; +#X connect 6 0 3 1; +#X connect 7 0 3 1; +#X connect 8 0 4 1; +#X connect 9 0 4 1; +#X connect 10 0 11 0; +#X connect 11 0 7 0; +#X connect 11 0 8 0; +#X connect 11 1 9 0; +#X connect 11 1 6 0; +#X restore 444 207 pd vswitch; +#X obj 521 207 tgl 15 0 empty load empty 17 7 0 10 -262144 -1 -1 1 +1; +#X obj 444 -23 gemhead; +#X msg 478 60 device 0; +#X msg 469 36 dialog; +#X obj 444 165 pix_video; +#X obj 444 599 square 2; +#X obj 596 601 square 2; +#X obj 596 526 pix_opencv_findchessboardcorners; +#X text 25 137 pix_opencv_findchessboardcorners :: Search inner corners +coordinates of a known chessboard pattern; +#X text 22 173 It is useful to calibration severals cameras togehter +or camera(s) and video beamer(s)...; +#X obj 444 314 pix_gray; +#X msg 492 111 driver 0; +#X obj 817 582 print; +#X obj 514 280 spigot; +#X obj 514 314 pix_rgba; +#X obj 444 280 spigot 1; +#X obj 598 237 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X text 615 237 switch gray/color; +#X text 830 558 print out raw corners coordinates...; +#X obj 650 472 pack 6 7; +#X floatatom 650 452 5 0 0 0 - - -; +#X floatatom 703 452 5 0 0 0 - - -; +#X msg 488 86 device /dev/video0; +#X msg 650 492 patternSize \$1 \$2; +#X text 784 493 pattern size (number of inner corners in each direction) +; +#X obj 598 257 == 0; +#X obj 444 236 pix_resize 640 480; +#X obj 521 185 loadbang; +#X connect 1 0 13 0; +#X connect 2 0 32 0; +#X connect 4 0 5 0; +#X connect 5 0 4 0; +#X connect 6 0 31 0; +#X connect 7 0 24 0; +#X connect 8 0 11 0; +#X connect 9 0 10 0; +#X connect 10 0 13 1; +#X connect 11 0 12 0; +#X connect 12 0 13 0; +#X connect 13 0 25 1; +#X connect 13 2 9 0; +#X connect 14 0 13 0; +#X connect 15 0 14 0; +#X connect 17 0 13 0; +#X connect 17 0 30 0; +#X connect 18 0 13 0; +#X connect 19 0 17 0; +#X connect 19 0 15 0; +#X connect 20 0 7 0; +#X connect 21 0 23 0; +#X connect 22 0 21 0; +#X connect 23 0 6 0; +#X connect 24 0 33 0; +#X connect 25 0 52 0; +#X connect 26 0 25 2; +#X connect 27 0 30 0; +#X connect 28 0 30 0; +#X connect 29 0 30 0; +#X connect 30 0 25 0; +#X connect 33 0 2 0; +#X connect 33 1 38 0; +#X connect 36 0 22 0; +#X connect 36 0 20 0; +#X connect 37 0 30 0; +#X connect 39 0 40 0; +#X connect 40 0 20 0; +#X connect 40 0 22 0; +#X connect 41 0 36 0; +#X connect 42 0 39 1; +#X connect 42 0 51 0; +#X connect 45 0 49 0; +#X connect 46 0 45 0; +#X connect 47 0 45 1; +#X connect 48 0 30 0; +#X connect 49 0 33 0; +#X connect 51 0 41 1; +#X connect 52 0 41 0; +#X connect 52 0 39 0; +#X connect 53 0 26 0; diff --git a/pix_opencv_findchessboardcorners.cc b/pix_opencv_findchessboardcorners.cc new file mode 100644 index 0000000..5593033 --- /dev/null +++ b/pix_opencv_findchessboardcorners.cc @@ -0,0 +1,226 @@ +//////////////////////////////////////////////////////// +// +// GEM - Graphics Environment for Multimedia +// +// zmoelnig@iem.kug.ac.at +// +// Implementation file +// +// Copyright (c) 1997-2000 Mark Danks. +// Copyright (c) Günther Geiger. +// Copyright (c) 2001-2002 IOhannes m zmoelnig. forum::für::umläute. IEM +// Copyright (c) 2002 James Tittle & Chris Clepper +// For information on usage and redistribution, and for a DISCLAIMER OF ALL +// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution. +// +///////////////////////////////////////////////////////// + +#include "pix_opencv_findchessboardcorners.h" +#include + +CPPEXTERN_NEW(pix_opencv_findchessboardcorners) + +///////////////////////////////////////////////////////// +// +// pix_opencv_findchessboardcorners +// +///////////////////////////////////////////////////////// +// Constructor +// +///////////////////////////////////////////////////////// +pix_opencv_findchessboardcorners :: pix_opencv_findchessboardcorners() +{ + //inlet_new(this->x_obj, &this->x_obj->ob_pd, gensym("float"), gensym("minarea")); + //inlet_new(this->x_obj, &this->x_obj->ob_pd, gensym("float"), gensym("maxarea")); + m_dataout = outlet_new(this->x_obj, 0); + //m_countout = outlet_new(this->x_obj, 0); + comp_xsize = 320; + comp_ysize = 240; + gray = NULL; + tmp_color = NULL; + tmp_gray = NULL; + rgb = NULL; + + pattern_size = cvSize(6,7); + corners = new CvPoint2D32f[pattern_size.width * pattern_size.height]; + cornerCount = 0; + win = cvSize(11, 11); + zero_zone = cvSize(-1,-1); + flags = CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS; + criteria = cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 30, 0.1); + coord_list = new t_atom[pattern_size.width * pattern_size.height * 2]; // all coordinates are packed in one list [x0 y0 x1 y1 .. xn yn( + + post("pix_opencv_findchessboardcorners by Antoine Villeret"); + post("build on %s at %s", __DATE__, __TIME__); + +} + +///////////////////////////////////////////////////////// +// Destructor +// +///////////////////////////////////////////////////////// +pix_opencv_findchessboardcorners :: ~pix_opencv_findchessboardcorners() +{ + //Destroy cv_images to clean memory + if (gray) cvReleaseImage(&gray); + if (rgb) cvReleaseImage(&rgb); + if (tmp_color) cvReleaseImage(&tmp_color); + if (tmp_gray) cvReleaseImage(&tmp_gray); +} + +///////////////////////////////////////////////////////// +// processImage +// +///////////////////////////////////////////////////////// +void pix_opencv_findchessboardcorners :: processRGBAImage(imageStruct &image) +{ + if ((this->comp_xsize!=image.xsize)||(this->comp_ysize!=image.ysize)||(!rgb)) + { + + this->comp_xsize = image.xsize; + this->comp_ysize = image.ysize; + + //Destroy cv_images to clean memory + if(gray) cvReleaseImage(&gray); + if(rgb) cvReleaseImage(&rgb); + if(tmp_color) cvReleaseImage(&tmp_color); + + // Create images with new sizes + rgb = cvCreateImage(cvSize(image.xsize,image.ysize), IPL_DEPTH_8U, 4); + tmp_gray = cvCreateImage(cvSize(image.xsize,image.ysize), IPL_DEPTH_8U, 1); + } + + // no need to copy a lot of memory, just point to it... + rgb->imageData = (char*) image.data; + cvCvtColor( rgb, tmp_gray, CV_RGBA2GRAY); + + //~ printf("find corner...*/\n"); + int found = cvFindChessboardCorners( tmp_gray, pattern_size, corners, &cornerCount, flags); + //~ printf(" found : %d\n",found); + + + if ( found ) { + //~ printf("find corner sub pix...\n"); + cvFindCornerSubPix( tmp_gray, corners, cornerCount, win, zero_zone, criteria); + } + + // Draw corners on the image + //cvCvtColor( gray, tmp_color, CV_GRAY2RGBA); + cvDrawChessboardCorners( rgb, pattern_size, corners, cornerCount, found); + //cvCvtColor( tmp_color, gray, CV_RGBA2GRAY); + + // send out corners screen coordinates if all corners have been found + if (found) { + int i; + CvPoint2D32f *pt; + pt = (CvPoint2D32f *) corners; + for ( i=0; ix); + SETFLOAT(&coord_list[i*2+1], pt->y); + pt++; + } + outlet_list( m_dataout, 0, pattern_size.width * pattern_size.height*2, coord_list ); + } + //~ printf("process RGBA image done\n"); +} + +void pix_opencv_findchessboardcorners :: processRGBImage(imageStruct &image) +{ + // TODO + error("cant't support RGB image for now"); +} + +void pix_opencv_findchessboardcorners :: processYUVImage(imageStruct &image) +{ + // TODO + error( "pix_opencv_findchessboardcorners : yuv format not supported" ); +} + +void pix_opencv_findchessboardcorners :: processGrayImage(imageStruct &image) +{ + //~ printf("process gray image\n"); + if ((this->comp_xsize!=image.xsize)||(this->comp_ysize!=image.ysize)||(!gray)) + { + + this->comp_xsize = image.xsize; + this->comp_ysize = image.ysize; + + //Destroy cv_images to clean memory + if(gray) cvReleaseImage(&gray); + if(rgb) cvReleaseImage(&rgb); + if(tmp_color) cvReleaseImage(&tmp_color); + if(tmp_gray) cvReleaseImage(&tmp_gray); + + // Create images with new sizes + gray = cvCreateImage(cvSize(image.xsize,image.ysize), IPL_DEPTH_8U, 1); + tmp_color = cvCreateImage(cvSize(image.xsize,image.ysize), IPL_DEPTH_8U, 4); + } + + // no need to copy a lot of memory, just point to it... + gray->imageData = (char*) image.data; + + //~ printf("find corner...*/\n"); + int found = cvFindChessboardCorners( gray, pattern_size, corners, &cornerCount, flags); + //~ printf(" found : %d\n",found); + + + if ( found ) { + //~ printf("find corner sub pix...\n"); + cvFindCornerSubPix( gray, corners, cornerCount, win, zero_zone, criteria); + } + + // Draw corners on the image + cvCvtColor( gray, tmp_color, CV_GRAY2RGBA); + cvDrawChessboardCorners( tmp_color, pattern_size, corners, cornerCount, found); + cvCvtColor( tmp_color, gray, CV_RGBA2GRAY); + + // send out corners screen coordinates if all corners have been found + if (found) { + int i; + CvPoint2D32f *pt; + pt = (CvPoint2D32f *) corners; + for ( i=0; ix); + SETFLOAT(&coord_list[i*2+1], pt->y); + pt++; + } + outlet_list( m_dataout, 0, pattern_size.width * pattern_size.height*2, coord_list ); + } + //~ printf("process gray image done\n"); +} + +///////////////////////////////////////////////////////// +// floatThreshMess +// +///////////////////////////////////////////////////////// +void pix_opencv_findchessboardcorners :: patternSizeMess (int xsize, int ysize) +{ + if ( xsize < 3 || ysize < 3 ) { + error("patternSize should be at least 3x3"); + return; + } + pattern_size=cvSize(xsize,ysize); + // update corners array & output list size + delete coord_list; + coord_list = new t_atom[pattern_size.width * pattern_size.height * 2]; + delete corners; + corners = new CvPoint2D32f[pattern_size.width * pattern_size.height]; +} + +///////////////////////////////////////////////////////// +// static member function +// +///////////////////////////////////////////////////////// +void pix_opencv_findchessboardcorners :: obj_setupCallback(t_class *classPtr) +{ + // TODO add support for message : win, zero_zone, flags and criteria + class_addmethod(classPtr, (t_method)&pix_opencv_findchessboardcorners::patternSizeMessCallback, + gensym("patternSize"), A_FLOAT, A_FLOAT, A_NULL); +} + +void pix_opencv_findchessboardcorners :: patternSizeMessCallback(void *data, t_floatarg xsize, t_floatarg ysize) +{ + GetMyClass(data)->patternSizeMess((int)xsize, (int)ysize); +} diff --git a/pix_opencv_findchessboardcorners.h b/pix_opencv_findchessboardcorners.h new file mode 100644 index 0000000..08dc91d --- /dev/null +++ b/pix_opencv_findchessboardcorners.h @@ -0,0 +1,98 @@ +/*----------------------------------------------------------------- +LOG + GEM - Graphics Environment for Multimedia + + Contours Bounding Rectangle detection + + Copyright (c) 1997-1999 Mark Danks. mark@danks.org + Copyright (c) Günther Geiger. geiger@epy.co.at + Copyright (c) 2001-2002 IOhannes m zmoelnig. forum::für::umläute. IEM. zmoelnig@iem.kug.ac.at + Copyright (c) 2002 James Tittle & Chris Clepper + For information on usage and redistribution, and for a DISCLAIMER OF ALL + WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution. + +-----------------------------------------------------------------*/ +// findchessboardcorners integration by Antoine Villeret - 2011 + +#ifndef INCLUDE_PIX_OPENCV_FINDCHESSBOARDCORNERS_H_ +#define INCLUDE_PIX_OPENCV_FINDCHESSBOARDCORNERS_H_ + +#ifndef _EiC +#include "cv.h" +#endif + +#include "Base/GemPixObj.h" + +#define MAX_MARKERS 500 + +/*----------------------------------------------------------------- +------------------------------------------------------------------- +CLASS + pix_opencv_findchessboardcorners + + Chessboard corners detection + +KEYWORDS + pix + +DESCRIPTION + +-----------------------------------------------------------------*/ +class GEM_EXTERN pix_opencv_findchessboardcorners : public GemPixObj +{ + CPPEXTERN_HEADER(pix_opencv_findchessboardcorners, GemPixObj) + + public: + + ////////// + // Constructor + pix_opencv_findchessboardcorners(); + + protected: + + ////////// + // Destructor + virtual ~pix_opencv_findchessboardcorners(); + + ////////// + // Do the processing + virtual void processRGBAImage(imageStruct &image); + virtual void processRGBImage(imageStruct &image); + virtual void processYUVImage(imageStruct &image); + virtual void processGrayImage(imageStruct &image); + + ///////// + // Setup + void patternSizeMess (int xsize, int ysize); + + + // to detect changes in the image size + int comp_xsize; + int comp_ysize; + + + CvSize pattern_size; // pattern size (inner corners count in 2D) + CvPoint2D32f *corners; // array to store corners coordinates + int cornerCount; // number of corners found + int flags; // flags for cvFindChessboardCorners + CvSize win; // half of the search window size for cvFindCornerSubPix + CvSize zero_zone; // for cvFindCornerSubPix + CvTermCriteria criteria; // for cvFindCornerSubPix + t_atom *coord_list; + + + private: + + t_outlet *m_dataout; + ////////// + // Static member functions + static void patternSizeMessCallback(void *data, t_floatarg xsize, t_floatarg ysize); + + + ///////// + // IplImage needed + IplImage *rgb, *tmp_color, *gray, *tmp_gray; + +}; + +#endif // for header file diff --git a/pix_opencv_warpperspective-help.pd b/pix_opencv_warpperspective-help.pd new file mode 100644 index 0000000..33f2452 --- /dev/null +++ b/pix_opencv_warpperspective-help.pd @@ -0,0 +1,232 @@ +#N canvas 295 24 980 660 10; +#X obj 24 25 gemhead; +#X obj 411 543 gemwin; +#X msg 411 509 create \, 1; +#X msg 492 509 destroy; +#X obj 24 565 pix_texture; +#X obj 24 93 pix_film; +#X obj 187 328 pix_texture; +#X obj 187 308 pix_opencv_findchessboardcorners; +#X obj 187 254 pack 6 7; +#X floatatom 187 234 5 0 0 0 - - -; +#X floatatom 240 234 5 0 0 0 - - -; +#X msg 187 274 patternSize \$1 \$2; +#N canvas 502 24 715 644 generates_coords 0; +#X obj 49 31 inlet; +#X obj 77 251 until; +#X obj 77 358 f; +#X msg 95 335 0; +#X obj 90 118 unpack; +#X obj 81 462 pack; +#X obj 77 188 f; +#X obj 177 251 until; +#X obj 209 358 f; +#X msg 227 335 0; +#X obj 177 287 t b b; +#X obj 177 188 f; +#X obj 90 143 t b f; +#X obj 81 501 list; +#X obj 57 521 list; +#X obj 81 482 list prepend; +#X obj 58 591 outlet; +#X text 185 97 generates source coordinates to find homography; +#X obj 89 437 + 0; +#X obj 221 437 + 0; +#X floatatom 420 348 5 0 0 0 offset_y - -; +#X obj 57 89 t b l b; +#X obj 77 208 t f b; +#X obj 177 208 t f b; +#X floatatom 420 328 5 0 0 0 offset_x - -; +#X floatatom 420 308 5 0 0 0 taille_du_cote_en_m - -; +#X obj 105 358 + 0.25; +#X obj 237 358 + 0.25; +#X msg 90 62 6 7; +#X obj 57 545 list prepend dstMatrix; +#X obj 57 566 route list; +#X obj 267 269 t b a; +#X obj 411 185 loadbang; +#X obj 352 399 t b a; +#X obj 277 389 t b a; +#X msg 409 216 11; +#X msg 450 216 493; +#X msg 492 216 137; +#X connect 0 0 21 0; +#X connect 1 0 2 0; +#X connect 2 0 18 0; +#X connect 2 0 26 0; +#X connect 3 0 2 1; +#X connect 4 0 12 0; +#X connect 4 1 11 1; +#X connect 5 0 15 0; +#X connect 6 0 22 0; +#X connect 7 0 10 0; +#X connect 8 0 19 0; +#X connect 8 0 27 0; +#X connect 9 0 8 1; +#X connect 10 0 6 0; +#X connect 10 1 8 0; +#X connect 11 0 23 0; +#X connect 12 0 11 0; +#X connect 12 1 6 1; +#X connect 13 0 14 1; +#X connect 13 0 15 1; +#X connect 14 0 29 0; +#X connect 15 0 13 0; +#X connect 18 0 5 0; +#X connect 19 0 5 1; +#X connect 20 0 33 0; +#X connect 21 0 14 0; +#X connect 21 1 4 0; +#X connect 21 2 15 1; +#X connect 22 0 1 0; +#X connect 22 1 3 0; +#X connect 23 0 7 0; +#X connect 23 1 9 0; +#X connect 24 0 34 0; +#X connect 25 0 31 0; +#X connect 26 0 2 1; +#X connect 27 0 8 1; +#X connect 28 0 21 0; +#X connect 29 0 30 0; +#X connect 30 0 16 0; +#X connect 31 0 28 0; +#X connect 31 1 27 1; +#X connect 31 1 26 1; +#X connect 32 0 35 0; +#X connect 32 0 36 0; +#X connect 32 0 37 0; +#X connect 33 0 28 0; +#X connect 33 1 19 1; +#X connect 34 0 28 0; +#X connect 34 1 18 1; +#X connect 35 0 25 0; +#X connect 36 0 24 0; +#X connect 37 0 20 0; +#X restore 426 309 pd generates_coords; +#X obj 408 350 list prepend srcMatrix; +#X obj 187 348 translateXYZ 2 2 0; +#X obj 187 368 rectangle 2 1.5; +#X obj 408 377 route list; +#X obj 203 571 print; +#X obj 24 512 separator; +#X obj 50 49 loadbang; +#X obj 104 262 spigot; +#X obj 139 139 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X msg 50 69 open shoot-2.mov \, auto 1; +#X obj 24 301 spigot 1; +#X obj 112 240 == 0; +#X obj 24 113 pix_grey; +#X obj 24 591 rectangle 4 3; +#X obj 23 -3 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1 +; +#X text 485 9 pix_opencv_wapperspective finds the transformation matrix +between srcMatrix and dstMatrix; +#X text 485 38 it sends through its second outlet the 3x3 transformation +matrix when a correct scrMatrix message is received; +#X text 484 65 you should first initiliaze dstMatrix; +#X obj 24 539 pix_opencv_warpperspective; +#X text 482 86 it also applied the tansformation matrix on incomming +image stream; +#X text 482 151 pix_opencv_findchessboardcorners finds chessboard corners +in the incomming image stream and send out corners coordinates as a +list trought its second outlet; +#X text 484 200 it also prints found corners on the image stream; +#X msg 409 423 mapMatrix 1 0 0 0 1 0 0 0 1; +#X text 408 404 you can also set the map matrix directly; +#X msg 409 443 mapMatrix 0.5 0 0 0 0.5 0 0 0 1; +#X text 614 422 identity; +#X text 635 444 scale by 0.5; +#X msg 409 463 mapMatrix 0 1 0 1 0 0 0 0 2; +#X text 608 465 rotation by 90deg and scale by 0.5; +#X text 156 134 switch to find corners and mapMatrix and switch back +to apply it; +#X text 186 211 number of inner corners in each direction; +#N canvas 0 0 936 545 wrap_perspective_GPU 0; +#X obj 251 443 mesh_square 10 10; +#X obj 301 277 /; +#X obj 351 278 /; +#X obj 301 233 loadbang; +#X obj 251 356 GEMglMultTransposeMatrixf; +#X obj 251 414 translateXYZ 1 1 0; +#X obj 251 299 scaleXYZ 0.003 0.003 0; +#X obj 251 376 scaleXYZ 639 479 0; +#X obj 251 212 translateXYZ -5.33333 -4 0; +#X obj 251 395 scaleXYZ 0.5 0.5 0; +#X msg 301 255 5.3333 320; +#X msg 377 255 4 240; +#X msg 423 330 \$1 \$4 0 \$7 \$2 \$5 0 \$8 0 0 1 0 \$3 \$6 0 \$9; +#X text 46 22 wrap_persective can be easilly computed by the GPU in +order to boost performace; +#X obj 251 188 spigot; +#X obj 290 138 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 39 105 t a a; +#X obj 39 190 spigot 1; +#X obj 92 164 == 0; +#X obj 39 253 rectangle 4 3; +#X obj 39 233 pix_texture; +#X obj 39 211 pix_opencv_warpperspective; +#X text 306 137 switch CPU / GPU; +#X text 454 256 Since the matrice is computed for somthing that range +from 0 to 639 in X \, and from 0 to 479 in Y \, one have to convert +(scale / translate) the primitive coordinate to fit the transformation +matrix.; +#X connect 1 0 6 1; +#X connect 2 0 6 2; +#X connect 3 0 10 0; +#X connect 3 0 11 0; +#X connect 4 0 7 0; +#X connect 5 0 0 0; +#X connect 6 0 4 0; +#X connect 7 0 9 0; +#X connect 8 0 6 0; +#X connect 9 0 5 0; +#X connect 10 0 1 0; +#X connect 11 0 2 0; +#X connect 12 0 4 1; +#X connect 14 0 8 0; +#X connect 15 0 14 1; +#X connect 15 0 18 0; +#X connect 16 0 17 0; +#X connect 16 1 14 0; +#X connect 17 0 21 0; +#X connect 18 0 17 1; +#X connect 20 0 19 0; +#X connect 21 0 20 0; +#X connect 21 1 12 0; +#X restore 413 589 pd wrap_perspective_GPU; +#X connect 0 0 5 0; +#X connect 2 0 1 0; +#X connect 3 0 1 0; +#X connect 4 0 26 0; +#X connect 5 0 25 0; +#X connect 5 2 22 0; +#X connect 6 0 14 0; +#X connect 7 0 6 0; +#X connect 7 1 13 0; +#X connect 8 0 11 0; +#X connect 8 0 12 0; +#X connect 9 0 8 0; +#X connect 10 0 8 1; +#X connect 11 0 7 0; +#X connect 12 0 31 0; +#X connect 13 0 16 0; +#X connect 14 0 15 0; +#X connect 16 0 31 0; +#X connect 18 0 31 0; +#X connect 19 0 22 0; +#X connect 20 0 7 0; +#X connect 21 0 20 1; +#X connect 21 0 24 0; +#X connect 22 0 5 0; +#X connect 23 0 18 0; +#X connect 24 0 23 1; +#X connect 25 0 23 0; +#X connect 25 0 20 0; +#X connect 27 0 0 0; +#X connect 31 0 4 0; +#X connect 31 1 17 0; +#X connect 35 0 31 0; +#X connect 37 0 31 0; +#X connect 40 0 31 0; diff --git a/pix_opencv_warpperspective.cc b/pix_opencv_warpperspective.cc new file mode 100644 index 0000000..c97dfa0 --- /dev/null +++ b/pix_opencv_warpperspective.cc @@ -0,0 +1,335 @@ +//////////////////////////////////////////////////////// +// +// GEM - Graphics Environment for Multimedia +// +// zmoelnig@iem.kug.ac.at +// +// Implementation file +// +// Copyright (c) 1997-2000 Mark Danks. +// Copyright (c) Günther Geiger. +// Copyright (c) 2001-2002 IOhannes m zmoelnig. forum::für::umläute. IEM +// Copyright (c) 2002 James Tittle & Chris Clepper +// For information on usage and redistribution, and for a DISCLAIMER OF ALL +// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution. +// +///////////////////////////////////////////////////////// +// +// pix_opencv_warpperspective by Antoine Villeret - 2011 +// + + + +#include "pix_opencv_warpperspective.h" +#include + +CPPEXTERN_NEW(pix_opencv_warpperspective) + +///////////////////////////////////////////////////////// +// Constructor +// +///////////////////////////////////////////////////////// + +pix_opencv_warpperspective :: pix_opencv_warpperspective() +{ + //inlet_new(this->x_obj, &this->x_obj->ob_pd, gensym("float"), gensym("minarea")); + //inlet_new(this->x_obj, &this->x_obj->ob_pd, gensym("float"), gensym("maxarea")); + m_dataout = outlet_new(this->x_obj, 0); + //m_countout = outlet_new(this->x_obj, 0); + comp_xsize = 320; + comp_ysize = 240; + gray = NULL; + tmp = NULL; + rgb = NULL; + mapMatrix = cvCreateMat(3,3,CV_32FC1); + srcMatrix = cvCreateMat(4,2,CV_32FC1); + dstMatrix = cvCreateMat(4,2,CV_32FC1); + + cvSet(mapMatrix, cvScalar(0)); // set all to 0. + CV_MAT_ELEM( *mapMatrix, float, 0, 0 ) = 1.; // then make identity + CV_MAT_ELEM( *mapMatrix, float, 1, 1 ) = 1.; + + // initialize srcMatrix & dstMatrix to the same... + CV_MAT_ELEM( *srcMatrix, float, 0, 0 ) = 0.; + CV_MAT_ELEM( *srcMatrix, float, 0, 1 ) = 0.; + CV_MAT_ELEM( *srcMatrix, float, 1, 0 ) = 1.; + CV_MAT_ELEM( *srcMatrix, float, 1, 1 ) = 0.; + CV_MAT_ELEM( *srcMatrix, float, 2, 0 ) = 1.; + CV_MAT_ELEM( *srcMatrix, float, 2, 1 ) = 1.; + CV_MAT_ELEM( *srcMatrix, float, 3, 0 ) = 0.; + CV_MAT_ELEM( *srcMatrix, float, 3, 1 ) = 1.; + + CV_MAT_ELEM( *dstMatrix, float, 0, 0 ) = 0.; + CV_MAT_ELEM( *dstMatrix, float, 0, 1 ) = 0.; + CV_MAT_ELEM( *dstMatrix, float, 1, 0 ) = 1.; + CV_MAT_ELEM( *dstMatrix, float, 1, 1 ) = 0.; + CV_MAT_ELEM( *dstMatrix, float, 2, 0 ) = 1.; + CV_MAT_ELEM( *dstMatrix, float, 2, 1 ) = 1.; + CV_MAT_ELEM( *dstMatrix, float, 3, 0 ) = 0.; + CV_MAT_ELEM( *dstMatrix, float, 3, 1 ) = 1.; + + mapMatrixList=new t_atom[9]; + + flags = CV_WARP_FILL_OUTLIERS; // TODO add a set method + findmethod = 0; // TODO add a set method + + printf("build on %s at %s\n", __DATE__, __TIME__); + post("pix_opencv_warpperspective by Antoine Villeret"); + post("build on %s at %s", __DATE__, __TIME__); + +} + +///////////////////////////////////////////////////////// +// Destructor +// +///////////////////////////////////////////////////////// +pix_opencv_warpperspective :: ~pix_opencv_warpperspective() +{ + //Destroy cv_images to clean memory + //if (gray) cvReleaseImage(&gray); // TODO free image header but not data because it points to Gem image... + if (rgb) cvReleaseImage(&rgb); + //if (tmp) cvReleaseImage(&tmp); // the same + if (mapMatrix) cvReleaseMat(&mapMatrix); + if (srcMatrix) cvReleaseMat(&srcMatrix); + if (dstMatrix) cvReleaseMat(&dstMatrix); +} + +///////////////////////////////////////////////////////// +// processImage +// +///////////////////////////////////////////////////////// +void pix_opencv_warpperspective :: processRGBAImage(imageStruct &image) +{ + if ((this->comp_xsize!=image.xsize)||(this->comp_ysize!=image.ysize)||(!rgb)) + { + this->comp_xsize = image.xsize; + this->comp_ysize = image.ysize; + + //Destroy cv_images to clean memory + if(gray) cvReleaseImage(&gray); + if(rgb) cvReleaseImage(&rgb); + if(tmp) cvReleaseImage(&tmp); + + // Create images with new sizes + rgb = cvCreateImage(cvSize(image.xsize,image.ysize), IPL_DEPTH_8U, 4); + tmp = cvCreateImage(cvSize(image.xsize,image.ysize), IPL_DEPTH_8U, 4); + } + + // no need to copy a lot of memory, just point to it... + rgb->imageData = (char*) image.data; + + cvWarpPerspective(rgb, tmp, mapMatrix, flags, cvScalar(0)); + memcpy(image.data, tmp->imageData, image.xsize*image.ysize); + +} + +void pix_opencv_warpperspective :: processRGBImage(imageStruct &image) +{ + // TODO + error("cant't support RGB image for now"); +} + +void pix_opencv_warpperspective :: processYUVImage(imageStruct &image) +{ + // TODO + error( "pix_opencv_warpperspective : yuv format not supported" ); +} + +void pix_opencv_warpperspective :: processGrayImage(imageStruct &image) +{ + if ((this->comp_xsize!=image.xsize)||(this->comp_ysize!=image.ysize)||(!gray)) + { + this->comp_xsize = image.xsize; + this->comp_ysize = image.ysize; + + //Destroy cv_images to clean memory + if(gray) cvReleaseImage(&gray); + if(rgb) cvReleaseImage(&rgb); + if(tmp) cvReleaseImage(&tmp); + + // Create images with new sizes + gray = cvCreateImage(cvSize(image.xsize,image.ysize), IPL_DEPTH_8U, 1); + tmp = cvCreateImage(cvSize(image.xsize,image.ysize), IPL_DEPTH_8U, 1); + } + + // no need to copy a lot of memory, just point to it... + gray->imageData = (char*) image.data; + + cvWarpPerspective(gray, tmp, mapMatrix, flags, cvScalar(0)); + memcpy(image.data, tmp->imageData, image.xsize*image.ysize); + +} + +///////////////////////////////////////////////////////// +// floatThreshMess +// +///////////////////////////////////////////////////////// +void pix_opencv_warpperspective :: mapMatrixMess (int argc, t_atom *argv) +{ + post("set mapMatrix"); + int i,j; + if (argc != 9) { + error("map matrix should be 3x3"); + return; + } + for ( i = 0; i < 9 ; i++) { + if (argv[i].a_type != A_FLOAT) { + error("map matrix should be float"); + return; + } + } + + // fillin the mapMatrix + CV_MAT_ELEM( *mapMatrix, float, 0, 0 ) = argv[0].a_w.w_float; + CV_MAT_ELEM( *mapMatrix, float, 1, 0 ) = argv[1].a_w.w_float; + CV_MAT_ELEM( *mapMatrix, float, 2, 0 ) = argv[2].a_w.w_float; + CV_MAT_ELEM( *mapMatrix, float, 0, 1 ) = argv[3].a_w.w_float; + CV_MAT_ELEM( *mapMatrix, float, 1, 1 ) = argv[4].a_w.w_float; + CV_MAT_ELEM( *mapMatrix, float, 2, 1 ) = argv[5].a_w.w_float; + CV_MAT_ELEM( *mapMatrix, float, 0, 2 ) = argv[6].a_w.w_float; + CV_MAT_ELEM( *mapMatrix, float, 1, 2 ) = argv[7].a_w.w_float; + CV_MAT_ELEM( *mapMatrix, float, 2, 2 ) = argv[8].a_w.w_float; + + printf("---mapMatrix---\n"); + for ( j = 0 ; j < 3 ; j++ ){ + for( i=0 ; i<3 ; i++){ + printf("%.2f,\t", CV_MAT_ELEM( *mapMatrix, float, i, j)); + } + printf("\n"); + } +} + +void pix_opencv_warpperspective :: srcMatrixMess (int argc, t_atom *argv) +{ + //~ printf("set srcMatrix\n"); + int i,j; + float a; + //~ printf("check parity\n"); + if ( argc % 2 ) { + error("src is should be a list of couple x/y values"); + return; + } + //~ printf("check size\n"); + if ( argc != dstMatrix->rows * dstMatrix->cols ) + { + error("src matrix should have the same size as dst matrix (which is %d x %d)", dstMatrix->cols, dstMatrix->rows); + return; + } + //~ printf("check type\n"); + for ( i = 0; i < argc ; i++) { + if (argv[i].a_type != A_FLOAT) { + error("src matrix should be float"); + return; + } + } + + // fillin the srcMatrix + //~ printf("fillin srcMatrix\n"); + for ( i = 0 ; i < dstMatrix->rows ; i++ ) + { + CV_MAT_ELEM( *srcMatrix, float, i, 0 ) = argv[i*2].a_w.w_float; + CV_MAT_ELEM( *srcMatrix, float, i, 1 ) = argv[i*2+1].a_w.w_float; // does it work ? + } + findhomography(); +} + +void pix_opencv_warpperspective :: dstMatrixMess (int argc, t_atom *argv) +{ + //~ printf("set dstMatrix\n"); + int i,j; + //~ printf("check parity\n"); + if ( argc % 2 ){ + error("dstMatrix is should be a list of x/y pairs"); + return; + } + //~ printf("check type\n"); + for ( i = 0; i < argc ; i++) { + if (argv[i].a_type != A_FLOAT) { + error("dstMatrix should be float"); + return; + } + } + //~ printf("dstMatrix-cols = %d,\t argc = %d\n", dstMatrix->rows, argc); + if ( dstMatrix->rows != argc/2 ) { + printf("re-create dstMatrix & srcMatrix\n"); + // delete and recreate matrix if needed + cvReleaseMat(&dstMatrix); + cvReleaseMat(&srcMatrix); + dstMatrix = cvCreateMat(argc/2,2,CV_32FC1); + srcMatrix = cvCreateMat(argc/2,2,CV_32FC1); + cvSet(srcMatrix, cvScalar(0)); // set all to 0. + } + // fillin the dstMatrix + printf("fillin dstMatrix\n"); + for ( i = 0 ; i < dstMatrix->rows ; i++ ) + { + CV_MAT_ELEM( *dstMatrix, float, i, 0 ) = argv[i*2].a_w.w_float; + CV_MAT_ELEM( *dstMatrix, float, i, 1 ) = argv[i*2+1].a_w.w_float; // does it work ? + } + findhomography(); +} + +void pix_opencv_warpperspective :: findhomography( ) +{ + int i,j; + //~ printf("find homography\n"); + if ( srcMatrix->cols != dstMatrix->cols || srcMatrix->rows != dstMatrix->rows ) { + error("srcMatrix and dstMatrix should have the same size to compute homography !"); + return; + } + /* + printf("--- srcMatrix ---"); + for ( i = 0 ; i < srcMatrix->rows ; i++ ){ + printf("%.2f\t", CV_MAT_ELEM( *srcMatrix, float, i, 0)); + printf("%.2f\n", CV_MAT_ELEM( *srcMatrix, float, i, 1)); + } + printf("--- dstMatrix ---"); + for ( i = 0 ; i < dstMatrix->rows ; i++ ){ + printf("%.2f\t", CV_MAT_ELEM( *dstMatrix, float, i, 0)); + printf("%.2f\n", CV_MAT_ELEM( *dstMatrix, float, i, 1)); + } + */ + + cvFindHomography(srcMatrix, dstMatrix, mapMatrix, findmethod, 0, NULL); + printf("---mapMatrix---\n"); + for ( j = 0 ; j < 3 ; j++ ){ + for( i=0 ; i<3 ; i++){ + SETFLOAT(&mapMatrixList[i+j*3], CV_MAT_ELEM( *mapMatrix, float, i, j)); + printf("%.2f,\t", CV_MAT_ELEM( *mapMatrix, float, i, j)); + } + printf("\n"); + } + // send out mapMatrix + outlet_list( m_dataout, 0, 9, mapMatrixList); +} +///////////////////////////////////////////////////////// +// static member function +// +///////////////////////////////////////////////////////// +void pix_opencv_warpperspective :: obj_setupCallback(t_class *classPtr) +{ + // TODO add method for message "flags" + // TODO treat list messages in a PD way ? + class_addmethod(classPtr, (t_method)&pix_opencv_warpperspective::mapMatrixMessCallback, + gensym("mapMatrix"), A_GIMME, A_NULL); + class_addmethod(classPtr, (t_method)&pix_opencv_warpperspective::srcMatrixMessCallback, + gensym("srcMatrix"), A_GIMME, A_NULL); + class_addmethod(classPtr, (t_method)&pix_opencv_warpperspective::dstMatrixMessCallback, + gensym("dstMatrix"), A_GIMME, A_NULL); +} + +void pix_opencv_warpperspective :: mapMatrixMessCallback(void *data, t_symbol *s, int argc, t_atom *argv) +{ + GetMyClass(data)->mapMatrixMess(argc, argv); +} + +void pix_opencv_warpperspective :: srcMatrixMessCallback(void *data, t_symbol *s, int argc, t_atom *argv) +{ + GetMyClass(data)->srcMatrixMess(argc, argv); +} + +void pix_opencv_warpperspective :: dstMatrixMessCallback(void *data, t_symbol *s, int argc, t_atom *argv) +{ + GetMyClass(data)->dstMatrixMess(argc, argv); +} + diff --git a/pix_opencv_warpperspective.h b/pix_opencv_warpperspective.h new file mode 100644 index 0000000..27af960 --- /dev/null +++ b/pix_opencv_warpperspective.h @@ -0,0 +1,95 @@ +/*----------------------------------------------------------------- +LOG + GEM - Graphics Environment for Multimedia + + Contours Bounding Rectangle detection + + Copyright (c) 1997-1999 Mark Danks. mark@danks.org + Copyright (c) Günther Geiger. geiger@epy.co.at + Copyright (c) 2001-2002 IOhannes m zmoelnig. forum::für::umläute. IEM. zmoelnig@iem.kug.ac.at + Copyright (c) 2002 James Tittle & Chris Clepper + For information on usage and redistribution, and for a DISCLAIMER OF ALL + WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution. + +-----------------------------------------------------------------*/ +// pix_opencv_warpperspective integration by Antoine Villeret - 2011 + +#ifndef INCLUDE_PIX_OPENCV_WARPPERSPECTIVE_H_ +#define INCLUDE_PIX_OPENCV_WARPPERSPECTIVE_H_ + +#ifndef _EiC +#include "cv.h" +#endif + +#include "Base/GemPixObj.h" + +#define MAX_MARKERS 500 + +/*----------------------------------------------------------------- +------------------------------------------------------------------- +CLASS + pix_opencv_warpperspective + +KEYWORDS + pix + +DESCRIPTION + +-----------------------------------------------------------------*/ +class GEM_EXTERN pix_opencv_warpperspective : public GemPixObj +{ + CPPEXTERN_HEADER(pix_opencv_warpperspective, GemPixObj) + + public: + + ////////// + // Constructor + pix_opencv_warpperspective(); + + protected: + + ////////// + // Destructor + virtual ~pix_opencv_warpperspective(); + + ////////// + // Do the processing + virtual void processRGBAImage(imageStruct &image); + virtual void processRGBImage(imageStruct &image); + virtual void processYUVImage(imageStruct &image); + virtual void processGrayImage(imageStruct &image); + + ///////// + // Setup + void mapMatrixMess (int argc, t_atom *argv); + void srcMatrixMess (int argc, t_atom *argv); + void dstMatrixMess (int argc, t_atom *argv); + void findhomography(); + + // to detect changes in the image size + int comp_xsize; + int comp_ysize; + + CvMat *mapMatrix; // 3x3 transformation matrix + CvMat *srcMatrix, *dstMatrix; // nX2 points coordinates matrices, n>4 + t_atom *mapMatrixList; // array to send out transformation Matrix + int flags; + int findmethod; + + + private: + + t_outlet *m_dataout; + ////////// + // Static member functions + static void mapMatrixMessCallback(void *data, t_symbol *s, int argc, t_atom *argv); + static void srcMatrixMessCallback(void *data, t_symbol *s, int argc, t_atom *argv); + static void dstMatrixMessCallback(void *data, t_symbol *s, int argc, t_atom *argv); + + ///////// + // IplImage needed + IplImage *rgb, *tmp, *gray; + +}; + +#endif // for header file -- cgit v1.2.1