aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlluís gómez i bigordà <lluisbigorda@users.sourceforge.net>2011-07-14 19:20:03 +0000
committerlluís gómez i bigordà <lluisbigorda@users.sourceforge.net>2011-07-14 19:20:03 +0000
commite9a8c09c2c581c80bc8fe3dee8d5fac8a2e8b59f (patch)
tree00c0aa5f92d2ee81c8af67973649ae0e6dd5cd8b
parent448dca81b3c4392d0fef62678919b3e638ba4111 (diff)
added pix_opencv_calibration: camera calibration function by Antoine Villeret helped by Cyrille Henry
thanks guys! svn path=/trunk/externals/pix_opencv/; revision=15152
-rw-r--r--Makefile.in2
-rw-r--r--pix_opencv_calibration-help.pd258
-rw-r--r--pix_opencv_calibration.cc476
-rw-r--r--pix_opencv_calibration.h115
4 files changed, 850 insertions, 1 deletions
diff --git a/Makefile.in b/Makefile.in
index c85978c..3384504 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
+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
all: $(SOURCES:.cc=.$(EXTENSION)) $(SOURCES_OPT:.cc=.$(EXTENSION))
diff --git a/pix_opencv_calibration-help.pd b/pix_opencv_calibration-help.pd
new file mode 100644
index 0000000..9adb855
--- /dev/null
+++ b/pix_opencv_calibration-help.pd
@@ -0,0 +1,258 @@
+#N canvas 260 0 1106 660 10;
+#X obj 182 329 cnv 15 400 180 empty empty empty 20 12 0 14 -4034 -66577
+0;
+#X obj 145 -162 gemhead;
+#X obj 192 525 pix_texture;
+#X obj 356 -216 cnv 15 220 70 empty empty empty 20 12 0 14 -195568
+-66577 0;
+#N canvas 0 22 454 304 gemwin 1;
+#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 342 184 destroy;
+#X msg 283 161 frame 25;
+#X obj 164 126 t b b b;
+#X msg 161 189 dimen 640 560 \, create \, 1;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 2 0 9 0;
+#X connect 2 1 4 0;
+#X connect 2 1 7 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 10 0;
+#X connect 9 2 8 0;
+#X connect 10 0 6 0;
+#X restore 366 -170 pd gemwin;
+#X msg 366 -190 destroy;
+#X obj -232 499 pix_texture;
+#X obj 192 251 separator;
+#X obj 157 -135 bng 25 250 50 0 load empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 214 40 bng 15 250 50 0 empty empty end_reached 20 7 0 10 -262144
+-1 -1;
+#X floatatom 196 5 5 0 10000 1 frame# - -;
+#X obj 157 -106 openpanel;
+#X msg 157 -86 open \$1;
+#X obj 145 23 pix_film;
+#X msg 163 -43 auto \$1;
+#X obj 163 -61 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
+1;
+#X text 364 -210 Create window and render;
+#X msg 258 -60 colorspace RGBA;
+#X msg 363 -60 colorspace RGB;
+#X msg 467 -60 colorspace Grey;
+#X obj 258 -88 loadbang;
+#X obj 192 222 pix_separator;
+#X obj -232 252 separator;
+#X obj -232 223 pix_separator;
+#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 -232 52 pd vswitch;
+#X obj -136 53 tgl 15 0 empty load empty 17 7 0 10 -262144 -1 -1 0
+1;
+#X obj -232 19 pix_video;
+#X obj -232 -169 gemhead;
+#X msg -213 -103 dimen 640 480;
+#X msg -215 -128 dimen 320 240;
+#X text 224 397 load distorsion coefficients and intrinsic matrix;
+#X msg -186 -33 driver v4l2;
+#X msg -202 -80 driver dc1394 \, dimen 640 480 \, colorspace grey;
+#X msg -177 -12 driver dc1394;
+#X obj 192 469 pix_opencv_calibration;
+#X obj -232 160 pix_grey;
+#X obj -232 289 translateXYZ 0 -2 0;
+#X obj 192 285 translateXYZ 0 2 0;
+#X obj -232 525 rectangle 2.666 2;
+#X obj 192 546 rectangle 2.666 2;
+#X msg 225 416 loadDist \$1;
+#X msg 321 417 loadIntra \$1;
+#X msg 225 376 writeDist \$1;
+#X msg 321 377 writeIntra \$1;
+#X text 224 357 write distorsion coefficients and intrinsic matrix
+;
+#X obj 353 79 cnv 15 500 220 empty empty empty 20 12 0 14 -4034 -66577
+0;
+#X obj 361 90 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1
+1;
+#X msg 361 110 calibration \$1;
+#X msg 361 154 view \$1;
+#X text 400 132 number of view to take during calibration;
+#X floatatom 361 136 5 0 0 0 - - -;
+#X obj 361 195 pack f f;
+#X msg 361 215 patternSize \$1 \$2;
+#X floatatom 361 177 5 0 0 0 - - -;
+#X floatatom 414 177 5 0 0 0 - - -;
+#X text 451 173 number of inner corners on the chessboard;
+#N canvas 130 67 612 325 advance-options 0;
+#X msg 55 161 findChessFlag \$1 \$2 \$3;
+#X obj 68 91 t b f;
+#X obj 55 142 pack f f f;
+#X obj 118 111 t b f;
+#X obj 55 51 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1
+;
+#X obj 68 71 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1
+;
+#X obj 118 91 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
+1;
+#X obj 55 267 outlet;
+#X text 53 27 findChessBoardCorner option;
+#X text 75 50 CV_CALIB_CB_ADAPTIVE_TRESH : adaptive threhold (default
+1);
+#X text 84 70 CV_CALIB_CB_NORMALIZE_IMAGE : normalize image (default
+0);
+#X text 135 91 CV_CALIB_CB_FILTER_QUADS: advance filtering (default
+1);
+#X connect 0 0 7 0;
+#X connect 1 0 2 0;
+#X connect 1 1 2 1;
+#X connect 2 0 0 0;
+#X connect 3 0 2 0;
+#X connect 3 1 2 2;
+#X connect 4 0 2 0;
+#X connect 5 0 1 0;
+#X connect 6 0 3 0;
+#X restore 360 277 pd advance-options;
+#X floatatom 361 236 5 0 0 0 - - -;
+#X msg 361 254 wait \$1;
+#X text 399 235 number of frame to wait between two takes during calibration
+;
+#X text 380 90 start callibration;
+#X text -168 -242 pix_opencv_calibration is an object allowing camera
+calibration. you need to move a checkboard in front of the camera during
+the calibration part.;
+#X obj -112 160 pix_rgba;
+#X obj -232 125 spigot 1;
+#X text -119 51 switch source (camera / film);
+#X obj -136 73 tgl 15 0 empty load empty 17 7 0 10 -262144 -1 -1 0
+1;
+#X text -119 71 switch color mode ( grey / rgba );
+#X msg 225 446 loadDist XCD-V60_4mm-dist;
+#X msg 414 446 loadIntra XCD-V60_4mm-intra;
+#X msg -193 -56 device 1;
+#X obj -164 100 == 0;
+#X obj -112 124 spigot 0;
+#X obj -108 375 cnv 15 200 50 empty empty empty 20 12 0 14 -4034 -66577
+0;
+#N canvas 602 330 764 438 how-to 1;
+#X text -93 -194 getting started with camera calibration :;
+#X text -65 -108 3 Check calibration toggle to start and move the chessboard
+in front of the camera (or move the camera in front of your screen).
+Your computer may slow down during searching chessboard corners. When
+all corners are found it takes a snapshot (and the image will be negative)
+;
+#X text -65 -128 2 Plug a supported camera and start rendering;
+#X text -64 -158 1 Print the chessboard ona rigid paperboard (or just
+show it on the screen);
+#X text -65 -37 4 When enought chessboard have been found (20 by default)
+it computes transformation matrix and map to undistord the image;
+#X text -65 13 5 Then all incoming images are undistord \, you can
+save the transformation and distorsion matrix to files to load it next
+times;
+#X text -99 96 for more information about this calibration see :;
+#X text -89 146 - A flexible new technique for camera calibration \,
+Zhang \, 1998 \, Microsoft Research;
+#X text -89 116 - Learning Opencv \, Bradski and Kaehler \, 2008 \,
+O'Reilly;
+#X restore -78 391 pd how-to calibrate;
+#X connect 1 0 13 0;
+#X connect 2 0 39 0;
+#X connect 4 0 5 0;
+#X connect 5 0 4 0;
+#X connect 6 0 38 0;
+#X connect 7 0 37 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 24 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 26 0;
+#X connect 18 0 13 0;
+#X connect 19 0 13 0;
+#X connect 20 0 17 0;
+#X connect 20 0 15 0;
+#X connect 21 0 7 0;
+#X connect 22 0 36 0;
+#X connect 23 0 22 0;
+#X connect 24 0 63 0;
+#X connect 24 0 71 0;
+#X connect 25 0 24 2;
+#X connect 26 0 24 0;
+#X connect 27 0 26 0;
+#X connect 28 0 26 0;
+#X connect 29 0 26 0;
+#X connect 31 0 26 0;
+#X connect 32 0 26 0;
+#X connect 33 0 26 0;
+#X connect 34 0 2 0;
+#X connect 35 0 23 0;
+#X connect 35 0 21 0;
+#X connect 36 0 6 0;
+#X connect 37 0 34 0;
+#X connect 40 0 34 0;
+#X connect 41 0 34 0;
+#X connect 42 0 34 0;
+#X connect 43 0 34 0;
+#X connect 46 0 47 0;
+#X connect 47 0 34 0;
+#X connect 48 0 34 0;
+#X connect 50 0 48 0;
+#X connect 51 0 52 0;
+#X connect 52 0 34 0;
+#X connect 53 0 51 0;
+#X connect 54 0 51 1;
+#X connect 56 0 34 0;
+#X connect 57 0 58 0;
+#X connect 58 0 34 0;
+#X connect 62 0 23 0;
+#X connect 62 0 21 0;
+#X connect 63 0 35 0;
+#X connect 65 0 70 0;
+#X connect 65 0 71 1;
+#X connect 68 0 34 0;
+#X connect 69 0 26 0;
+#X connect 70 0 63 1;
+#X connect 71 0 62 0;
diff --git a/pix_opencv_calibration.cc b/pix_opencv_calibration.cc
new file mode 100644
index 0000000..f7681c3
--- /dev/null
+++ b/pix_opencv_calibration.cc
@@ -0,0 +1,476 @@
+////////////////////////////////////////////////////////
+//
+// 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.
+//
+/////////////////////////////////////////////////////////
+// based on code written by Lluis Gomez i Bigorda ( lluisgomez _at_ hangar _dot_ org )
+// camera calibration function by Antoine Villeret helped by Cyrille Henry
+
+#include "pix_opencv_calibration.h"
+#include <stdio.h>
+//#include <stdlib.h>
+//#include <string.h>
+
+CPPEXTERN_NEW(pix_opencv_calibration)
+
+/////////////////////////////////////////////////////////
+//
+// pix_opencv_calibration
+//
+/////////////////////////////////////////////////////////
+// Constructor
+//
+/////////////////////////////////////////////////////////
+pix_opencv_calibration :: pix_opencv_calibration()
+{
+ find_rgb = NULL;
+ find_gray = NULL;
+ rgb = NULL;
+ gray = NULL;
+ tmp = NULL;
+ mapx = NULL;
+ mapy = NULL;
+
+ success_count = 0;
+ board_view_nb = 10;
+ calibration = 0;
+ patternSize[0] = 6;
+ patternSize[1] = 7;
+ frame = 0;
+ wait_n_frame = 10;
+ findChessFlag = CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS;
+
+ // allocate storage matrix
+ image_points = cvCreateMat(patternSize[0]*patternSize[1]*board_view_nb, 2, CV_32FC1);
+ object_points = cvCreateMat(patternSize[0]*patternSize[1]*board_view_nb, 3, CV_32FC1);
+ point_counts = cvCreateMat(board_view_nb, 1, CV_32SC1);
+ intrinsic_matrix = cvCreateMat(3, 3, CV_32FC1);
+ distortion_coeffs = cvCreateMat(5, 1, CV_32FC1);
+
+ // make an "empty" intrinsinc matrix
+ CV_MAT_ELEM( *intrinsic_matrix, float, 0, 0 ) = 8;
+ CV_MAT_ELEM( *intrinsic_matrix, float, 1, 0 ) = 0;
+ CV_MAT_ELEM( *intrinsic_matrix, float, 2, 0 ) = 0;
+ CV_MAT_ELEM( *intrinsic_matrix, float, 0, 1 ) = 0;
+ CV_MAT_ELEM( *intrinsic_matrix, float, 1, 1 ) = 8;
+ CV_MAT_ELEM( *intrinsic_matrix, float, 2, 1 ) = 0;
+ CV_MAT_ELEM( *intrinsic_matrix, float, 0, 2 ) = 3;
+ CV_MAT_ELEM( *intrinsic_matrix, float, 1, 2 ) = 3;
+ CV_MAT_ELEM( *intrinsic_matrix, float, 2, 2 ) = 1;
+
+ // zeros distortion coeffs
+ for ( int i = 0 ; i < 5 ; i++ ) {
+ CV_MAT_ELEM( *distortion_coeffs, float, i, 0 ) = 0.0;
+ }
+
+ post("pix_opencv_calibration build on %s at %s", __DATE__, __TIME__);
+}
+
+/////////////////////////////////////////////////////////
+// Destructor
+//
+/////////////////////////////////////////////////////////
+pix_opencv_calibration :: ~pix_opencv_calibration()
+{
+ //Destroy cv_images to clean memory
+ if ( find_rgb ) cvReleaseImage(&find_rgb);
+ if ( find_gray ) cvReleaseImage(&find_gray);
+ if ( gray ) cvReleaseImage(&gray);
+ if ( rgb ) cvReleaseImage(&rgb);
+ if ( tmp ) cvReleaseImage(&tmp);
+ if ( mapx ) cvReleaseImage(&mapx);
+ if ( mapy ) cvReleaseImage(&mapy);
+ cvReleaseMat(&intrinsic_matrix);
+ cvReleaseMat(&distortion_coeffs);
+ cvReleaseMat(&image_points);
+ cvReleaseMat(&object_points);
+ cvReleaseMat(&point_counts);
+}
+
+/////////////////////////////////////////////////////////
+// processImage
+//
+/////////////////////////////////////////////////////////
+void pix_opencv_calibration :: processRGBAImage(imageStruct &image)
+{
+ if ((this->comp_xsize!=image.xsize)||(this->comp_ysize!=image.ysize)||(!rgb)) {
+
+ // printf("process rgba image\n");
+ this->comp_xsize = image.xsize;
+ this->comp_ysize = image.ysize;
+ if ( calibration ) error ( "image size changed, calibration was cancelled");
+ calibration = 0;
+
+ if ( find_rgb ) cvReleaseImage(&find_rgb);
+ if ( find_gray ) cvReleaseImage(&find_gray);
+ if ( gray ) cvReleaseImage(&gray); // TODO : cette ligne crash qd on passe du gray a couleur apres ou pendant calibration
+ if ( rgb ) cvReleaseImage(&rgb);
+ if ( tmp ) cvReleaseImage(&tmp);
+ if ( mapx ) cvReleaseImage(&mapx);
+ if ( mapy ) cvReleaseImage(&mapy);
+
+ // used in findCorners
+ find_rgb = cvCreateImage(cvSize(this->comp_xsize,this->comp_ysize), IPL_DEPTH_8U, 4);
+ find_gray = cvCreateImage(cvSize(this->comp_xsize,this->comp_ysize), IPL_DEPTH_8U, 1);
+
+ //create the images with new size
+ rgb = cvCreateImage(cvSize(this->comp_xsize,this->comp_ysize), IPL_DEPTH_8U, 4);
+ tmp = cvCreateImage(cvSize(this->comp_xsize,this->comp_ysize), IPL_DEPTH_8U, 4);
+ mapx = cvCreateImage(cvSize(this->comp_xsize,this->comp_ysize), IPL_DEPTH_32F, 1);
+ mapy = cvCreateImage(cvSize(this->comp_xsize,this->comp_ysize), IPL_DEPTH_32F, 1);
+
+ // create new map
+ cvInitUndistortMap(this->intrinsic_matrix, this->distortion_coeffs, this->mapx, this->mapy);
+ }
+
+ // no need to copy a lot of memory, just point to it...
+ rgb->imageData = (char*) image.data;
+
+ // this will loop until we got enought views (x->board_view_nb) with all corners visible
+ if ( success_count < board_view_nb && calibration != 0 ) {
+ findCorners( rgb );
+ image.data = (unsigned char*) rgb->imageData;
+ }
+ else if ( success_count >= board_view_nb && calibration != 0 ) {
+ computeCalibration( rgb );
+ image.data = (unsigned char*) rgb->imageData;
+ }
+ else if ( this->calibration == 0 ) {
+ cvRemap(rgb,tmp,mapx,mapy);
+ image.data = (unsigned char*) tmp->imageData;
+ }
+}
+
+void pix_opencv_calibration :: processRGBImage(imageStruct &image) {
+ error( "pix_opencv_calibration : rgb format not supported");
+}
+
+void pix_opencv_calibration :: processYUVImage(imageStruct &image) {
+ error( "pix_opencv_calibration : yuv format not supported" );
+}
+
+void pix_opencv_calibration :: processGrayImage(imageStruct &image)
+{
+ if ((this->comp_xsize!=image.xsize)||(this->comp_ysize!=image.ysize)||(!gray)) {
+
+ // printf("process gray image\n");
+ this->comp_xsize = image.xsize;
+ this->comp_ysize = image.ysize;
+ if ( calibration ) error ( "image size changed, calibration was cancelled");
+ calibration = 0;
+
+ if ( find_rgb ) cvReleaseImage(&find_rgb);
+ if ( find_gray ) cvReleaseImage(&find_gray);
+ if ( gray ) cvReleaseImage(&gray);
+ if ( rgb ) cvReleaseImage(&rgb);
+ if ( tmp ) cvReleaseImage(&tmp);
+ if ( mapx ) cvReleaseImage(&mapx);
+ if ( mapy ) cvReleaseImage(&mapy);
+
+ // used in findCorners
+ find_rgb = cvCreateImage(cvSize(this->comp_xsize,this->comp_ysize), IPL_DEPTH_8U, 4);
+ find_gray = cvCreateImage(cvSize(this->comp_xsize,this->comp_ysize), IPL_DEPTH_8U, 1);
+
+ //create the images with new size
+ gray = cvCreateImage(cvSize(this->comp_xsize,this->comp_ysize), IPL_DEPTH_8U, 1);
+ tmp = cvCreateImage(cvSize(this->comp_xsize,this->comp_ysize), IPL_DEPTH_8U, 1);
+ mapx = cvCreateImage(cvSize(this->comp_xsize,this->comp_ysize), IPL_DEPTH_32F, 1);
+ mapy = cvCreateImage(cvSize(this->comp_xsize,this->comp_ysize), IPL_DEPTH_32F, 1);
+
+ // create new map
+ cvInitUndistortMap(this->intrinsic_matrix, this->distortion_coeffs, this->mapx, this->mapy);
+ }
+
+ // no need to copy a lot of memory, just point to it...
+ gray->imageData = (char*) image.data;
+
+ // this will loop until we got enought views (x->board_view_nb) with all corners visible
+ if ( success_count < board_view_nb && calibration != 0 ) {
+ findCorners( gray );
+ image.data = (unsigned char*) gray->imageData;
+ }
+ else if ( success_count >= board_view_nb && calibration != 0 ) {
+ computeCalibration( gray );
+ image.data = (unsigned char*) gray->imageData;
+ }
+ else if ( this->calibration == 0 ) {
+ cvRemap(gray,tmp,mapx,mapy);
+ image.data = (unsigned char*) tmp->imageData;
+ }
+}
+
+/////////////////////////////////////////////////////////
+// findCorners
+//
+/////////////////////////////////////////////////////////
+void pix_opencv_calibration :: findCorners ( IplImage *image )
+{
+ int board_point_nb = this->patternSize[0]*this->patternSize[1];
+ CvPoint2D32f *corners = new CvPoint2D32f[board_point_nb];
+ int corner_count;
+ int step;
+ CvSize patternSize, image_size;
+ CvMat in_cv;
+
+ patternSize = cvSize( this->patternSize[0], this->patternSize[1] );
+ image_size = cvSize( image->width, image->height );
+ // cvGetImage (&in_cv, &in_image); // create an IplImage from a CvMat
+ cvGetMat ( image, &in_cv ); // create a CvMat from IplImage
+
+ // find chessboard corners (gray or RGBA image...)
+ int found = cvFindChessboardCorners(image,
+ patternSize,
+ corners,
+ &corner_count,
+ findChessFlag);
+ if (image->nChannels == 4) {
+ cvCvtColor( image , find_gray , CV_RGBA2GRAY); // convert color to gray
+ } else {
+ cvCopy(image, find_gray) ;
+ }
+
+ // get subpixel accuracy on those corners (grayscale image only)
+ cvFindCornerSubPix(find_gray,
+ corners,
+ corner_count,
+ cvSize(11,11),
+ cvSize(-1,-1),
+ cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 30, 0.1));
+
+ cvCvtColor( find_gray , find_rgb , CV_GRAY2RGBA); // convert gray to color
+
+ // draw chessboard corner (color image only)
+ cvDrawChessboardCorners(find_rgb, patternSize, corners, corner_count, found);
+
+ this->frame++;
+ if ( this->frame % this->wait_n_frame == 0 ) {
+ // update arrays
+
+ if( corner_count == board_point_nb ) {
+ step = this->success_count*board_point_nb;
+ for( int i=step, j=0; j<board_point_nb; ++i,++j ) {
+ CV_MAT_ELEM(*this->image_points, float,i,0) = corners[j].x;
+ CV_MAT_ELEM(*this->image_points, float,i,1) = corners[j].y;
+ CV_MAT_ELEM(*this->object_points,float,i,0) = j/this->patternSize[0];
+ CV_MAT_ELEM(*this->object_points,float,i,1) = j%this->patternSize[0];
+ CV_MAT_ELEM(*this->object_points,float,i,2) = 0.0f;
+ }
+ CV_MAT_ELEM(*this->point_counts, int,this->success_count,0) = board_point_nb;
+ this->success_count++;
+
+ cvNot( find_rgb , find_rgb );
+ }
+ post("take : %d/%d\n", success_count, board_view_nb);
+ }
+
+ // convert color to gray
+ if (image->nChannels == 1) {
+ cvCvtColor( find_rgb , image, CV_RGBA2GRAY); // convert color to gray
+ } else {
+ cvCopy(find_rgb, image);
+ }
+
+}
+/////////////////////////////////////////////////////////
+// computeCalibration
+//
+/////////////////////////////////////////////////////////
+void pix_opencv_calibration :: computeCalibration ( IplImage *image )
+{
+ //CALIBRATE THE CAMERA!
+ cvCalibrateCamera2(this->object_points,
+ this->image_points,
+ this->point_counts,
+ cvSize( image->width , image->height ),
+ this->intrinsic_matrix,
+ this->distortion_coeffs,
+ NULL,
+ NULL,
+ 0);
+ cvReleaseImage(&mapx);
+ cvReleaseImage(&mapy);
+ this->mapx = cvCreateImage( cvSize( image->width, image->height ), IPL_DEPTH_32F, 1 );
+ this->mapy = cvCreateImage( cvSize( image->width, image->height ), IPL_DEPTH_32F, 1 );
+
+ cvInitUndistortMap(this->intrinsic_matrix, this->distortion_coeffs, this->mapx, this->mapy);
+ calibration = 0;
+}
+/////////////////////////////////////////////////////////
+// LoadMess
+//
+/////////////////////////////////////////////////////////
+
+void pix_opencv_calibration :: loadIntraMess (t_symbol *filename)
+{
+ if ( filename == NULL ) { error("NULL pointer passed to function loadIntra"); return;}
+ this->intrinsic_matrix = (CvMat*)cvLoad(filename->s_name, 0, 0, 0);
+
+ if (intrinsic_matrix == NULL) {
+ intrinsic_matrix = cvCreateMat(3, 3, CV_32FC1);
+ post("can't open file %s", filename->s_name);
+ CV_MAT_ELEM( *intrinsic_matrix, float, 0, 0 ) = 8;
+ CV_MAT_ELEM( *intrinsic_matrix, float, 1, 0 ) = 0;
+ CV_MAT_ELEM( *intrinsic_matrix, float, 2, 0 ) = 0;
+ CV_MAT_ELEM( *intrinsic_matrix, float, 0, 1 ) = 0;
+ CV_MAT_ELEM( *intrinsic_matrix, float, 1, 1 ) = 8;
+ CV_MAT_ELEM( *intrinsic_matrix, float, 2, 1 ) = 0;
+ CV_MAT_ELEM( *intrinsic_matrix, float, 0, 2 ) = 3;
+ CV_MAT_ELEM( *intrinsic_matrix, float, 1, 2 ) = 3;
+ CV_MAT_ELEM( *intrinsic_matrix, float, 2, 2 ) = 1;
+ }
+ else post("load transformation matrix from %s",filename->s_name);
+
+ // reinitialise size to force reinitialisation of mapx and mapy on next frame
+ this->comp_xsize = 0;
+}
+
+void pix_opencv_calibration :: loadDistMess (t_symbol *filename)
+{
+ if ( filename == NULL ) { error("NULL pointer passed to function loadDist"); return;}
+ distortion_coeffs = (CvMat*)cvLoad(filename->s_name);
+ if (distortion_coeffs == NULL){
+ distortion_coeffs = cvCreateMat(5, 1, CV_32FC1);
+ post("can't open file %s", filename->s_name);
+ // zeros distortion coeffs
+ for ( int i = 0 ; i < 5 ; i++ ) {
+ CV_MAT_ELEM( *distortion_coeffs, float, i, 0 ) = 0.0;
+ }
+ }
+ else post("load distortion coefficients from %s",filename->s_name);
+
+ // reinitialise size to force reinitialisation of mapx and mapy on next frame
+ this->comp_xsize = 0;
+}
+
+void pix_opencv_calibration :: writeIntraMess (t_symbol *filename)
+{
+ // printf("write intrinsic matrix\n");
+ cvSave(filename->s_name,intrinsic_matrix);
+}
+
+void pix_opencv_calibration :: writeDistMess (t_symbol *filename)
+{
+ // printf("write distorsion coeffs\n");
+ cvSave(filename->s_name,distortion_coeffs);
+}
+
+void pix_opencv_calibration :: floatCalibrationhMess (float calib_flag)
+{
+ this->calibration=calib_flag;
+ if ( this->calibration == 1 ) {
+ this->success_count = 0;
+ this->frame = 0;
+ }
+ post("calibration : %d", this->calibration);
+}
+
+void pix_opencv_calibration :: patternSizeMess (float xsize, float ysize)
+{
+ if (calibration) error("you can't change pattern size during calibration"); return;
+ if ( xsize < 3 || ysize < 3 ) error("patternSize should be at least 3x3"); return;
+ this->patternSize[0]=xsize;
+ this->patternSize[1]=ysize;
+}
+
+void pix_opencv_calibration :: viewMess (int view)
+{
+ if ( calibration == 1 ) {error("you can't change view number during calibration !"); return;}
+ board_view_nb=view<2?2:view;
+ if (view < 2) error("view should be greater or equal to 2");
+
+ cvReleaseMat(&image_points);
+ cvReleaseMat(&object_points);
+ cvReleaseMat(&point_counts);
+ image_points = cvCreateMat(patternSize[0]*patternSize[1]*board_view_nb, 2, CV_32FC1);
+ object_points = cvCreateMat(patternSize[0]*patternSize[1]*board_view_nb, 3, CV_32FC1);
+ point_counts = cvCreateMat(board_view_nb, 1, CV_32SC1);
+
+}
+
+void pix_opencv_calibration :: waitMess (int wait)
+{
+ wait_n_frame=wait<1?1:wait;
+ if (wait < 1) error("wait should be greater or equal to 1, you can't calibrate more often than each frame !");
+}
+
+void pix_opencv_calibration :: findChessFlagMess(int adaptThres, int normalize, int filter)
+{
+ adaptThres=adaptThres<=0?0:adaptThres>=1?1:adaptThres;
+ normalize=normalize<=0?0:normalize>=1?1:normalize;
+ filter=filter<=0?0:filter>=1?1:filter;
+ findChessFlag = CV_CALIB_CB_ADAPTIVE_THRESH * adaptThres + CV_CALIB_CB_NORMALIZE_IMAGE * normalize + CV_CALIB_CB_FILTER_QUADS * filter;
+}
+/////////////////////////////////////////////////////////
+// static member function
+//
+/////////////////////////////////////////////////////////
+void pix_opencv_calibration :: obj_setupCallback(t_class *classPtr)
+{
+ class_addmethod(classPtr, (t_method)&pix_opencv_calibration::loadIntraMessCallback,
+ gensym("loadIntra"), A_SYMBOL, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_calibration::loadDistMessCallback,
+ gensym("loadDist"), A_SYMBOL, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_calibration::writeIntraMessCallback,
+ gensym("writeIntra"), A_SYMBOL, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_calibration::writeDistMessCallback,
+ gensym("writeDist"), A_SYMBOL, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_calibration::floatCalibrationMessCallback,
+ gensym("calibration"), A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_calibration::patternSizeMessCallback,
+ gensym("patternSize"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_calibration::viewMessCallback,
+ gensym("view"), A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_calibration::waitMessCallback,
+ gensym("wait"), A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_calibration::findChessFlagMessCallback,
+ gensym("findChessFlag"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+
+}
+void pix_opencv_calibration :: loadIntraMessCallback(void *data, t_symbol* filename)
+{
+ GetMyClass(data)->loadIntraMess(filename);
+}
+void pix_opencv_calibration :: loadDistMessCallback(void *data, t_symbol* filename)
+{
+ GetMyClass(data)->loadDistMess(filename);
+}
+void pix_opencv_calibration :: writeIntraMessCallback(void *data, t_symbol* filename)
+{
+ GetMyClass(data)->writeIntraMess(filename);
+}
+void pix_opencv_calibration :: writeDistMessCallback(void *data, t_symbol* filename)
+{
+ GetMyClass(data)->writeDistMess(filename);
+}
+void pix_opencv_calibration :: floatCalibrationMessCallback(void *data, t_floatarg calib_flag)
+{
+ GetMyClass(data)->floatCalibrationhMess((float)calib_flag);
+}
+void pix_opencv_calibration :: patternSizeMessCallback(void *data, t_floatarg xsize, t_floatarg ysize)
+{
+ GetMyClass(data)->patternSizeMess((float)xsize, (float)ysize);
+}
+void pix_opencv_calibration :: viewMessCallback(void *data, t_floatarg view)
+{
+ GetMyClass(data)->viewMess((int)view);
+}
+void pix_opencv_calibration :: waitMessCallback(void *data, t_floatarg wait)
+{
+ GetMyClass(data)->waitMess((int)wait);
+}
+void pix_opencv_calibration :: findChessFlagMessCallback(void *data, t_floatarg adaptThres, t_floatarg normalize, t_floatarg filter)
+{
+ GetMyClass(data)->findChessFlagMess((int) adaptThres, (int) normalize, (int) filter);
+}
+
diff --git a/pix_opencv_calibration.h b/pix_opencv_calibration.h
new file mode 100644
index 0000000..7114288
--- /dev/null
+++ b/pix_opencv_calibration.h
@@ -0,0 +1,115 @@
+/*-----------------------------------------------------------------
+LOG
+ GEM - Graphics Environment for Multimedia
+
+ Threshold filter
+
+ 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.
+
+-----------------------------------------------------------------*/
+
+#ifndef INCLUDE_pix_opencv_calibration_H_
+#define INCLUDE_pix_opencv_calibration_H_
+
+#ifndef _EiC
+#include "cv.h"
+#endif
+
+#include "Base/GemPixObj.h"
+
+/*-----------------------------------------------------------------
+-------------------------------------------------------------------
+CLASS
+ pix_opencv_calibration
+
+ Threshold filter
+
+KEYWORDS
+ pix
+
+DESCRIPTION
+
+-----------------------------------------------------------------*/
+class GEM_EXTERN pix_opencv_calibration : public GemPixObj
+{
+ CPPEXTERN_HEADER(pix_opencv_calibration, GemPixObj)
+
+ public:
+
+ //////////
+ // Constructor
+ pix_opencv_calibration();
+
+ protected:
+
+ //////////
+ // Destructor
+ virtual ~pix_opencv_calibration();
+
+ //////////
+ // Do the processing
+ virtual void processRGBAImage(imageStruct &image);
+ virtual void processRGBImage(imageStruct &image);
+ virtual void processYUVImage(imageStruct &image);
+ virtual void processGrayImage(imageStruct &image);
+
+ void findCorners ( IplImage *image );
+ void computeCalibration ( IplImage *image );
+
+ //////////
+ // Set the new edge threshold
+ void loadIntraMess(t_symbol *filename);
+ void loadDistMess(t_symbol *filename);
+ void writeIntraMess(t_symbol *filename);
+ void writeDistMess(t_symbol *filename);
+ void floatCalibrationhMess (float calib_flag);
+ void patternSizeMess (float xsize, float ysize);
+ void viewMess (int view);
+ void waitMess (int wait);
+ void findChessFlagMess(int adaptThres, int normalize, int filter);
+
+ // to detect changes in the image size
+ int comp_xsize;
+ int comp_ysize;
+
+ int success_count, /* number of images on wich we correctly found corners */
+ board_view_nb, /* number of views to take */
+ calibration, /* calibration flag */
+ patternSize[2], /* size of the calibration chessboard */
+ frame, /* number of frames analysed for chessboard corner */
+ wait_n_frame, /* number of frames to wait between two take */
+ findChessFlag; // flag for cvFindChessboardCorners
+
+
+ private:
+
+ //////////
+ // Static member functions
+ static void loadIntraMessCallback(void *data, t_symbol* filename);
+ static void loadDistMessCallback(void *data, t_symbol* filename);
+ static void writeIntraMessCallback(void *data, t_symbol* filename);
+ static void writeDistMessCallback(void *data, t_symbol* filename);
+ static void floatCalibrationMessCallback(void *data, t_floatarg calib_flag);
+ static void patternSizeMessCallback(void *data, t_floatarg xsize, t_floatarg ysize);
+ static void viewMessCallback(void *data, t_floatarg view);
+ static void waitMessCallback(void *data, t_floatarg wait);
+ static void findChessFlagMessCallback(void *data, t_floatarg adaptThres, t_floatarg normalize, t_floatarg filter);
+ /////////
+ // CvMat needed
+ CvMat *image_points,
+ *object_points,
+ *point_counts,
+ *intrinsic_matrix,
+ *distortion_coeffs;
+
+ /////////
+ // IplImage needed
+ IplImage *find_rgb, *find_gray, *rgb, *gray, *tmp, *mapx, *mapy;
+};
+
+#endif // for header file