From 06cd3c8ccc5053672211cae4ad20ea9248824241 Mon Sep 17 00:00:00 2001
From: Dennis Evangelista <evangeli@usna.edu>
Date: Fri, 28 Jul 2017 16:21:45 -0400
Subject: [PATCH] Initial commit

---
 .gitignore           |    4 +
 Makefile             |   30 +
 README_FOR_LINUX.TXT |   28 +
 cvcalibinit3.cpp     | 2461 ++++++++++++++++++++++++++++++++++++++++++
 cvcalibinit3.h       |    3 +
 main.cpp             |  242 +++++
 pictures.txt         |    1 +
 7 files changed, 2769 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 Makefile
 create mode 100644 README_FOR_LINUX.TXT
 create mode 100644 cvcalibinit3.cpp
 create mode 100644 cvcalibinit3.h
 create mode 100644 main.cpp
 create mode 100644 pictures.txt

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..eb50090
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+cToMatlab
+outputImages
+*~
+*.jpg
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..2dd9004
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,30 @@
+
+INCS = 
+LIBS = 
+
+
+DEFINCS = -I/usr/include -I/usr/include/opencv2
+DEFLIBS = -L/usr/lib 
+LINKLIBS = -lopencv_core -lopencv_highgui -lopencv_imgproc 
+
+CPP  = g++
+CC   = gcc
+OBJ  = main.o cvcalibinit3.o 
+LINKOBJ  = main.o cvcalibinit3.o 
+BIN  = FindCorners.exe
+RM = rm -f
+
+
+all: $(BIN)
+
+clean:
+	${RM} $(OBJ) $(BIN)
+
+$(BIN): $(OBJ)
+	$(CPP) $(LINKOBJ) -g -o $(BIN)  $(LIBS) $(DEFLIBS) $(LINKLIBS)
+
+main.o: main.cpp
+	$(CPP) -c -g main.cpp -o main.o $(INCS) $(DEFINCS) 
+
+cvcalibinit3.o: cvcalibinit3.cpp
+	$(CPP) -c -g cvcalibinit3.cpp -o cvcalibinit3.o  $(INCS) $(DEFINCS)
diff --git a/README_FOR_LINUX.TXT b/README_FOR_LINUX.TXT
new file mode 100644
index 0000000..75b76a8
--- /dev/null
+++ b/README_FOR_LINUX.TXT
@@ -0,0 +1,28 @@
+How to use this code:
+
+<1> make sure you have opencv library installed. If you have it, please go to step <2>; if not, follow the tips below:
+   - sudo apt-get install libopencv-dev
+   - All the header files will be installed in /usr/include/opencv by default
+   - All the libraries will be installed in /usr/lib by default
+   - go to step <3>
+<2> if you have opencv already installed from source code, please modify the Makefile as:
+   - INCS= your correct opencv include path, e.g. /usr/local/include/opencv (which is the default path of opencv library)
+   - LIBS= your correct opencv lib path, e.g. /usr/local/lib
+<3> make clean;
+<4> make;
+<5> copy the generated FindCorners.exe into the "autoCornerFinder" folder in your toolbox path, replacing the existing one.
+<6> test it by the "Extract grid corners" button in the toolbox, after "Load images". 
+
+NOTE THAT THE CODE WORKS ONLY WITH JPEG IMAGES.
+Note, if you want to display all the processing steps of the corner extraction, just change the flag VIS in cvcalibinit3.cpp to 1.
+Please observe that the exetutable is called withing the "click_ima_calib_rufli.m". in the toolbox path.
+
+If you use this code, please cite the following articles:
+
+1. Scaramuzza, D., Martinelli, A. and Siegwart, R. (2006), A Toolbox for Easily Calibrating Omnidirectional Cameras, Proceedings of the IEEE/RSJ International Conference on Intelligent Robots and Systems  (IROS 2006), Beijing, China, October 2006.
+
+2. Scaramuzza, D., Martinelli, A. and Siegwart, R., (2006). "A Flexible Technique for Accurate Omnidirectional Camera Calibration and Structure from Motion", Proceedings of IEEE International Conference of Vision Systems  (ICVS'06), New York, January 5-7, 2006.
+
+3. Rufli, M., Scaramuzza, D., and Siegwart, R. (2008), Automatic Detection of Checkerboards on Blurred and Distorted Images, Proceedings of the IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS 2008), Nice, France, September 2008.
+
+
diff --git a/cvcalibinit3.cpp b/cvcalibinit3.cpp
new file mode 100644
index 0000000..9ffc933
--- /dev/null
+++ b/cvcalibinit3.cpp
@@ -0,0 +1,2461 @@
+/************************************************************************************\
+    This is improved variant of chessboard corner detection algorithm that
+    uses a graph of connected quads. It is based on the code contributed
+    by Vladimir Vezhnevets and Philip Gruebele.
+    Here is the copyright notice from the original Vladimir's code:
+    ===============================================================
+
+    The algorithms developed and implemented by Vezhnevets Vldimir
+    aka Dead Moroz (vvp@graphics.cs.msu.ru)
+    See http://graphics.cs.msu.su/en/research/calibration/opencv.html
+    for detailed information.
+
+    Reliability additions and modifications made by Philip Gruebele.
+    <a href="mailto:pgruebele@cox.net">pgruebele@cox.net</a>
+
+	His code was adapted for use with low resolution and omnidirectional cameras
+	by Martin Rufli during his Master Thesis under supervision of Davide Scaramuzza, at the ETH Zurich. Further enhancements include:
+		- Increased chance of correct corner matching.
+		- Corner matching over all dilation runs.
+		
+If you use this code, please cite the following articles:
+
+1. Scaramuzza, D., Martinelli, A. and Siegwart, R. (2006), A Toolbox for Easily Calibrating Omnidirectional Cameras, Proceedings of the IEEE/RSJ International Conference on Intelligent Robots and Systems  (IROS 2006), Beijing, China, October 2006.
+2. Scaramuzza, D., Martinelli, A. and Siegwart, R., (2006). "A Flexible Technique for Accurate Omnidirectional Camera Calibration and Structure from Motion", Proceedings of IEEE International Conference of Vision Systems  (ICVS'06), New York, January 5-7, 2006.
+3. Rufli, M., Scaramuzza, D., and Siegwart, R. (2008), Automatic Detection of Checkerboards on Blurred and Distorted Images, Proceedings of the IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS 2008), Nice, France, September 2008.
+
+\************************************************************************************/
+
+//===========================================================================
+// CODE STARTS HERE
+//===========================================================================
+// Include files
+#include <opencv.hpp>
+#include <opencv2/core/internal.hpp>
+
+#include <time.h>
+#include <fstream>
+using namespace std;
+using std::ifstream;
+
+
+// Defines
+#define MAX_CONTOUR_APPROX  7
+
+
+//Ming #define VIS 1
+#define VIS 0
+// Turn on visualization
+#define TIMER 0					// Elapse the function duration times
+
+
+// Definition Contour Struct
+typedef struct CvContourEx
+{
+    CV_CONTOUR_FIELDS()
+    int counter;
+}
+CvContourEx;
+
+
+// Definition Corner Struct
+typedef struct CvCBCorner
+{
+    CvPoint2D32f pt;					// X and y coordinates
+	int row;							// Row and column of the corner 
+	int column;							// in the found pattern
+	bool needsNeighbor;					// Does the corner require a neighbor?
+    int count;							// number of corner neighbors
+    struct CvCBCorner* neighbors[4];	// pointer to all corner neighbors
+}
+CvCBCorner;
+
+
+// Definition Quadrangle Struct
+// This structure stores information about the chessboard quadrange
+typedef struct CvCBQuad
+{
+    int count;							// Number of quad neihbors
+    int group_idx;						// Quad group ID
+    float edge_len;						// Smallest side length^2
+    CvCBCorner *corners[4];				// Coordinates of quad corners
+    struct CvCBQuad *neighbors[4];		// Pointers of quad neighbors
+	bool labeled;						// Has this corner been labeled?
+}
+CvCBQuad;
+
+
+
+//===========================================================================
+// FUNCTION PROTOTYPES
+//===========================================================================
+static int icvGenerateQuads( CvCBQuad **quads, CvCBCorner **corners,
+                             CvMemStorage *storage, CvMat *image, int flags, int dilation,
+							 bool firstRun );
+
+static void mrFindQuadNeighbors2( CvCBQuad *quads, int quad_count, int dilation);
+
+static int mrAugmentBestRun( CvCBQuad *new_quads, int new_quad_count, int new_dilation, 
+							 CvCBQuad **old_quads, int old_quad_count, int old_dilation );
+
+static int icvFindConnectedQuads( CvCBQuad *quads, int quad_count, CvCBQuad **quad_group,
+								  int group_idx,
+                                  CvMemStorage* storage, int dilation );
+
+static void mrLabelQuadGroup( CvCBQuad **quad_group, int count, CvSize pattern_size, 
+							  bool firstRun );
+
+static void mrCopyQuadGroup( CvCBQuad **temp_quad_group, CvCBQuad **out_quad_group, 
+							 int count );
+
+static int icvCleanFoundConnectedQuads( int quad_count, CvCBQuad **quads, 
+									    CvSize pattern_size );
+
+static int mrWriteCorners( CvCBQuad **output_quads, int count, CvSize pattern_size,
+						   int min_number_of_corners );
+
+
+
+//===========================================================================
+// MAIN FUNCTION
+//===========================================================================
+int cvFindChessboardCorners3( const void* arr, CvSize pattern_size,
+                             CvPoint2D32f* out_corners, int* out_corner_count,
+                             int min_number_of_corners )
+{
+//START TIMER
+#if TIMER
+	ofstream FindChessboardCorners2;
+    time_t  start_time = clock();
+#endif
+
+	// PART 0: INITIALIZATION
+	//-----------------------------------------------------------------------
+	// Initialize variables
+	int flags					=  1;	// not part of the function call anymore!
+	int max_count				=  0;
+	int max_dilation_run_ID		= -1;
+    const int min_dilations		=  1;
+    const int max_dilations		=  6;
+    int found					=  0;
+    CvMat* norm_img				=  0;
+    CvMat* thresh_img			=  0;
+	CvMat* thresh_img_save		=  0;
+    CvMemStorage* storage		=  0;
+	
+	CvCBQuad *quads				=  0;
+	CvCBQuad **quad_group		=  0;
+    CvCBCorner *corners			=  0;
+	CvCBCorner **corner_group	=  0;
+	CvCBQuad **output_quad_group = 0;
+	
+    // debug trial. Martin Rufli, 28. Ocober, 2008
+	int block_size = 0;
+
+
+	// Create error message file
+	ofstream error("cToMatlab/error.txt");
+
+	
+	// Set openCV function name and label the function start
+    CV_FUNCNAME( "cvFindChessBoardCornerGuesses2" );
+    __BEGIN__;
+
+
+	// Further initializations
+    int quad_count, group_idx, dilations;
+    CvMat stub, *img = (CvMat*)arr;
+
+
+	// Read image from input
+    CV_CALL( img = cvGetMat( img, &stub ));
+
+
+	// Error handling, write error message to error.txt
+    if( CV_MAT_DEPTH( img->type ) != CV_8U || CV_MAT_CN( img->type ) == 2 )
+	{
+        error << "Only 8-bit grayscale or color images are supported" << endl;
+		error.close();
+		return -1;
+	}
+    if( pattern_size.width < 2 || pattern_size.height < 2 )
+	{
+        error << "Pattern should have at least 2x2 size" << endl;
+		error.close();
+		return -1;
+	}
+	if( pattern_size.width > 127 || pattern_size.height > 127 )
+	{
+        error << "Pattern should not have a size larger than 127 x 127" << endl;
+		error.close();
+		return -1;
+	}
+	/*
+	if( pattern_size.width != pattern_size.height )
+	{
+        error << "In this implementation only square sized checker boards are supported" << endl;
+		error.close();
+		return -1;
+	}
+	*/
+	if( !out_corners )
+	{
+        error << "Null pointer to corners encountered" << endl;
+		error.close();
+		return -1;
+	}
+
+
+	// Create memory storage
+    CV_CALL( storage = cvCreateMemStorage(0) );
+    CV_CALL( thresh_img = cvCreateMat( img->rows, img->cols, CV_8UC1 ));
+	CV_CALL( thresh_img_save = cvCreateMat( img->rows, img->cols, CV_8UC1 ));
+
+
+	// Image histogramm normalization and
+	// BGR to Grayscale image conversion (if applicable)
+	// MARTIN: Set to "false"
+    if( CV_MAT_CN(img->type) != 1 || (flags & CV_CALIB_CB_NORMALIZE_IMAGE) )
+    {
+        CV_CALL( norm_img = cvCreateMat( img->rows, img->cols, CV_8UC1 ));
+
+        if( CV_MAT_CN(img->type) != 1 )
+        {
+            CV_CALL( cvCvtColor( img, norm_img, CV_BGR2GRAY ));
+            img = norm_img;
+        }
+
+        if(false)
+        {
+            cvEqualizeHist( img, norm_img );
+            img = norm_img;
+        }
+    }
+	
+// EVALUATE TIMER
+#if TIMER
+	float time0_1 = (float) (clock() - start_time) / CLOCKS_PER_SEC;
+	FindChessboardCorners2.open("timer/FindChessboardCorners2.txt", ofstream::app);
+	FindChessboardCorners2 << "Time 0.1 for cvFindChessboardCorners2 was " << time0_1 << " seconds." << endl;
+#endif
+
+	// For image binarization (thresholding)
+    // we use an adaptive threshold with a gaussian mask
+	// ATTENTION: Gaussian thresholding takes MUCH more time than Mean thresholding!
+    block_size = cvRound(MIN(img->cols,img->rows)*0.2)|1;
+    cvAdaptiveThreshold( img, thresh_img, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, block_size, 0 );
+	cvCopy( thresh_img, thresh_img_save);
+
+
+	// PART 1: FIND LARGEST PATTERN
+	//-----------------------------------------------------------------------
+	// Checker patterns are tried to be found by dilating the background and
+	// then applying a canny edge finder on the closed contours (checkers).
+	// Try one dilation run, but if the pattern is not found, repeat until
+	// max_dilations is reached.
+    for( dilations = min_dilations; dilations <= max_dilations; dilations++ )
+    {
+		// Calling "cvCopy" again is much faster than rerunning "cvAdaptiveThreshold"
+		cvCopy( thresh_img_save, thresh_img);
+		
+// EVALUATE TIMER
+#if TIMER
+		float time0_2 = (float) (clock() - start_time) / CLOCKS_PER_SEC;
+		FindChessboardCorners2 << "Time 0.2 for cvFindChessboardCorners2 was " << time0_2 << " seconds." << endl;
+#endif
+
+//VISUALIZATION--------------------------------------------------------------
+#if VIS
+ 		cvNamedWindow( "Original Image", 1 );
+		cvShowImage( "Original Image", img);
+		//cvSaveImage("pictureVis/OrigImg.png", img);
+		cvWaitKey(0);
+#endif
+//END------------------------------------------------------------------------
+
+
+		// MARTIN's Code
+		// Use both a rectangular and a cross kernel. In this way, a more
+		// homogeneous dilation is performed, which is crucial for small, 
+		// distorted checkers. Use the CROSS kernel first, since its action
+		// on the image is more subtle
+		IplConvKernel *kernel1 = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_CROSS,NULL);
+		IplConvKernel *kernel2 = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_RECT,NULL);
+
+        if (dilations >= 1)
+			cvDilate( thresh_img, thresh_img, kernel1, 1);
+		if (dilations >= 2)
+			cvDilate( thresh_img, thresh_img, kernel2, 1);
+		if (dilations >= 3)
+			cvDilate( thresh_img, thresh_img, kernel1, 1);
+		if (dilations >= 4)
+			cvDilate( thresh_img, thresh_img, kernel2, 1);
+		if (dilations >= 5)
+			cvDilate( thresh_img, thresh_img, kernel1, 1);
+		if (dilations >= 6)
+			cvDilate( thresh_img, thresh_img, kernel2, 1);
+
+// EVALUATE TIMER
+#if TIMER
+		float time0_3 = (float) (clock() - start_time) / CLOCKS_PER_SEC;
+		FindChessboardCorners2 << "Time 0.3 for cvFindChessboardCorners2 was " << time0_3 << " seconds." << endl;
+#endif
+
+//VISUALIZATION--------------------------------------------------------------
+#if VIS
+		cvNamedWindow( "After adaptive Threshold (and Dilation)", 1 );
+		cvShowImage( "After adaptive Threshold (and Dilation)", thresh_img);
+		//cvSaveImage("pictureVis/afterDilation.png", thresh_img);
+		cvWaitKey(0);
+#endif
+//END------------------------------------------------------------------------ 
+  
+
+        // In order to find rectangles that go to the edge, we draw a white
+		// line around the image edge. Otherwise FindContours will miss those 
+		// clipped rectangle contours. The border color will be the image mean,
+		// because otherwise we risk screwing up filters like cvSmooth()
+        cvRectangle( thresh_img, cvPoint(0,0), cvPoint(thresh_img->cols-1,
+                     thresh_img->rows-1), CV_RGB(255,255,255), 3, 8);
+
+
+		// Generate quadrangles in the following function
+		// "quad_count" is the number of cound quadrangles
+        CV_CALL( quad_count = icvGenerateQuads( &quads, &corners, storage, thresh_img, flags, dilations, true ));
+        if( quad_count <= 0 )
+            continue;
+
+// EVALUATE TIMER
+#if TIMER
+		float time0_4 = (float) (clock() - start_time) / CLOCKS_PER_SEC;
+		FindChessboardCorners2 << "Time 0.4 for cvFindChessboardCorners2 was " << time0_4 << " seconds." << endl;
+#endif
+
+//VISUALIZATION--------------------------------------------------------------
+#if VIS
+  		cvNamedWindow( "all found quads per dilation run", 1 );
+		IplImage* imageCopy2 = cvCreateImage( cvGetSize(thresh_img), 8, 1 );
+		IplImage* imageCopy22 = cvCreateImage( cvGetSize(thresh_img), 8, 3 );
+		cvCopy( thresh_img, imageCopy2);
+		cvCvtColor( imageCopy2, imageCopy22, CV_GRAY2BGR );
+
+		for( int kkk = 0; kkk < quad_count; kkk++ )
+		{
+			CvCBQuad* print_quad = &quads[kkk];
+			CvPoint pt[4];
+			pt[0].x = (int)print_quad->corners[0]->pt.x;
+			pt[0].y = (int)print_quad->corners[0]->pt.y;
+			pt[1].x = (int)print_quad->corners[1]->pt.x;
+			pt[1].y = (int)print_quad->corners[1]->pt.y;
+			pt[2].x = (int)print_quad->corners[2]->pt.x;
+			pt[2].y = (int)print_quad->corners[2]->pt.y;
+			pt[3].x = (int)print_quad->corners[3]->pt.x;
+			pt[3].y = (int)print_quad->corners[3]->pt.y;
+			cvLine( imageCopy22, pt[0], pt[1], CV_RGB(255,255,0), 1, 8 );
+			cvLine( imageCopy22, pt[1], pt[2], CV_RGB(255,255,0), 1, 8 );
+			cvLine( imageCopy22, pt[2], pt[3], CV_RGB(255,255,0), 1, 8 );
+			cvLine( imageCopy22, pt[3], pt[0], CV_RGB(255,255,0), 1, 8 );
+		}
+		cvShowImage( "all found quads per dilation run", imageCopy22);
+		//cvSaveImage("pictureVis/allFoundQuads.png", imageCopy22);
+		cvWaitKey(0);
+#endif
+//END------------------------------------------------------------------------
+
+		
+        // The following function finds and assigns neighbor quads to every 
+		// quadrangle in the immediate vicinity fulfilling certain 
+		// prerequisites
+        CV_CALL( mrFindQuadNeighbors2( quads, quad_count, dilations));
+		
+//VISUALIZATION--------------------------------------------------------------
+#if VIS
+		cvNamedWindow( "quads with neighbors", 1 );
+		IplImage* imageCopy3 = cvCreateImage( cvGetSize(thresh_img), 8, 3 );
+		cvCopy( imageCopy22, imageCopy3);
+		CvPoint pt;
+		int scale = 0;
+		int line_type = CV_AA;
+		CvScalar color = {{0,0,255}};
+		for( int kkk = 0; kkk < quad_count; kkk++ )
+		{
+			CvCBQuad* print_quad2 = &quads[kkk];
+			for( int kkkk = 0; kkkk < 4; kkkk++ )
+			{
+				if( print_quad2->neighbors[kkkk] )
+				{
+					pt.x = (int)(print_quad2->corners[kkkk]->pt.x);
+					pt.y = (int)(print_quad2->corners[kkkk]->pt.y);
+					cvCircle( imageCopy3, pt, 3, color, 1, line_type, scale);
+				}
+			}
+		}
+		cvShowImage( "quads with neighbors", imageCopy3);
+		//cvSaveImage("pictureVis/allFoundNeighbors.png", imageCopy3);
+		cvWaitKey(0);
+#endif
+//END------------------------------------------------------------------------
+
+
+		// Allocate memory
+        CV_CALL( quad_group = (CvCBQuad**)cvAlloc( sizeof(quad_group[0]) * quad_count));
+        CV_CALL( corner_group = (CvCBCorner**)cvAlloc( sizeof(corner_group[0]) * quad_count*4 ));
+
+
+		// The connected quads will be organized in groups. The following loop
+		// increases a "group_idx" identifier.
+		// The function "icvFindConnectedQuads assigns all connected quads
+		// a unique group ID.
+		// If more quadrangles were assigned to a given group (i.e. connected)
+		// than are expected by the input variable "pattern_size", the 
+		// function "icvCleanFoundConnectedQuads" erases the surplus
+		// quadrangles by minimizing the convex hull of the remaining pattern.
+        for( group_idx = 0; ; group_idx++ )
+        {
+            int count;
+            CV_CALL( count = icvFindConnectedQuads( quads, quad_count, quad_group, group_idx, storage, dilations ));
+
+            if( count == 0 )
+                break;
+        
+			CV_CALL( count = icvCleanFoundConnectedQuads( count, quad_group, pattern_size ));
+
+
+			// MARTIN's Code
+			// To save computational time, only proceed, if the number of
+			// found quads during this dilation run is larger than the 
+			// largest previous found number
+			if( count >= max_count)
+			{
+				// set max_count to its new value
+				max_count = count;
+				max_dilation_run_ID = dilations;
+			
+				// The following function labels all corners of every quad 
+				// with a row and column entry.
+				// "count" specifies the number of found quads in "quad_group"
+				// with group identifier "group_idx"
+				// The last parameter is set to "true", because this is the
+				// first function call and some initializations need to be
+				// made.
+				mrLabelQuadGroup( quad_group, max_count, pattern_size, true );
+				
+
+//VISUALIZATION--------------------------------------------------------------
+#if VIS
+				// display all corners in INCREASING ROW AND COLUMN ORDER
+				cvNamedWindow( "Corners in increasing order", 1 );
+				IplImage* imageCopy11 = cvCreateImage( cvGetSize(thresh_img), 8, 3 );
+				cvCopy( imageCopy22, imageCopy11);
+				// Assume min and max rows here, since we are outside of the
+				// relevant function
+				int min_row = -15;
+				int max_row = 15;
+				int min_column = -15;
+				int max_column = 15;
+				for(int i = min_row; i <= max_row; i++)
+				{
+						for(int j = min_column; j <= max_column; j++)
+						{
+							for(int k = 0; k < count; k++)
+							{
+								for(int l = 0; l < 4; l++)
+								{
+									if( ((quad_group[k])->corners[l]->row == i) && ((quad_group[k])->corners[l]->column == j) )
+									{
+										// draw the row and column numbers
+										char str[255];
+										sprintf(str,"%i/%i",i,j);
+										CvFont font;
+										cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.2, 0.2, 0, 1);
+										CvPoint ptt;
+										ptt.x = (int) quad_group[k]->corners[l]->pt.x;
+										ptt.y = (int) quad_group[k]->corners[l]->pt.y;
+										// Mark central corners with a different color than 
+										// border corners
+										if ((quad_group[k])->corners[l]->needsNeighbor == false)
+										{
+											cvPutText(imageCopy11, str, ptt, &font, CV_RGB(0,255,0));
+										}
+										else
+										{
+											cvPutText(imageCopy11, str, ptt, &font, CV_RGB(255,0,0));
+										}
+										cvShowImage( "Corners in increasing order", imageCopy11);
+										//cvSaveImage("pictureVis/CornersIncreasingOrder.tif", imageCopy11);
+										//cvWaitKey(0);
+									}
+								}
+							}
+						}
+				}
+				cvWaitKey(0);
+#endif
+//END------------------------------------------------------------------------
+
+	
+				// Allocate memory
+				CV_CALL( output_quad_group = (CvCBQuad**)cvAlloc( sizeof(output_quad_group[0]) * ((pattern_size.height+2) * (pattern_size.width+2)) ));
+				
+				
+				// The following function copies every member of "quad_group"
+				// to "output_quad_group", because "quad_group" will be 
+				// overwritten during the next loop pass.
+				// "output_quad_group" is a true copy of "quad_group" and 
+				// later used for output
+				mrCopyQuadGroup( quad_group, output_quad_group, max_count );
+			}
+        }
+		
+
+		// Free the allocated variables
+        cvFree( &quads );
+        cvFree( &corners );
+    }
+	
+
+// EVALUATE TIMER
+#if TIMER
+	float time1 = (float) (clock() - start_time) / CLOCKS_PER_SEC;
+	FindChessboardCorners2.open("timer/FindChessboardCorners2.txt", ofstream::app);
+	FindChessboardCorners2 << "Time 1 for cvFindChessboardCorners2 was " << time1 << " seconds." << endl;
+#endif
+
+	// If enough corners have been found already, then there is no need for PART 2 ->EXIT
+	found = mrWriteCorners( output_quad_group, max_count, pattern_size, min_number_of_corners);
+		if (found == -1 || found == 1)
+			EXIT;
+
+	// PART 2: AUGMENT LARGEST PATTERN
+	//-----------------------------------------------------------------------
+	// Instead of saving all found quads of all dilation runs from PART 1, we
+	// just recompute them again, but skipping the dilation run which 
+	// produced the maximum number of found quadrangles.
+	// In essence the first section of PART 2 is identical to the first
+	// section of PART 1.
+    for( dilations = max_dilations; dilations >= min_dilations; dilations-- )
+    {
+		//if(max_dilation_run_ID == dilations)
+		//	continue;
+        
+		// Calling "cvCopy" again is much faster than rerunning "cvAdaptiveThreshold"
+		cvCopy( thresh_img_save, thresh_img);
+        
+		IplConvKernel *kernel1 = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_CROSS,NULL);
+		IplConvKernel *kernel2 = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_RECT,NULL);
+
+        if (dilations >= 1)
+			cvDilate( thresh_img, thresh_img, kernel1, 1);
+		if (dilations >= 2)
+			cvDilate( thresh_img, thresh_img, kernel2, 1);
+		if (dilations >= 3)
+			cvDilate( thresh_img, thresh_img, kernel1, 1);
+		if (dilations >= 4)
+			cvDilate( thresh_img, thresh_img, kernel2, 1);
+		if (dilations >= 5)
+			cvDilate( thresh_img, thresh_img, kernel1, 1);
+		if (dilations >= 6)
+			cvDilate( thresh_img, thresh_img, kernel2, 1);
+    
+        cvRectangle( thresh_img, cvPoint(0,0), cvPoint(thresh_img->cols-1,
+                     thresh_img->rows-1), CV_RGB(255,255,255), 3, 8);
+
+//VISUALIZATION--------------------------------------------------------------
+#if VIS
+		cvNamedWindow( "PART2: Starting Point", 1 );
+		IplImage* imageCopy23 = cvCreateImage( cvGetSize(thresh_img), 8, 3 );
+		cvCvtColor( thresh_img, imageCopy23, CV_GRAY2BGR );
+		
+		CvPoint *pt = new CvPoint[4];
+		for( int kkk = 0; kkk < max_count; kkk++ )
+		{ 
+			CvCBQuad* print_quad2 = output_quad_group[kkk];
+			for( int kkkk = 0; kkkk < 4; kkkk++ )
+			{
+				pt[kkkk].x = (int) print_quad2->corners[kkkk]->pt.x;
+				pt[kkkk].y = (int) print_quad2->corners[kkkk]->pt.y;
+			}
+			// draw a filled polygon
+			cvFillConvexPoly ( imageCopy23, pt, 4, CV_RGB(255*0.1,255*0.25,255*0.6));
+		}
+		// indicate the dilation run
+		char str[255];
+		sprintf(str,"Dilation Run No.: %i",dilations);
+		CvFont font;
+		cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.5, 0.5, 0, 2);
+		//cvPutText(imageCopy23, str, cvPoint(20,20), &font, CV_RGB(0,255,0));
+
+		cvShowImage( "PART2: Starting Point", imageCopy23);
+		cvSaveImage("pictureVis/part2Start.png", imageCopy23);
+		cvWaitKey(0);
+#endif
+//END------------------------------------------------------------------------
+
+
+        CV_CALL( quad_count = icvGenerateQuads( &quads, &corners, storage, thresh_img, flags, dilations, false ));
+        if( quad_count <= 0 )
+            continue;
+			
+
+//VISUALIZATION--------------------------------------------------------------
+#if VIS
+		//draw on top of previous image
+		for( int kkk = 0; kkk < quad_count; kkk++ )
+		{
+			CvCBQuad* print_quad = &quads[kkk];
+
+			CvPoint pt[4];
+			pt[0].x = (int)print_quad->corners[0]->pt.x;
+			pt[0].y = (int)print_quad->corners[0]->pt.y;
+			pt[1].x = (int)print_quad->corners[1]->pt.x;
+			pt[1].y = (int)print_quad->corners[1]->pt.y;
+			pt[2].x = (int)print_quad->corners[2]->pt.x;
+			pt[2].y = (int)print_quad->corners[2]->pt.y;
+			pt[3].x = (int)print_quad->corners[3]->pt.x;
+			pt[3].y = (int)print_quad->corners[3]->pt.y;
+			cvLine( imageCopy23, pt[0], pt[1], CV_RGB(255,0,0), 1, 8 );
+			cvLine( imageCopy23, pt[1], pt[2], CV_RGB(255,0,0), 1, 8 );
+			cvLine( imageCopy23, pt[2], pt[3], CV_RGB(255,0,0), 1, 8 );
+			cvLine( imageCopy23, pt[3], pt[0], CV_RGB(255,0,0), 1, 8 );
+			//compute center of print_quad
+			int x1 = (pt[0].x + pt[1].x)/2;
+			int y1 = (pt[0].y + pt[1].y)/2;
+			int x2 = (pt[2].x + pt[3].x)/2;
+			int y2 = (pt[2].y + pt[3].y)/2;
+			
+			int x3 = (x1 + x2)/2;
+			int y3 = (y1 + y2)/2;
+			// indicate the quad number in the image
+			char str[255];
+			sprintf(str,"%i",kkk);
+			//CvFont font;
+			//cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.5, 0.5, 0, 1);
+			//cvPutText(imageCopy23, str, cvPoint(x3,y3), &font, CV_RGB(0,255,255));
+		}
+
+		for( int kkk = 0; kkk < max_count; kkk++ )
+		{
+			CvCBQuad* print_quad = output_quad_group[kkk];
+
+			CvPoint pt[4];
+			pt[0].x = (int)print_quad->corners[0]->pt.x;
+			pt[0].y = (int)print_quad->corners[0]->pt.y;
+			pt[1].x = (int)print_quad->corners[1]->pt.x;
+			pt[1].y = (int)print_quad->corners[1]->pt.y;
+			pt[2].x = (int)print_quad->corners[2]->pt.x;
+			pt[2].y = (int)print_quad->corners[2]->pt.y;
+			pt[3].x = (int)print_quad->corners[3]->pt.x;
+			pt[3].y = (int)print_quad->corners[3]->pt.y;
+			//compute center of print_quad
+			int x1 = (pt[0].x + pt[1].x)/2;
+			int y1 = (pt[0].y + pt[1].y)/2;
+			int x2 = (pt[2].x + pt[3].x)/2;
+			int y2 = (pt[2].y + pt[3].y)/2;
+			
+			int x3 = (x1 + x2)/2;
+			int y3 = (y1 + y2)/2;
+
+			// indicate the quad number in the image
+			char str[255];
+			sprintf(str,"%i",kkk);
+			//CvFont font;
+			//cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.5, 0.5, 0, 1);
+			//cvPutText(imageCopy23, str, cvPoint(x3,y3), &font, CV_RGB(0,0,0));
+		}
+
+		cvShowImage( "PART2: Starting Point", imageCopy23);
+		cvSaveImage("pictureVis/part2StartAndNewQuads.png", imageCopy23);
+		cvWaitKey(0);
+#endif
+//END------------------------------------------------------------------------
+
+		
+		// MARTIN's Code
+		// The following loop is executed until no more newly found quads
+		// can be matched to one of the border corners of the largest found
+		// pattern from PART 1.
+		// The function "mrAugmentBestRun" tests whether a quad can be linked
+		// to the existng pattern.
+		// The function "mrLabelQuadGroup" then labels the newly added corners
+		// with the respective row and column entries.
+		int feedBack = -1;
+		while ( feedBack == -1)
+		{
+			feedBack = mrAugmentBestRun( quads, quad_count, dilations, 
+            							 output_quad_group, max_count, max_dilation_run_ID );
+			
+
+//VISUALIZATION--------------------------------------------------------------
+#if VIS
+			if( feedBack == -1)
+			{
+				CvCBQuad* remember_quad;
+				for( int kkk = max_count; kkk < max_count+1; kkk++ )
+				{
+					CvCBQuad* print_quad = output_quad_group[kkk];
+					remember_quad = print_quad;
+					CvPoint pt[4];
+					pt[0].x = (int)print_quad->corners[0]->pt.x;
+					pt[0].y = (int)print_quad->corners[0]->pt.y;
+					pt[1].x = (int)print_quad->corners[1]->pt.x;
+					pt[1].y = (int)print_quad->corners[1]->pt.y;
+					pt[2].x = (int)print_quad->corners[2]->pt.x;
+					pt[2].y = (int)print_quad->corners[2]->pt.y;
+					pt[3].x = (int)print_quad->corners[3]->pt.x;
+					pt[3].y = (int)print_quad->corners[3]->pt.y;
+					cvLine( imageCopy23, pt[0], pt[1], CV_RGB(255,0,0), 2, 8 );
+					cvLine( imageCopy23, pt[1], pt[2], CV_RGB(255,0,0), 2, 8 );
+					cvLine( imageCopy23, pt[2], pt[3], CV_RGB(255,0,0), 2, 8 );
+					cvLine( imageCopy23, pt[3], pt[0], CV_RGB(255,0,0), 2, 8 );
+				}
+
+				cvWaitKey(0);
+				// also draw the corner to which it is connected
+				// Remember it is not yet completely linked!!!
+				for( int kkk = 0; kkk < max_count; kkk++ )
+				{
+					CvCBQuad* print_quad = output_quad_group[kkk];
+
+					for( int kkkk = 0; kkkk < 4; kkkk++)
+					{
+						if(print_quad->neighbors[kkkk] == remember_quad)
+						{
+							CvPoint pt[4];
+							pt[0].x = (int)print_quad->corners[0]->pt.x;
+							pt[0].y = (int)print_quad->corners[0]->pt.y;
+							pt[1].x = (int)print_quad->corners[1]->pt.x;
+							pt[1].y = (int)print_quad->corners[1]->pt.y;
+							pt[2].x = (int)print_quad->corners[2]->pt.x;
+							pt[2].y = (int)print_quad->corners[2]->pt.y;
+							pt[3].x = (int)print_quad->corners[3]->pt.x;
+							pt[3].y = (int)print_quad->corners[3]->pt.y;
+							cvLine( imageCopy23, pt[0], pt[1], CV_RGB(255,0,0), 2, 8 );
+							cvLine( imageCopy23, pt[1], pt[2], CV_RGB(255,0,0), 2, 8 );
+							cvLine( imageCopy23, pt[2], pt[3], CV_RGB(255,0,0), 2, 8 );
+							cvLine( imageCopy23, pt[3], pt[0], CV_RGB(255,0,0), 2, 8 );
+						}
+					}
+				}
+				cvShowImage( "PART2: Starting Point", imageCopy23);
+				cvSaveImage("pictureVis/part2StartAndSelectedQuad.png", imageCopy23);
+				cvWaitKey(0);
+			}
+#endif
+//END------------------------------------------------------------------------
+
+
+			// if we have found a new matching quad
+			if (feedBack == -1)
+			{
+				// increase max_count by one
+				max_count = max_count + 1;
+   				mrLabelQuadGroup( output_quad_group, max_count, pattern_size, false );
+
+
+				// write the found corners to output array
+				// Go to __END__, if enough corners have been found
+				found = mrWriteCorners( output_quad_group, max_count, pattern_size, min_number_of_corners);
+				if (found == -1 || found == 1)
+					EXIT;
+			}
+		}
+	}
+
+
+	// "End of file" jump point
+	// After the command "EXIT" the code jumps here
+    __END__;
+
+
+	/*
+	// MARTIN:
+	found = mrWriteCorners( output_quad_group, max_count, pattern_size, min_number_of_corners);
+	*/
+
+	// If a linking problem was encountered, throw an error message
+    if( found == -1 )
+	{
+        error << "While linking the corners a problem was encountered. No corner sequence is returned. " << endl;
+		error.close();
+		return -1;
+	}
+
+
+	// Release allocated memory
+    cvReleaseMemStorage( &storage );
+    cvReleaseMat( &norm_img );
+    cvReleaseMat( &thresh_img );
+    cvFree( &quads );
+    cvFree( &corners );
+    cvFree( &quad_group );
+    cvFree( &corner_group );
+	cvFree( &output_quad_group );
+	error.close();
+
+// EVALUATE TIMER
+#if TIMER
+	float time3 = (float) (clock() - start_time) / CLOCKS_PER_SEC;
+	FindChessboardCorners2 << "Time 3 for cvFindChessboardCorners2 was " << time3 << " seconds." << endl;
+	FindChessboardCorners2.close();
+#endif
+
+	// Return found
+	// Found can have the values
+	// -1  ->	Error or corner linking problem, see error.txt for more information
+	//  0  ->	Not enough corners were found
+	//  1  ->	Enough corners were found
+    return found;
+}
+
+
+//===========================================================================
+// ERASE OVERHEAD
+//===========================================================================
+// If we found too many connected quads, remove those which probably do not 
+// belong.
+static int
+icvCleanFoundConnectedQuads( int quad_count, CvCBQuad **quad_group, CvSize pattern_size )
+{
+    CvMemStorage *temp_storage = 0;
+    CvPoint2D32f *centers = 0;
+
+    CV_FUNCNAME( "icvCleanFoundConnectedQuads" );
+
+    __BEGIN__;
+
+    CvPoint2D32f center = {0,0};
+    int i, j, k;
+
+
+    // Number of quads this pattern should contain
+    int count = ((pattern_size.width + 1)*(pattern_size.height + 1) + 1)/2;
+
+
+    // If we have more quadrangles than we should, try to eliminate duplicates
+	// or ones which don't belong to the pattern rectangle. Else go to the end
+	// of the function
+    if( quad_count <= count )
+        EXIT;
+
+
+    // Create an array of quadrangle centers
+    CV_CALL( centers = (CvPoint2D32f *)cvAlloc( sizeof(centers[0])*quad_count ));
+    CV_CALL( temp_storage = cvCreateMemStorage(0));
+
+    for( i = 0; i < quad_count; i++ )
+    {
+        CvPoint2D32f ci = {0,0};
+        CvCBQuad* q = quad_group[i];
+
+        for( j = 0; j < 4; j++ )
+        {
+            CvPoint2D32f pt = q->corners[j]->pt;
+            ci.x += pt.x;
+            ci.y += pt.y;
+        }
+
+        ci.x *= 0.25f;
+        ci.y *= 0.25f;
+	
+
+		// Centers(i), is the geometric center of quad(i)
+		// Center, is the center of all found quads
+        centers[i] = ci;
+        center.x += ci.x;
+        center.y += ci.y;
+    }
+    center.x /= quad_count;
+    center.y /= quad_count;
+
+    // If we have more quadrangles than we should, we try to eliminate bad
+	// ones based on minimizing the bounding box. We iteratively remove the
+	// point which reduces the size of the bounding box of the blobs the most
+    // (since we want the rectangle to be as small as possible) remove the
+	// quadrange that causes the biggest reduction in pattern size until we
+	// have the correct number
+    for( ; quad_count > count; quad_count-- )
+    {
+        double min_box_area = DBL_MAX;
+        int skip, min_box_area_index = -1;
+        CvCBQuad *q0, *q;
+
+
+        // For each point, calculate box area without that point
+        for( skip = 0; skip < quad_count; skip++ )
+        {
+            // get bounding rectangle
+            CvPoint2D32f temp = centers[skip]; 
+            centers[skip] = center; 
+            CvMat pointMat = cvMat(1, quad_count, CV_32FC2, centers);
+            CvSeq *hull = cvConvexHull2( &pointMat, temp_storage, CV_CLOCKWISE, 1 );
+            centers[skip] = temp;
+            double hull_area = fabs(cvContourArea(hull, CV_WHOLE_SEQ));
+
+
+            // remember smallest box area
+            if( hull_area < min_box_area )
+            {
+                min_box_area = hull_area;
+                min_box_area_index = skip;
+            }
+            cvClearMemStorage( temp_storage );
+        }
+
+        q0 = quad_group[min_box_area_index];
+
+
+        // remove any references to this quad as a neighbor
+        for( i = 0; i < quad_count; i++ )
+        {
+            q = quad_group[i];
+            for( j = 0; j < 4; j++ )
+            {
+                if( q->neighbors[j] == q0 )
+                {
+                    q->neighbors[j] = 0;
+                    q->count--;
+                    for( k = 0; k < 4; k++ )
+                        if( q0->neighbors[k] == q )
+                        {
+                            q0->neighbors[k] = 0;
+                            q0->count--;
+                            break;
+                        }
+                    break;
+                }
+            }
+        }
+
+		// remove the quad by copying th last quad in the list into its place
+        quad_count--;
+        quad_group[min_box_area_index] = quad_group[quad_count];
+        centers[min_box_area_index] = centers[quad_count];
+    }
+
+    __END__;
+
+    cvReleaseMemStorage( &temp_storage );
+    cvFree( &centers );
+
+    return quad_count;
+}
+
+
+
+//===========================================================================
+// FIND COONECTED QUADS
+//===========================================================================
+static int
+icvFindConnectedQuads( CvCBQuad *quad, int quad_count, CvCBQuad **out_group,
+                       int group_idx, CvMemStorage* storage, int dilation )
+{
+//START TIMER
+#if TIMER
+	ofstream FindConnectedQuads;
+    time_t  start_time = clock();
+#endif
+
+	// initializations
+    CvMemStorage* temp_storage = cvCreateChildMemStorage( storage );
+    CvSeq* stack = cvCreateSeq( 0, sizeof(*stack), sizeof(void*), temp_storage );
+	int i, count = 0;
+
+
+    // Scan the array for a first unlabeled quad
+    for( i = 0; i < quad_count; i++ )
+    {
+        if( quad[i].count > 0 && quad[i].group_idx < 0)
+            break;
+    }
+
+
+    // Recursively find a group of connected quads starting from the seed
+	// quad[i]
+    if( i < quad_count )
+    {
+        CvCBQuad* q = &quad[i];
+        cvSeqPush( stack, &q );
+        out_group[count++] = q;
+        q->group_idx = group_idx;
+
+        while( stack->total )
+        {
+            cvSeqPop( stack, &q );
+            for( i = 0; i < 4; i++ )
+            {
+                CvCBQuad *neighbor = q->neighbors[i];
+
+
+				// If he neighbor exists and the neighbor has more than 0 
+				// neighbors and the neighbor has not been classified yet.
+                if( neighbor && neighbor->count > 0 && neighbor->group_idx < 0 )
+                {
+                    cvSeqPush( stack, &neighbor );
+                    out_group[count++] = neighbor;
+                    neighbor->group_idx = group_idx;
+                }
+            }
+        }
+    }
+
+    cvReleaseMemStorage( &temp_storage );
+	
+// EVALUATE TIMER
+#if TIMER
+	float time = (float) (clock() - start_time) / CLOCKS_PER_SEC;
+	FindConnectedQuads.open("timer/FindConnectedQuads.txt", ofstream::app);
+	FindConnectedQuads << "Time for cvFindConnectedQuads was " << time << " seconds." << endl;
+	FindConnectedQuads.close();
+#endif
+
+    return count;
+}
+
+
+
+//===========================================================================
+// LABEL CORNER WITH ROW AND COLUMN //DONE
+//===========================================================================
+static void mrLabelQuadGroup( CvCBQuad **quad_group, int count, CvSize pattern_size, bool firstRun )
+{
+//START TIMER
+#if TIMER
+	ofstream LabelQuadGroup;
+    time_t  start_time = clock();
+#endif
+
+	// If this is the first function call, a seed quad needs to be selected
+	if (firstRun == true)
+	{
+		// Search for the (first) quad with the maximum number of neighbors
+		// (usually 4). This will be our starting point.
+		int max_id = -1;
+		int max_number = -1;
+		for(int i = 0; i < count; i++ )
+		{
+			CvCBQuad* q = quad_group[i];
+			if( q->count > max_number)
+			{
+				max_number = q->count;
+				max_id = i;
+
+				if (max_number == 4)
+					break;
+			}
+		}
+
+
+		// Mark the starting quad's (per definition) upper left corner with
+		//(0,0) and then proceed clockwise
+		// The following labeling sequence enshures a "right coordinate system"
+		(quad_group[max_id])->labeled = true;
+
+		(quad_group[max_id])->corners[0]->row = 0;
+        (quad_group[max_id])->corners[0]->column = 0;
+		(quad_group[max_id])->corners[1]->row = 0;
+		(quad_group[max_id])->corners[1]->column = 1;
+		(quad_group[max_id])->corners[2]->row = 1;
+		(quad_group[max_id])->corners[2]->column = 1;
+		(quad_group[max_id])->corners[3]->row = 1;
+		(quad_group[max_id])->corners[3]->column = 0;
+	}
+
+
+	// Mark all other corners with their respective row and column
+	bool flag_changed = true;
+	while( flag_changed == true )
+	{
+		// First reset the flag to "false"
+		flag_changed = false;
+
+
+		// Go through all quads top down is faster, since unlabeled quads will
+		// be inserted at the end of the list
+		for( int i = (count-1); i >= 0; i-- )
+		{
+			// Check whether quad "i" has been labeled already
+ 			if ( (quad_group[i])->labeled == false )
+			{
+				// Check its neighbors, whether some of them have been labeled
+				// already
+				for( int j = 0; j < 4; j++ )
+				{
+					// Check whether the neighbor exists (i.e. is not the NULL
+					// pointer)
+					if( (quad_group[i])->neighbors[j] )
+					{
+						CvCBQuad *quadNeighborJ = (quad_group[i])->neighbors[j];
+						
+						
+						// Only proceed, if neighbor "j" was labeled
+						if( quadNeighborJ->labeled == true)
+						{
+							// For every quad it could happen to pass here 
+							// multiple times. We therefore "break" later.
+							// Check whitch of the neighbors corners is 
+							// connected to the current quad
+							int connectedNeighborCornerId = -1;
+							for( int k = 0; k < 4; k++)
+							{
+								if( quadNeighborJ->neighbors[k] == quad_group[i] )
+								{
+									connectedNeighborCornerId = k;
+									
+									
+									// there is only one, therefore
+									break;
+								}
+							}
+
+
+							// For the following calculations we need the row 
+							// and column of the connected neighbor corner and 
+							// all other corners of the connected quad "j", 
+							// clockwise (CW)
+							CvCBCorner *conCorner	 = quadNeighborJ->corners[connectedNeighborCornerId];
+							CvCBCorner *conCornerCW1 = quadNeighborJ->corners[(connectedNeighborCornerId+1)%4];
+							CvCBCorner *conCornerCW2 = quadNeighborJ->corners[(connectedNeighborCornerId+2)%4];
+							CvCBCorner *conCornerCW3 = quadNeighborJ->corners[(connectedNeighborCornerId+3)%4];
+							
+							(quad_group[i])->corners[j]->row			=	conCorner->row;
+							(quad_group[i])->corners[j]->column			=	conCorner->column;
+							(quad_group[i])->corners[(j+1)%4]->row		=	conCorner->row - conCornerCW2->row + conCornerCW3->row;
+							(quad_group[i])->corners[(j+1)%4]->column	=	conCorner->column - conCornerCW2->column + conCornerCW3->column;
+							(quad_group[i])->corners[(j+2)%4]->row		=	conCorner->row + conCorner->row - conCornerCW2->row;
+							(quad_group[i])->corners[(j+2)%4]->column	=	conCorner->column + conCorner->column - conCornerCW2->column;
+							(quad_group[i])->corners[(j+3)%4]->row		=	conCorner->row - conCornerCW2->row + conCornerCW1->row;
+							(quad_group[i])->corners[(j+3)%4]->column	=	conCorner->column - conCornerCW2->column + conCornerCW1->column;
+							
+
+							// Mark this quad as labeled
+							(quad_group[i])->labeled = true;
+							
+
+							// Changes have taken place, set the flag
+							flag_changed = true;
+
+
+							// once is enough!
+							break;
+						}
+					}
+				}
+			}
+		}
+	}
+
+
+	// All corners are marked with row and column
+	// Record the minimal and maximal row and column indices
+	// It is unlikely that more than 8bit checkers are used per dimension, if there are
+	// an error would have been thrown at the beginning of "cvFindChessboardCorners2"
+	int min_row		=  127;
+	int max_row		= -127;
+	int min_column	=  127;
+	int max_column	= -127;
+
+	for(int i = 0; i < count; i++ )
+    {
+		CvCBQuad* q = quad_group[i];
+		
+		for(int j = 0; j < 4; j++ )
+		{
+			if( (q->corners[j])->row > max_row)
+				max_row = (q->corners[j])->row;
+
+			if( (q->corners[j])->row < min_row)
+				min_row = (q->corners[j])->row;
+
+			if( (q->corners[j])->column > max_column)
+				max_column = (q->corners[j])->column;
+
+			if( (q->corners[j])->column < min_column)
+				min_column = (q->corners[j])->column;
+		}
+	}
+
+	// Label all internal corners with "needsNeighbor" = false
+	// Label all external corners with "needsNeighbor" = true,
+	// except if in a given dimension the pattern size is reached
+	for(int i = min_row; i <= max_row; i++)
+	{
+			for(int j = min_column; j <= max_column; j++)
+			{
+				// A flag that indicates, wheter a row/column combination is
+				// executed multiple times
+				bool flagg = false;
+
+
+				// Remember corner and quad
+				int cornerID;
+				int quadID;
+
+				for(int k = 0; k < count; k++)
+				{
+					for(int l = 0; l < 4; l++)
+					{
+						if( ((quad_group[k])->corners[l]->row == i) && ((quad_group[k])->corners[l]->column == j) )
+						{
+							
+							if (flagg == true)
+							{
+								// Passed at least twice through here
+								(quad_group[k])->corners[l]->needsNeighbor = false;
+								(quad_group[quadID])->corners[cornerID]->needsNeighbor = false;
+							}
+							else
+							{
+								// Mark with needs a neighbor, but note the
+								// address
+								(quad_group[k])->corners[l]->needsNeighbor = true;
+								cornerID = l;
+								quadID = k;
+							}
+							
+
+							// set the flag to true
+							flagg = true;
+						}
+					}
+				}
+			}
+	}
+
+	
+	// Complete Linking:
+	// sometimes not all corners were properly linked in "mrFindQuadNeighbors2",
+	// but after labeling each corner with its respective row and column, it is 
+	// possible to match them anyway.
+	for(int i = min_row; i <= max_row; i++)
+	{
+			for(int j = min_column; j <= max_column; j++)
+			{
+				// the following "number" indicates the number of corners which 
+				// correspond to the given (i,j) value
+				// 1	is a border corner or a conrer which still needs a neighbor
+				// 2	is a fully connected internal corner
+				// >2	something went wrong during labeling, report a warning
+				int number = 1;
+
+
+				// remember corner and quad
+				int cornerID;
+				int quadID;
+
+				for(int k = 0; k < count; k++)
+				{
+					for(int l = 0; l < 4; l++)
+					{
+						if( ((quad_group[k])->corners[l]->row == i) && ((quad_group[k])->corners[l]->column == j) )
+						{
+
+							if (number == 1)
+							{
+								// First corner, note its ID
+								cornerID = l;
+								quadID = k;
+							}
+							
+							else if (number == 2)
+							{
+								// Second corner, check wheter this and the 
+								// first one have equal coordinates, else 
+								// interpolate
+								float delta_x = (quad_group[k])->corners[l]->pt.x - (quad_group[quadID])->corners[cornerID]->pt.x;
+								float delta_y = (quad_group[k])->corners[l]->pt.y - (quad_group[quadID])->corners[cornerID]->pt.y;
+								
+								if (delta_x != 0 || delta_y != 0)
+								{
+									// Interpolate
+									(quad_group[k])->corners[l]->pt.x = (quad_group[k])->corners[l]->pt.x - delta_x/2;
+									(quad_group[quadID])->corners[cornerID]->pt.x = (quad_group[quadID])->corners[cornerID]->pt.x + delta_x/2;
+									(quad_group[k])->corners[l]->pt.y = (quad_group[k])->corners[l]->pt.y - delta_y/2;
+									(quad_group[quadID])->corners[cornerID]->pt.y = (quad_group[quadID])->corners[cornerID]->pt.y + delta_y/2;
+								}
+							}
+							else if (number > 2)
+							{
+								// Something went wrong during row/column labeling
+								// Report a Warning
+								// ->Implemented in the function "mrWriteCorners"
+							}
+	
+							// increase the number by one
+							number = number + 1;
+						}
+					}
+				}
+			}
+	}
+
+
+	// Bordercorners don't need any neighbors, if the pattern size in the 
+	// respective direction is reached
+	// The only time we can make shure that the target pattern size is reached in a given
+	// dimension, is when the larger side has reached the target size in the maximal
+	// direction, or if the larger side is larger than the smaller target size and the 
+	// smaller side equals the smaller target size
+	int largerDimPattern = max(pattern_size.height,pattern_size.width);
+	int smallerDimPattern = min(pattern_size.height,pattern_size.width);
+	bool flagSmallerDim1 = false;
+	bool flagSmallerDim2 = false;
+
+	if((largerDimPattern + 1) == max_column - min_column)
+	{
+		flagSmallerDim1 = true;
+		// We found out that in the column direction the target pattern size is reached
+		// Therefore border column corners do not need a neighbor anymore
+		// Go through all corners
+		for( int k = 0; k < count; k++ )
+		{
+			for( int l = 0; l < 4; l++ )
+			{
+				if ( (quad_group[k])->corners[l]->column == min_column || (quad_group[k])->corners[l]->column == max_column)
+				{
+					// Needs no neighbor anymore
+					(quad_group[k])->corners[l]->needsNeighbor = false;
+				}
+			}
+		}		
+	}
+
+	if((largerDimPattern + 1) == max_row - min_row)
+	{
+		flagSmallerDim2 = true;
+		// We found out that in the column direction the target pattern size is reached
+		// Therefore border column corners do not need a neighbor anymore
+		// Go through all corners
+		for( int k = 0; k < count; k++ )
+		{
+			for( int l = 0; l < 4; l++ )
+			{
+				if ( (quad_group[k])->corners[l]->row == min_row || (quad_group[k])->corners[l]->row == max_row)
+				{
+					// Needs no neighbor anymore
+					(quad_group[k])->corners[l]->needsNeighbor = false;
+				}
+			}
+		}		
+	}
+
+
+	// Check the two flags: 
+	//	-	If one is true and the other false, then the pattern target 
+	//		size was reached in in one direction -> We can check, whether the target 
+	//		pattern size is also reached in the other direction
+	//  -	If both are set to true, then we deal with a square board -> do nothing
+	//  -	If both are set to false -> There is a possibility that the larger side is
+	//		larger than the smaller target size -> Check and if true, then check whether
+	//		the other side has the same size as the smaller target size
+	if( (flagSmallerDim1 == false && flagSmallerDim2 == true) )
+	{
+		// Larger target pattern size is in row direction, check wheter smaller target
+		// pattern size is reached in column direction
+		if((smallerDimPattern + 1) == max_column - min_column)
+		{
+			for( int k = 0; k < count; k++ )
+			{
+				for( int l = 0; l < 4; l++ )
+				{
+					if ( (quad_group[k])->corners[l]->column == min_column || (quad_group[k])->corners[l]->column == max_column)
+					{
+						// Needs no neighbor anymore
+						(quad_group[k])->corners[l]->needsNeighbor = false;
+					}
+				}
+			}
+		}
+	}
+
+	if( (flagSmallerDim1 == true && flagSmallerDim2 == false) )
+	{
+		// Larger target pattern size is in column direction, check wheter smaller target
+		// pattern size is reached in row direction
+		if((smallerDimPattern + 1) == max_row - min_row)
+		{
+			for( int k = 0; k < count; k++ )
+			{
+				for( int l = 0; l < 4; l++ )
+				{
+					if ( (quad_group[k])->corners[l]->row == min_row || (quad_group[k])->corners[l]->row == max_row)
+					{
+						// Needs no neighbor anymore
+						(quad_group[k])->corners[l]->needsNeighbor = false;
+					}
+				}
+			}
+		}
+	}
+
+	if( (flagSmallerDim1 == false && flagSmallerDim2 == false) && smallerDimPattern + 1 < max_column - min_column )
+	{
+		// Larger target pattern size is in column direction, check wheter smaller target
+		// pattern size is reached in row direction
+		if((smallerDimPattern + 1) == max_row - min_row)
+		{
+			for( int k = 0; k < count; k++ )
+			{
+				for( int l = 0; l < 4; l++ )
+				{
+					if ( (quad_group[k])->corners[l]->row == min_row || (quad_group[k])->corners[l]->row == max_row)
+					{
+						// Needs no neighbor anymore
+						(quad_group[k])->corners[l]->needsNeighbor = false;
+					}
+				}
+			}
+		}
+	}
+
+	if( (flagSmallerDim1 == false && flagSmallerDim2 == false) && smallerDimPattern + 1 < max_row - min_row )
+	{
+		// Larger target pattern size is in row direction, check wheter smaller target
+		// pattern size is reached in column direction
+		if((smallerDimPattern + 1) == max_column - min_column)
+		{
+			for( int k = 0; k < count; k++ )
+			{
+				for( int l = 0; l < 4; l++ )
+				{
+					if ( (quad_group[k])->corners[l]->column == min_column || (quad_group[k])->corners[l]->column == max_column)
+					{
+						// Needs no neighbor anymore
+						(quad_group[k])->corners[l]->needsNeighbor = false;
+					}
+				}
+			}
+		}
+	}
+		
+		
+	
+// EVALUATE TIMER
+#if TIMER
+	float time = (float) (clock() - start_time) / CLOCKS_PER_SEC;
+	LabelQuadGroup.open("timer/LabelQuadGroup.txt", ofstream::app);
+	LabelQuadGroup << "Time for mrLabelQuadGroup was " << time << " seconds." << endl;
+	LabelQuadGroup.close();
+#endif
+
+}
+
+
+
+//===========================================================================
+// PRESERVE LARGEST QUAD GROUP
+//===========================================================================
+// Copies all necessary information of every quad of the largest found group
+// into a new Quad struct array. 
+// This information is then again needed in PART 2 of the MAIN LOOP
+static void mrCopyQuadGroup( CvCBQuad **temp_quad_group, CvCBQuad **for_out_quad_group, int count )
+{
+	for (int i = 0; i < count; i++)
+	{
+		for_out_quad_group[i]				= new CvCBQuad;
+		for_out_quad_group[i]->count		= temp_quad_group[i]->count;
+		for_out_quad_group[i]->edge_len		= temp_quad_group[i]->edge_len;
+		for_out_quad_group[i]->group_idx	= temp_quad_group[i]->group_idx;
+		for_out_quad_group[i]->labeled		= temp_quad_group[i]->labeled;
+		
+		for (int j = 0; j < 4; j++)
+		{
+			for_out_quad_group[i]->corners[j]					= new CvCBCorner;
+			for_out_quad_group[i]->corners[j]->pt.x				= temp_quad_group[i]->corners[j]->pt.x;
+			for_out_quad_group[i]->corners[j]->pt.y				= temp_quad_group[i]->corners[j]->pt.y;
+			for_out_quad_group[i]->corners[j]->row				= temp_quad_group[i]->corners[j]->row;
+			for_out_quad_group[i]->corners[j]->column			= temp_quad_group[i]->corners[j]->column;
+			for_out_quad_group[i]->corners[j]->needsNeighbor	= temp_quad_group[i]->corners[j]->needsNeighbor;
+		}
+	}
+}
+
+
+
+//===========================================================================
+// GIVE A GROUP IDX
+//===========================================================================
+// This function replaces mrFindQuadNeighbors, which in turn replaced
+// icvFindQuadNeighbors
+static void mrFindQuadNeighbors2( CvCBQuad *quads, int quad_count, int dilation)
+{
+//START TIMER
+#if TIMER
+	ofstream FindQuadNeighbors2;
+    time_t  start_time = clock();
+#endif
+
+	// Thresh dilation is used to counter the effect of dilation on the
+	// distance between 2 neighboring corners. Since the distance below is 
+	// computed as its square, we do here the same. Additionally, we take the
+	// conservative assumption that dilation was performed using the 3x3 CROSS
+	// kernel, which coresponds to the 4-neighborhood.
+	const float thresh_dilation = (float)(2*dilation+3)*(2*dilation+3)*2;	// the "*2" is for the x and y component
+    int idx, i, k, j;														// the "3" is for initial corner mismatch
+    float dx, dy, dist;
+	int cur_quad_group = -1;
+
+
+    // Find quad neighbors
+    for( idx = 0; idx < quad_count; idx++ )
+    {
+        CvCBQuad* cur_quad = &quads[idx];
+
+
+		// Go through all quadrangles and label them in groups
+        // For each corner of this quadrangle
+        for( i = 0; i < 4; i++ )
+        {
+            CvPoint2D32f pt;
+            float min_dist = FLT_MAX;
+            int closest_corner_idx = -1;
+            CvCBQuad *closest_quad = 0;
+            CvCBCorner *closest_corner = 0;
+
+            if( cur_quad->neighbors[i] )
+                continue;
+
+            pt = cur_quad->corners[i]->pt;
+
+
+            // Find the closest corner in all other quadrangles
+            for( k = 0; k < quad_count; k++ )
+            {
+                if( k == idx )
+                    continue;
+
+                for( j = 0; j < 4; j++ )
+                {
+					// If it already has a neighbor
+                    if( quads[k].neighbors[j] )
+                        continue;
+
+                    dx = pt.x - quads[k].corners[j]->pt.x;
+                    dy = pt.y - quads[k].corners[j]->pt.y;
+                    dist = dx * dx + dy * dy;
+
+
+					// The following "if" checks, whether "dist" is the
+					// shortest so far and smaller than the smallest
+					// edge length of the current and target quads
+                    if( dist < min_dist && 
+						dist <= (cur_quad->edge_len + thresh_dilation) &&
+                        dist <= (quads[k].edge_len + thresh_dilation)    )
+                    {
+						// First Check everything from the viewpoint of the current quad
+						// compute midpoints of "parallel" quad sides 1
+						float x1 = (cur_quad->corners[i]->pt.x + cur_quad->corners[(i+1)%4]->pt.x)/2;
+						float y1 = (cur_quad->corners[i]->pt.y + cur_quad->corners[(i+1)%4]->pt.y)/2;				
+						float x2 = (cur_quad->corners[(i+2)%4]->pt.x + cur_quad->corners[(i+3)%4]->pt.x)/2;
+						float y2 = (cur_quad->corners[(i+2)%4]->pt.y + cur_quad->corners[(i+3)%4]->pt.y)/2;	
+						// compute midpoints of "parallel" quad sides 2
+						float x3 = (cur_quad->corners[i]->pt.x + cur_quad->corners[(i+3)%4]->pt.x)/2;
+						float y3 = (cur_quad->corners[i]->pt.y + cur_quad->corners[(i+3)%4]->pt.y)/2;				
+						float x4 = (cur_quad->corners[(i+1)%4]->pt.x + cur_quad->corners[(i+2)%4]->pt.x)/2;
+						float y4 = (cur_quad->corners[(i+1)%4]->pt.y + cur_quad->corners[(i+2)%4]->pt.y)/2;	
+						
+						// MARTIN: Heuristic
+						// For the corner "j" of quad "k" to be considered, 
+						// it needs to be on the same side of the two lines as 
+						// corner "i". This is given, if the cross product has 
+						// the same sign for both computations below:
+						float a1 = x1 - x2;
+						float b1 = y1 - y2;
+						// the current corner
+						float c11 = cur_quad->corners[i]->pt.x - x2;
+						float d11 = cur_quad->corners[i]->pt.y - y2;
+						// the candidate corner
+						float c12 = quads[k].corners[j]->pt.x - x2;
+						float d12 = quads[k].corners[j]->pt.y - y2;
+						float sign11 = a1*d11 - c11*b1;
+						float sign12 = a1*d12 - c12*b1;
+
+						float a2 = x3 - x4;
+						float b2 = y3 - y4;
+						// the current corner
+						float c21 = cur_quad->corners[i]->pt.x - x4;
+						float d21 = cur_quad->corners[i]->pt.y - y4;
+						// the candidate corner
+						float c22 = quads[k].corners[j]->pt.x - x4;
+						float d22 = quads[k].corners[j]->pt.y - y4;
+						float sign21 = a2*d21 - c21*b2;
+						float sign22 = a2*d22 - c22*b2;
+
+
+						// Then make shure that two border quads of the same row or
+						// column don't link. Check from the current corner's view,
+						// whether the corner diagonal from the candidate corner
+						// is also on the same side of the two lines as the current
+						// corner and the candidate corner.
+						float c13 = quads[k].corners[(j+2)%4]->pt.x - x2;
+						float d13 = quads[k].corners[(j+2)%4]->pt.y - y2;
+						float c23 = quads[k].corners[(j+2)%4]->pt.x - x4;
+						float d23 = quads[k].corners[(j+2)%4]->pt.y - y4;
+						float sign13 = a1*d13 - c13*b1;
+						float sign23 = a2*d23 - c23*b2;
+
+
+						// Then check everything from the viewpoint of the candidate quad
+						// compute midpoints of "parallel" quad sides 1
+						float u1 = (quads[k].corners[j]->pt.x + quads[k].corners[(j+1)%4]->pt.x)/2;
+						float v1 = (quads[k].corners[j]->pt.y + quads[k].corners[(j+1)%4]->pt.y)/2;				
+						float u2 = (quads[k].corners[(j+2)%4]->pt.x + quads[k].corners[(j+3)%4]->pt.x)/2;
+						float v2 = (quads[k].corners[(j+2)%4]->pt.y + quads[k].corners[(j+3)%4]->pt.y)/2;	
+						// compute midpoints of "parallel" quad sides 2
+						float u3 = (quads[k].corners[j]->pt.x + quads[k].corners[(j+3)%4]->pt.x)/2;
+						float v3 = (quads[k].corners[j]->pt.y + quads[k].corners[(j+3)%4]->pt.y)/2;				
+						float u4 = (quads[k].corners[(j+1)%4]->pt.x + quads[k].corners[(j+2)%4]->pt.x)/2;
+						float v4 = (quads[k].corners[(j+1)%4]->pt.y + quads[k].corners[(j+2)%4]->pt.y)/2;	
+						
+						// MARTIN: Heuristic
+						// for the corner "j" of quad "k" to be considered, it 
+						// needs to be on the same side of the two lines as 
+						// corner "i". This is again given, if the cross
+						//product has the same sign for both computations below:
+						float a3 = u1 - u2;
+						float b3 = v1 - v2;
+						// the current corner
+						float c31 = cur_quad->corners[i]->pt.x - u2;
+						float d31 = cur_quad->corners[i]->pt.y - v2;
+						// the candidate corner
+						float c32 = quads[k].corners[j]->pt.x - u2;
+						float d32 = quads[k].corners[j]->pt.y - v2;
+						float sign31 = a3*d31-c31*b3;
+						float sign32 = a3*d32-c32*b3;
+
+						float a4 = u3 - u4;
+						float b4 = v3 - v4;
+						// the current corner
+						float c41 = cur_quad->corners[i]->pt.x - u4;
+						float d41 = cur_quad->corners[i]->pt.y - v4;
+						// the candidate corner
+						float c42 = quads[k].corners[j]->pt.x - u4;
+						float d42 = quads[k].corners[j]->pt.y - v4;
+						float sign41 = a4*d41-c41*b4;
+						float sign42 = a4*d42-c42*b4;
+
+
+						// Then make shure that two border quads of the same row or
+						// column don't link. Check from the candidate corner's view,
+						// whether the corner diagonal from the current corner
+						// is also on the same side of the two lines as the current
+						// corner and the candidate corner.
+						float c33 = cur_quad->corners[(i+2)%4]->pt.x - u2;
+						float d33 = cur_quad->corners[(i+2)%4]->pt.y - v2;
+						float c43 = cur_quad->corners[(i+2)%4]->pt.x - u4;
+						float d43 = cur_quad->corners[(i+2)%4]->pt.y - v4;
+						float sign33 = a3*d33-c33*b3;
+						float sign43 = a4*d43-c43*b4;
+
+
+						// Check whether conditions are fulfilled
+						if ( ((sign11 < 0 && sign12 < 0) || (sign11 > 0 && sign12 > 0))  && 
+							 ((sign21 < 0 && sign22 < 0) || (sign21 > 0 && sign22 > 0))  &&
+							 ((sign31 < 0 && sign32 < 0) || (sign31 > 0 && sign32 > 0))  &&   
+							 ((sign41 < 0 && sign42 < 0) || (sign41 > 0 && sign42 > 0))  &&
+							 ((sign11 < 0 && sign13 < 0) || (sign11 > 0 && sign13 > 0))  &&   
+							 ((sign21 < 0 && sign23 < 0) || (sign21 > 0 && sign23 > 0))  &&
+							 ((sign31 < 0 && sign33 < 0) || (sign31 > 0 && sign33 > 0))  &&   
+							 ((sign41 < 0 && sign43 < 0) || (sign41 > 0 && sign43 > 0))    )
+						
+						{
+							closest_corner_idx = j;
+							closest_quad = &quads[k];
+							min_dist = dist;
+						}
+                    }
+                }
+            }
+
+            // Have we found a matching corner point?
+            if( closest_corner_idx >= 0 && min_dist < FLT_MAX )
+            {
+                closest_corner = closest_quad->corners[closest_corner_idx];
+
+
+                // Make shure that the closest quad does not have the current
+				// quad as neighbor already
+                for( j = 0; j < 4; j++ )
+                {
+                    if( closest_quad->neighbors[j] == cur_quad )
+                        break;
+                }
+                if( j < 4 )
+                    continue;
+
+
+				// We've found one more corner - remember it
+                closest_corner->pt.x = (pt.x + closest_corner->pt.x) * 0.5f;
+                closest_corner->pt.y = (pt.y + closest_corner->pt.y) * 0.5f;
+
+                cur_quad->count++;
+                cur_quad->neighbors[i] = closest_quad;
+                cur_quad->corners[i] = closest_corner;
+
+                closest_quad->count++;
+                closest_quad->neighbors[closest_corner_idx] = cur_quad;
+				closest_quad->corners[closest_corner_idx] = closest_corner;
+            }
+        }
+    }
+
+// EVALUATE TIMER
+#if TIMER
+	float time = (float) (clock() - start_time) / CLOCKS_PER_SEC;
+	FindQuadNeighbors2.open("timer/FindQuadNeighbors2.txt", ofstream::app);
+	FindQuadNeighbors2 << "Time for mrFindQuadNeighbors2 was " << time << " seconds." << endl;
+	FindQuadNeighbors2.close();
+#endif
+}
+
+
+
+//===========================================================================
+// AUGMENT PATTERN WITH ADDITIONAL QUADS
+//===========================================================================
+// The first part of the function is basically a copy of 
+// "mrFindQuadNeighbors2"
+// The comparisons between two points and two lines could be computed in their
+// own function
+static int mrAugmentBestRun( CvCBQuad *new_quads, int new_quad_count, int new_dilation, 
+							  CvCBQuad **old_quads, int old_quad_count, int old_dilation )
+{
+//START TIMER
+#if TIMER
+	ofstream AugmentBestRun;
+    time_t  start_time = clock();
+#endif
+
+	// thresh dilation is used to counter the effect of dilation on the
+	// distance between 2 neighboring corners. Since the distance below is 
+	// computed as its square, we do here the same. Additionally, we take the
+	// conservative assumption that dilation was performed using the 3x3 CROSS
+	// kernel, which coresponds to the 4-neighborhood.
+	const float thresh_dilation = (float)(2*new_dilation+3)*(2*old_dilation+3)*2;	// the "*2" is for the x and y component
+    int idx, i, k, j;																// the "3" is for initial corner mismatch
+    float dx, dy, dist;
+	
+
+    // Search all old quads which have a neighbor that needs to be linked
+    for( idx = 0; idx < old_quad_count; idx++ )
+    {
+        CvCBQuad* cur_quad = old_quads[idx];
+
+
+        // For each corner of this quadrangle
+        for( i = 0; i < 4; i++ )
+        {
+            CvPoint2D32f pt;
+            float min_dist = FLT_MAX;
+            int closest_corner_idx = -1;
+            CvCBQuad *closest_quad = 0;
+            CvCBCorner *closest_corner = 0;
+
+
+			// If cur_quad corner[i] is already linked, continue
+            if( cur_quad->corners[i]->needsNeighbor == false )
+                continue;
+
+            pt = cur_quad->corners[i]->pt;
+
+
+            // Look for a match in all new_quads' corners
+            for( k = 0; k < new_quad_count; k++ )
+            {
+				// Only look at unlabeled new quads
+				if( new_quads[k].labeled == true)
+					continue;
+
+                for( j = 0; j < 4; j++ )
+                {
+
+					// Only proceed if they are less than dist away from each
+					// other
+                    dx = pt.x - new_quads[k].corners[j]->pt.x;
+                    dy = pt.y - new_quads[k].corners[j]->pt.y;
+                    dist = dx * dx + dy * dy;
+
+                    if( (dist < min_dist) && 
+						dist <= (cur_quad->edge_len + thresh_dilation) &&
+                        dist <= (new_quads[k].edge_len + thresh_dilation) )
+                    {
+						// First Check everything from the viewpoint of the 
+						// current quad compute midpoints of "parallel" quad 
+						// sides 1
+						float x1 = (cur_quad->corners[i]->pt.x + cur_quad->corners[(i+1)%4]->pt.x)/2;
+						float y1 = (cur_quad->corners[i]->pt.y + cur_quad->corners[(i+1)%4]->pt.y)/2;				
+						float x2 = (cur_quad->corners[(i+2)%4]->pt.x + cur_quad->corners[(i+3)%4]->pt.x)/2;
+						float y2 = (cur_quad->corners[(i+2)%4]->pt.y + cur_quad->corners[(i+3)%4]->pt.y)/2;	
+						// compute midpoints of "parallel" quad sides 2
+						float x3 = (cur_quad->corners[i]->pt.x + cur_quad->corners[(i+3)%4]->pt.x)/2;
+						float y3 = (cur_quad->corners[i]->pt.y + cur_quad->corners[(i+3)%4]->pt.y)/2;				
+						float x4 = (cur_quad->corners[(i+1)%4]->pt.x + cur_quad->corners[(i+2)%4]->pt.x)/2;
+						float y4 = (cur_quad->corners[(i+1)%4]->pt.y + cur_quad->corners[(i+2)%4]->pt.y)/2;	
+						
+						// MARTIN: Heuristic
+						// For the corner "j" of quad "k" to be considered, 
+						// it needs to be on the same side of the two lines as 
+						// corner "i". This is given, if the cross product has 
+						// the same sign for both computations below:
+						float a1 = x1 - x2;
+						float b1 = y1 - y2;
+						// the current corner
+						float c11 = cur_quad->corners[i]->pt.x - x2;
+						float d11 = cur_quad->corners[i]->pt.y - y2;
+						// the candidate corner
+						float c12 = new_quads[k].corners[j]->pt.x - x2;
+						float d12 = new_quads[k].corners[j]->pt.y - y2;
+						float sign11 = a1*d11 - c11*b1;
+						float sign12 = a1*d12 - c12*b1;
+
+						float a2 = x3 - x4;
+						float b2 = y3 - y4;
+						// the current corner
+						float c21 = cur_quad->corners[i]->pt.x - x4;
+						float d21 = cur_quad->corners[i]->pt.y - y4;
+						// the candidate corner
+						float c22 = new_quads[k].corners[j]->pt.x - x4;
+						float d22 = new_quads[k].corners[j]->pt.y - y4;
+						float sign21 = a2*d21 - c21*b2;
+						float sign22 = a2*d22 - c22*b2;
+
+						// Also make shure that two border quads of the same row or
+						// column don't link. Check from the current corner's view,
+						// whether the corner diagonal from the candidate corner
+						// is also on the same side of the two lines as the current
+						// corner and the candidate corner.
+						float c13 = new_quads[k].corners[(j+2)%4]->pt.x - x2;
+						float d13 = new_quads[k].corners[(j+2)%4]->pt.y - y2;
+						float c23 = new_quads[k].corners[(j+2)%4]->pt.x - x4;
+						float d23 = new_quads[k].corners[(j+2)%4]->pt.y - y4;
+						float sign13 = a1*d13 - c13*b1;
+						float sign23 = a2*d23 - c23*b2;
+
+
+						// Second: Then check everything from the viewpoint of
+						// the candidate quad. Compute midpoints of "parallel"
+						// quad sides 1
+						float u1 = (new_quads[k].corners[j]->pt.x + new_quads[k].corners[(j+1)%4]->pt.x)/2;
+						float v1 = (new_quads[k].corners[j]->pt.y + new_quads[k].corners[(j+1)%4]->pt.y)/2;				
+						float u2 = (new_quads[k].corners[(j+2)%4]->pt.x + new_quads[k].corners[(j+3)%4]->pt.x)/2;
+						float v2 = (new_quads[k].corners[(j+2)%4]->pt.y + new_quads[k].corners[(j+3)%4]->pt.y)/2;	
+						// compute midpoints of "parallel" quad sides 2
+						float u3 = (new_quads[k].corners[j]->pt.x + new_quads[k].corners[(j+3)%4]->pt.x)/2;
+						float v3 = (new_quads[k].corners[j]->pt.y + new_quads[k].corners[(j+3)%4]->pt.y)/2;				
+						float u4 = (new_quads[k].corners[(j+1)%4]->pt.x + new_quads[k].corners[(j+2)%4]->pt.x)/2;
+						float v4 = (new_quads[k].corners[(j+1)%4]->pt.y + new_quads[k].corners[(j+2)%4]->pt.y)/2;	
+						
+						// MARTIN: Heuristic
+						// For the corner "j" of quad "k" to be considered, 
+						// it needs to be on the same side of the two lines as 
+						// corner "i". This is given, if the cross product has 
+						// the same sign for both computations below:
+						float a3 = u1 - u2;
+						float b3 = v1 - v2;
+						// the current corner
+						float c31 = cur_quad->corners[i]->pt.x - u2;
+						float d31 = cur_quad->corners[i]->pt.y - v2;
+						// the candidate corner
+						float c32 = new_quads[k].corners[j]->pt.x - u2;
+						float d32 = new_quads[k].corners[j]->pt.y - v2;
+						float sign31 = a3*d31-c31*b3;
+						float sign32 = a3*d32-c32*b3;
+
+						float a4 = u3 - u4;
+						float b4 = v3 - v4;
+						// the current corner
+						float c41 = cur_quad->corners[i]->pt.x - u4;
+						float d41 = cur_quad->corners[i]->pt.y - v4;
+						// the candidate corner
+						float c42 = new_quads[k].corners[j]->pt.x - u4;
+						float d42 = new_quads[k].corners[j]->pt.y - v4;
+						float sign41 = a4*d41-c41*b4;
+						float sign42 = a4*d42-c42*b4;
+
+						// Also make shure that two border quads of the same row or
+						// column don't link. Check from the candidate corner's view,
+						// whether the corner diagonal from the current corner
+						// is also on the same side of the two lines as the current
+						// corner and the candidate corner.
+						float c33 = cur_quad->corners[(i+2)%4]->pt.x - u2;
+						float d33 = cur_quad->corners[(i+2)%4]->pt.y - v2;
+						float c43 = cur_quad->corners[(i+2)%4]->pt.x - u4;
+						float d43 = cur_quad->corners[(i+2)%4]->pt.y - v4;
+						float sign33 = a3*d33-c33*b3;
+						float sign43 = a4*d43-c43*b4;
+
+						
+						// This time we also need to make shure, that no quad
+						// is linked to a quad of another dilation run which 
+						// may lie INSIDE it!!!
+						// Third: Therefore check everything from the viewpoint
+						// of the current quad compute midpoints of "parallel" 
+						// quad sides 1
+						float x5 = cur_quad->corners[i]->pt.x;
+						float y5 = cur_quad->corners[i]->pt.y;				
+						float x6 = cur_quad->corners[(i+1)%4]->pt.x;
+						float y6 = cur_quad->corners[(i+1)%4]->pt.y;	
+						// compute midpoints of "parallel" quad sides 2
+						float x7 = x5;
+						float y7 = y5;				
+						float x8 = cur_quad->corners[(i+3)%4]->pt.x;
+						float y8 = cur_quad->corners[(i+3)%4]->pt.y;	
+						
+						// MARTIN: Heuristic
+						// For the corner "j" of quad "k" to be considered, 
+						// it needs to be on the other side of the two lines than 
+						// corner "i". This is given, if the cross product has 
+						// a different sign for both computations below:
+						float a5 = x6 - x5;
+						float b5 = y6 - y5;
+						// the current corner
+						float c51 = cur_quad->corners[(i+2)%4]->pt.x - x5;
+						float d51 = cur_quad->corners[(i+2)%4]->pt.y - y5;
+						// the candidate corner
+						float c52 = new_quads[k].corners[j]->pt.x - x5;
+						float d52 = new_quads[k].corners[j]->pt.y - y5;
+						float sign51 = a5*d51 - c51*b5;
+						float sign52 = a5*d52 - c52*b5;
+
+						float a6 = x8 - x7;
+						float b6 = y8 - y7;
+						// the current corner
+						float c61 = cur_quad->corners[(i+2)%4]->pt.x - x7;
+						float d61 = cur_quad->corners[(i+2)%4]->pt.y - y7;
+						// the candidate corner
+						float c62 = new_quads[k].corners[j]->pt.x - x7;
+						float d62 = new_quads[k].corners[j]->pt.y - y7;
+						float sign61 = a6*d61 - c61*b6;
+						float sign62 = a6*d62 - c62*b6;
+
+
+						// Fourth: Then check everything from the viewpoint of 
+						// the candidate quad compute midpoints of "parallel" 
+						// quad sides 1
+						float u5 = new_quads[k].corners[j]->pt.x;
+						float v5 = new_quads[k].corners[j]->pt.y;				
+						float u6 = new_quads[k].corners[(j+1)%4]->pt.x;
+						float v6 = new_quads[k].corners[(j+1)%4]->pt.y;	
+						// compute midpoints of "parallel" quad sides 2
+						float u7 = u5;
+						float v7 = v5;				
+						float u8 = new_quads[k].corners[(j+3)%4]->pt.x;
+						float v8 = new_quads[k].corners[(j+3)%4]->pt.y;	
+						
+						// MARTIN: Heuristic
+						// For the corner "j" of quad "k" to be considered, 
+						// it needs to be on the other side of the two lines than 
+						// corner "i". This is given, if the cross product has 
+						// a different sign for both computations below:
+						float a7 = u6 - u5;
+						float b7 = v6 - v5;
+						// the current corner
+						float c71 = cur_quad->corners[i]->pt.x - u5;
+						float d71 = cur_quad->corners[i]->pt.y - v5;
+						// the candidate corner
+						float c72 = new_quads[k].corners[(j+2)%4]->pt.x - u5;
+						float d72 = new_quads[k].corners[(j+2)%4]->pt.y - v5;
+						float sign71 = a7*d71-c71*b7;
+						float sign72 = a7*d72-c72*b7;
+
+						float a8 = u8 - u7;
+						float b8 = v8 - v7;
+						// the current corner
+						float c81 = cur_quad->corners[i]->pt.x - u7;
+						float d81 = cur_quad->corners[i]->pt.y - v7;
+						// the candidate corner
+						float c82 = new_quads[k].corners[(j+2)%4]->pt.x - u7;
+						float d82 = new_quads[k].corners[(j+2)%4]->pt.y - v7;
+						float sign81 = a8*d81-c81*b8;
+						float sign82 = a8*d82-c82*b8;
+
+
+
+
+
+						// Check whether conditions are fulfilled
+						if ( ((sign11 < 0 && sign12 < 0) || (sign11 > 0 && sign12 > 0))  && 
+							 ((sign21 < 0 && sign22 < 0) || (sign21 > 0 && sign22 > 0))  &&
+							 ((sign31 < 0 && sign32 < 0) || (sign31 > 0 && sign32 > 0))  &&   
+							 ((sign41 < 0 && sign42 < 0) || (sign41 > 0 && sign42 > 0))	 &&	
+							 ((sign11 < 0 && sign13 < 0) || (sign11 > 0 && sign13 > 0))  &&   
+							 ((sign21 < 0 && sign23 < 0) || (sign21 > 0 && sign23 > 0))  &&
+							 ((sign31 < 0 && sign33 < 0) || (sign31 > 0 && sign33 > 0))  &&   
+							 ((sign41 < 0 && sign43 < 0) || (sign41 > 0 && sign43 > 0))  &&
+							 ((sign51 < 0 && sign52 > 0) || (sign51 > 0 && sign52 < 0))  && 
+							 ((sign61 < 0 && sign62 > 0) || (sign61 > 0 && sign62 < 0))  &&
+							 ((sign71 < 0 && sign72 > 0) || (sign71 > 0 && sign72 < 0))  &&   
+							 ((sign81 < 0 && sign82 > 0) || (sign81 > 0 && sign82 < 0)) )						
+						{
+							closest_corner_idx = j;
+							closest_quad = &new_quads[k];
+							min_dist = dist;
+						}
+                    }
+                }
+            }
+
+            // Have we found a matching corner point?
+            if( closest_corner_idx >= 0 && min_dist < FLT_MAX )
+            {
+                closest_corner = closest_quad->corners[closest_corner_idx];
+                closest_corner->pt.x = (pt.x + closest_corner->pt.x) * 0.5f;
+                closest_corner->pt.y = (pt.y + closest_corner->pt.y) * 0.5f;
+
+
+                // We've found one more corner - remember it
+				// ATTENTION: write the corner x and y coordinates separately, 
+				// else the crucial row/column entries will be overwritten !!!
+                cur_quad->corners[i]->pt.x = closest_corner->pt.x;
+				cur_quad->corners[i]->pt.y = closest_corner->pt.y;
+				cur_quad->neighbors[i] = closest_quad;
+				closest_quad->corners[closest_corner_idx]->pt.x = closest_corner->pt.x;
+				closest_quad->corners[closest_corner_idx]->pt.y = closest_corner->pt.y;
+				
+				
+				// Label closest quad as labeled. In this way we exclude it
+				// being considered again during the next loop iteration
+				closest_quad->labeled = true;
+
+
+				// We have a new member of the final pattern, copy it over
+				old_quads[old_quad_count]				= new CvCBQuad;
+				old_quads[old_quad_count]->count		= 1;
+				old_quads[old_quad_count]->edge_len		= closest_quad->edge_len;
+				old_quads[old_quad_count]->group_idx	= cur_quad->group_idx;	//the same as the current quad
+				old_quads[old_quad_count]->labeled		= false;				//do it right afterwards
+				
+				
+				// We only know one neighbor for shure, initialize rest with 
+				// the NULL pointer
+				old_quads[old_quad_count]->neighbors[closest_corner_idx]		= cur_quad;
+				old_quads[old_quad_count]->neighbors[(closest_corner_idx+1)%4]	= NULL;
+				old_quads[old_quad_count]->neighbors[(closest_corner_idx+2)%4]	= NULL;
+				old_quads[old_quad_count]->neighbors[(closest_corner_idx+3)%4]	= NULL;
+
+				for (int j = 0; j < 4; j++)
+				{
+					old_quads[old_quad_count]->corners[j]					= new CvCBCorner;
+					old_quads[old_quad_count]->corners[j]->pt.x				= closest_quad->corners[j]->pt.x;
+					old_quads[old_quad_count]->corners[j]->pt.y				= closest_quad->corners[j]->pt.y;
+				}
+
+				cur_quad->neighbors[i] = old_quads[old_quad_count];
+
+
+				// Start the function again
+				return -1;
+            }
+        }
+    }
+	
+// EVALUATE TIMER
+#if TIMER
+	float time = (float) (clock() - start_time) / CLOCKS_PER_SEC;
+	AugmentBestRun.open("timer/AugmentBestRun.txt", ofstream::app);
+	AugmentBestRun << "Time for mrAugmentBestRun was " << time << " seconds." << endl;
+	AugmentBestRun.close();
+#endif
+
+	// Finished, don't start the function again
+	return 1;
+}
+
+
+
+//===========================================================================
+// GENERATE QUADRANGLES
+//===========================================================================
+static int
+icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners,
+                  CvMemStorage *storage, CvMat *image, int flags, int dilation, bool firstRun )
+{
+//START TIMER
+#if TIMER
+	ofstream GenerateQuads;
+    time_t  start_time = clock();
+#endif
+
+	// Initializations
+    int quad_count = 0;
+    CvMemStorage *temp_storage = 0;
+
+    if( out_quads )
+        *out_quads = 0;
+
+    if( out_corners )
+        *out_corners = 0;
+
+    CV_FUNCNAME( "icvGenerateQuads" );
+
+    __BEGIN__;
+
+    CvSeq *src_contour = 0;
+    CvSeq *root;
+    CvContourEx* board = 0;
+    CvContourScanner scanner;
+    int i, idx, min_size;
+
+    CV_ASSERT( out_corners && out_quads );
+
+
+    // Empiric sower bound for the size of allowable quadrangles.
+	// MARTIN, modified: Added "*0.1" in order to find smaller quads.
+	min_size = cvRound( image->cols * image->rows * .03 * 0.01 * 0.92 * 0.1);
+
+
+    // Create temporary storage for contours and the sequence of pointers to
+	// found quadrangles
+    CV_CALL( temp_storage = cvCreateChildMemStorage( storage ));
+    CV_CALL( root = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvSeq*), temp_storage ));
+
+
+    // Initialize contour retrieving routine
+    CV_CALL( scanner = cvStartFindContours( image, temp_storage, sizeof(CvContourEx),
+                                            CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ));
+
+
+    // Get all the contours one by one
+    while( (src_contour = cvFindNextContour( scanner )) != 0 )
+    {
+        CvSeq *dst_contour = 0;
+        CvRect rect = ((CvContour*)src_contour)->rect;
+		
+	
+
+        // Reject contours with a too small perimeter and contours which are 
+		// completely surrounded by another contour
+		// MARTIN: If this function is called during PART 1, then the parameter "first run"
+		// is set to "true". This guarantees, that only "nice" squares are detected.
+		// During PART 2, we allow the polygonial approcimation function below to
+		// approximate more freely, which can result in recognized "squares" that are in
+		// reality multiple blurred and sticked together squares.
+        if( CV_IS_SEQ_HOLE(src_contour) && rect.width*rect.height >= min_size )
+        {
+            int min_approx_level = 2, max_approx_level;
+			if (firstRun == true)
+				max_approx_level = 3;
+			else
+				max_approx_level = MAX_CONTOUR_APPROX;
+            int approx_level;
+            for( approx_level = min_approx_level; approx_level <= max_approx_level; approx_level++ )
+            {
+                dst_contour = cvApproxPoly( src_contour, sizeof(CvContour), temp_storage,
+                                            CV_POLY_APPROX_DP, (float)approx_level );
+                
+				
+				// We call this again on its own output, because sometimes
+                // cvApproxPoly() does not simplify as much as it should.
+                dst_contour = cvApproxPoly( dst_contour, sizeof(CvContour), temp_storage,
+                                            CV_POLY_APPROX_DP, (float)approx_level );
+
+				if( dst_contour->total == 4 )
+                    break;
+            }
+
+
+            // Reject non-quadrangles
+            if(dst_contour->total == 4 && cvCheckContourConvexity(dst_contour) )
+            {
+                CvPoint pt[4];
+                double d1, d2, p = cvContourPerimeter(dst_contour);
+                double area = fabs(cvContourArea(dst_contour, CV_WHOLE_SEQ));
+                double dx, dy;
+
+                for( i = 0; i < 4; i++ )
+                    pt[i] = *(CvPoint*)cvGetSeqElem(dst_contour, i);
+
+                dx = pt[0].x - pt[2].x;
+                dy = pt[0].y - pt[2].y;
+                d1 = sqrt(dx*dx + dy*dy);
+
+                dx = pt[1].x - pt[3].x;
+                dy = pt[1].y - pt[3].y;
+                d2 = sqrt(dx*dx + dy*dy);
+
+                // PHILIPG: Only accept those quadrangles which are more
+				// square than rectangular and which are big enough
+                double d3, d4;
+                dx = pt[0].x - pt[1].x;
+                dy = pt[0].y - pt[1].y;
+                d3 = sqrt(dx*dx + dy*dy);
+                dx = pt[1].x - pt[2].x;
+                dy = pt[1].y - pt[2].y;
+                d4 = sqrt(dx*dx + dy*dy);
+                if(true)//!(flags & CV_CALIB_CB_FILTER_QUADS) ||
+                    //d3*4 > d4 && d4*4 > d3 && d3*d4 < area*1.5 && area > min_size &&
+                    //d1 >= 0.15 * p && d2 >= 0.15 * p )
+                {
+					CvContourEx* parent = (CvContourEx*)(src_contour->v_prev);
+					parent->counter++;
+					if( !board || board->counter < parent->counter )
+						board = parent;
+					dst_contour->v_prev = (CvSeq*)parent;
+					cvSeqPush( root, &dst_contour );
+                }
+            }
+        }
+    }
+
+
+    // Finish contour retrieving
+    cvEndFindContours( &scanner );
+
+
+    // Allocate quad & corner buffers
+    CV_CALL( *out_quads = (CvCBQuad*)cvAlloc(root->total * sizeof((*out_quads)[0])));
+    CV_CALL( *out_corners = (CvCBCorner*)cvAlloc(root->total * 4 * sizeof((*out_corners)[0])));
+
+
+    // Create array of quads structures
+    for( idx = 0; idx < root->total; idx++ )
+    {
+        CvCBQuad* q = &(*out_quads)[quad_count];
+        src_contour = *(CvSeq**)cvGetSeqElem( root, idx );
+        if( (flags & CV_CALIB_CB_FILTER_QUADS) && src_contour->v_prev != (CvSeq*)board )
+            continue;
+
+
+        // Reset group ID
+        memset( q, 0, sizeof(*q) );
+        q->group_idx = -1;
+        assert( src_contour->total == 4 );
+        for( i = 0; i < 4; i++ )
+        {
+            CvPoint2D32f pt = cvPointTo32f(*(CvPoint*)cvGetSeqElem(src_contour, i));
+            CvCBCorner* corner = &(*out_corners)[quad_count*4 + i];
+
+            memset( corner, 0, sizeof(*corner) );
+            corner->pt = pt;
+            q->corners[i] = corner;
+        }
+        q->edge_len = FLT_MAX;
+        for( i = 0; i < 4; i++ )
+        {
+            float dx = q->corners[i]->pt.x - q->corners[(i+1)&3]->pt.x;
+            float dy = q->corners[i]->pt.y - q->corners[(i+1)&3]->pt.y;
+            float d = dx*dx + dy*dy;
+            if( q->edge_len > d )
+                q->edge_len = d;
+        }
+        quad_count++;
+    }
+
+    __END__;
+
+    if( cvGetErrStatus() < 0 )
+    {
+        if( out_quads )
+            cvFree( out_quads );
+        if( out_corners )
+            cvFree( out_corners );
+        quad_count = 0;
+    }
+
+    cvReleaseMemStorage( &temp_storage );
+
+// EVALUATE TIMER
+#if TIMER
+	float time = (float) (clock() - start_time) / CLOCKS_PER_SEC;
+	GenerateQuads.open("timer/GenerateQuads.txt", ofstream::app);
+	GenerateQuads << "Time for icvGenerateQuads was " << time << " seconds." << endl;
+	GenerateQuads.close();
+#endif
+
+    return quad_count;
+}
+
+
+
+//===========================================================================
+// WRITE CORNERS TO FILE
+//===========================================================================
+static int mrWriteCorners( CvCBQuad **output_quads, int count, CvSize pattern_size, int min_number_of_corners )
+{
+	// Initialize
+	int corner_count = 0;
+	bool flagRow = false;
+	bool flagColumn = false;
+	int maxPattern_sizeRow = -1;
+	int maxPattern_sizeColumn = -1;
+
+
+	// Return variable
+	int internal_found = 0;
+	
+
+	// Compute the minimum and maximum row / column ID
+	// (it is unlikely that more than 8bit checkers are used per dimension)
+	int min_row		=  127;
+	int max_row		= -127;
+	int min_column	=  127;
+	int max_column	= -127;
+
+	for(int i = 0; i < count; i++ )
+    {
+		CvCBQuad* q = output_quads[i];
+		
+		for(int j = 0; j < 4; j++ )
+		{
+			if( (q->corners[j])->row > max_row)
+				max_row = (q->corners[j])->row;
+			if( (q->corners[j])->row < min_row)
+				min_row = (q->corners[j])->row;
+			if( (q->corners[j])->column > max_column)
+				max_column = (q->corners[j])->column;
+			if( (q->corners[j])->column < min_column)
+				min_column = (q->corners[j])->column;
+		}
+	}
+
+
+	// If in a given direction the target pattern size is reached, we know exactly how
+	// the checkerboard is oriented.
+	// Else we need to prepare enought "dummy" corners for the worst case.
+	for(int i = 0; i < count; i++ )
+    {
+		CvCBQuad* q = output_quads[i];
+		
+		for(int j = 0; j < 4; j++ )
+		{
+			if( (q->corners[j])->column == max_column && (q->corners[j])->row != min_row && (q->corners[j])->row != max_row )
+			{
+				if( (q->corners[j]->needsNeighbor) == false)
+				{
+					// We know, that the target pattern size is reached
+					// in column direction
+					flagColumn = true;
+				}
+			}
+			if( (q->corners[j])->row == max_row && (q->corners[j])->column != min_column && (q->corners[j])->column != max_column )
+			{
+				if( (q->corners[j]->needsNeighbor) == false)
+				{
+					// We know, that the target pattern size is reached
+					// in row direction
+					flagRow = true;
+				}
+			}
+		}
+	}
+
+	if( flagColumn == true)
+	{
+		if( max_column - min_column == pattern_size.width + 1)
+		{
+			maxPattern_sizeColumn = pattern_size.width;
+			maxPattern_sizeRow = pattern_size.height;
+		}
+		else
+		{
+			maxPattern_sizeColumn = pattern_size.height;
+			maxPattern_sizeRow = pattern_size.width;
+		}
+	}
+	else if( flagRow == true)
+	{
+		if( max_row - min_row == pattern_size.width + 1)
+		{
+			maxPattern_sizeRow = pattern_size.width;
+			maxPattern_sizeColumn = pattern_size.height;
+		}
+		else
+		{
+			maxPattern_sizeRow = pattern_size.height;
+			maxPattern_sizeColumn = pattern_size.width;
+		}
+	}
+	else
+	{
+		// If target pattern size is not reached in at least one of the two
+		// directions,  then we do not know where the remaining corners are
+		// located. Account for this.
+		maxPattern_sizeColumn = max(pattern_size.width, pattern_size.height);
+		maxPattern_sizeRow = max(pattern_size.width, pattern_size.height);
+	}
+
+
+	// Open the output files
+	ofstream cornersX("cToMatlab/cornersX.txt");
+	ofstream cornersY("cToMatlab/cornersY.txt");
+	ofstream cornerInfo("cToMatlab/cornerInfo.txt");
+
+
+	// Write the corners in increasing order to the output file
+	for(int i = min_row + 1; i < maxPattern_sizeRow + min_row + 1; i++)
+	{
+		for(int j = min_column + 1; j < maxPattern_sizeColumn + min_column + 1; j++)
+		{
+			// Reset the iterator
+			int iter = 1;
+
+			for(int k = 0; k < count; k++)
+			{
+				for(int l = 0; l < 4; l++)
+				{
+					if(((output_quads[k])->corners[l]->row == i) && ((output_quads[k])->corners[l]->column == j) )
+					{
+						// Only write corners to the output file, which are connected
+						// i.e. only if iter == 2
+						if( iter == 2)
+						{
+							// The respective row and column have been found, print it to
+							// the output file, only do this once
+							cornersX << (output_quads[k])->corners[l]->pt.x;
+							cornersX << " ";
+							cornersY << (output_quads[k])->corners[l]->pt.y;
+							cornersY << " ";
+
+							corner_count++;
+						}
+						
+
+						// If the iterator is larger than two, this means that more than
+						// two corners have the same row / column entries. Then some
+						// linking errors must have occured and we should not use the found
+						// pattern
+						if (iter > 2)
+							return -1;
+
+						iter++;
+					}
+				}
+			}
+
+			// If the respective row / column is non - existent or is a border corner
+			if (iter == 1 || iter == 2)
+			{
+				cornersX << -1;
+				cornersX << " ";
+				cornersY << -1;
+				cornersY << " ";
+			}
+		}
+		cornersX << endl;
+		cornersY << endl;
+	}
+
+
+	// Write to the corner matrix size info file
+	cornerInfo << maxPattern_sizeRow<< " " << maxPattern_sizeColumn << endl;
+
+
+	// Close the output files
+	cornersX.close(); 
+	cornersY.close();
+	cornerInfo.close();
+
+
+	// check whether enough corners have been found
+	if (corner_count >= min_number_of_corners)
+		internal_found = 1;
+	else
+		internal_found = 0;
+
+
+	// pattern found, or not found?
+	return internal_found;
+}
+
+//===========================================================================
+// END OF FILE
+//===========================================================================
diff --git a/cvcalibinit3.h b/cvcalibinit3.h
new file mode 100644
index 0000000..bbe231e
--- /dev/null
+++ b/cvcalibinit3.h
@@ -0,0 +1,3 @@
+int cvFindChessboardCorners3( const void* arr, CvSize pattern_size,
+                             CvPoint2D32f* out_corners, int* out_corner_count,
+                             int min_number_of_corners );
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..191022a
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,242 @@
+/************************************************************************************\
+    This is improved variant of chessboard corner detection algorithm that
+    uses a graph of connected quads. It is based on the code contributed
+    by Vladimir Vezhnevets and Philip Gruebele.
+    Here is the copyright notice from the original Vladimir's code:
+    ===============================================================
+
+    The algorithms developed and implemented by Vezhnevets Vldimir
+    aka Dead Moroz (vvp@graphics.cs.msu.ru)
+    See http://graphics.cs.msu.su/en/research/calibration/opencv.html
+    for detailed information.
+
+    Reliability additions and modifications made by Philip Gruebele.
+    <a href="mailto:pgruebele@cox.net">pgruebele@cox.net</a>
+
+	His code was adapted for use with low resolution and omnidirectional cameras
+	by Martin Rufli during his Master Thesis under supervision of Davide Scaramuzza, at the ETH Zurich. Further enhancements include:
+		- Increased chance of correct corner matching.
+		- Corner matching over all dilation runs.
+		
+If you use this code, please cite the following articles:
+
+1. Scaramuzza, D., Martinelli, A. and Siegwart, R. (2006), A Toolbox for Easily Calibrating Omnidirectional Cameras, Proceedings of the IEEE/RSJ International Conference on Intelligent Robots and Systems  (IROS 2006), Beijing, China, October 2006.
+2. Scaramuzza, D., Martinelli, A. and Siegwart, R., (2006). "A Flexible Technique for Accurate Omnidirectional Camera Calibration and Structure from Motion", Proceedings of IEEE International Conference of Vision Systems  (ICVS'06), New York, January 5-7, 2006.
+3. Rufli, M., Scaramuzza, D., and Siegwart, R. (2008), Automatic Detection of Checkerboards on Blurred and Distorted Images, Proceedings of the IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS 2008), Nice, France, September 2008.
+
+\************************************************************************************/
+
+
+// Includes
+#include <cstdlib>
+#include <iostream>
+
+#include <opencv.hpp>
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include <fstream>
+using namespace std;
+using std::ifstream;
+
+#include "cvcalibinit3.h"
+/*
+static int cvFindChessboardCorners3( const void* arr, CvSize pattern_size,
+                             CvPoint2D32f* out_corners, int* out_corner_count,
+                             int min_number_of_corners );
+*/	
+
+//===========================================================================
+// MAIN LOOP 
+//===========================================================================
+int main( int argc, char** argv )
+{
+	// CHOOSE METHOD (0= Vladimir Vezhnevets, 1= Martin Rufli)
+	int method = 1;
+
+
+	// Initializations
+	CvSize board_size				= {7,6};
+	const char* input_filename		= 0;
+	CvCapture* capture				= 0;
+	FILE* f							= 0;
+	char imagename[1024];
+	CvMemStorage* storage;
+	CvSeq* image_points_seq			= 0;
+	int elem_size;
+	CvPoint2D32f* image_points_buf	= 0;
+	CvSize img_size					= {0,0};
+	int found						= -2;
+	int min_number_of_corners		= 42;
+	input_filename					= "pictures.txt";
+	//input_filename					= "myVideo2.avi";
+
+	// Create error message file
+	ofstream error("outputImages/error.txt");
+
+
+	// Read the "argv" function input arguments
+	for(int i = 1; i < argc; i++ )
+	{
+		const char* s = argv[i];
+		if( strcmp( s, "-w" ) == 0 )
+		{
+			if( sscanf( argv[++i], "%u", &board_size.width ) != 1 || board_size.width <= 0 )
+			{
+				error << "Invalid board width" << endl;
+				error.close();
+				return -1;
+			}
+		}
+		else if( strcmp( s, "-h" ) == 0 )
+		{
+			if( sscanf( argv[++i], "%u", &board_size.height ) != 1 || board_size.height <= 0 )
+			{
+				error << "Invalid board height" << endl;
+				error.close();
+				return -1;
+			}
+		}
+		else if( strcmp( s, "-m" ) == 0 )
+		{
+			if( sscanf( argv[++i], "%u", &min_number_of_corners ) != 1 )
+			{
+				error << "Invalid minimal number of corners" << endl;
+				error.close();
+				return -1;
+			}
+		}
+		else if( s[0] != '-' )
+			input_filename = s;
+		else
+		{
+				error << "Unknown option" << endl;
+				error.close();
+				return -1;
+		}
+	}
+
+
+	// Close error message file
+	error.close();
+
+
+	// Figure out what kind of image input needs to be prepared
+	if( input_filename )
+	{
+		// Try to open a video sequence
+		//capture = cvCreateFileCapture( input_filename ); //OBRAND commented out
+		if( !capture )
+		{
+			// Try to open an input image
+			f = fopen( input_filename, "rt" );
+			if( !f )
+				return fprintf( stderr, "The input file could not be opened\n" ), -1;
+		}
+	}
+	else
+		// Open a live video stream
+		capture = cvCreateCameraCapture(0);
+
+
+	// Nothing could be opened -> error
+	if( !capture && !f )
+		return fprintf( stderr, "Could not initialize video capture\n" ), -2;
+
+	
+	// Allocate memory
+	elem_size = board_size.width*board_size.height*sizeof(image_points_buf[0]);
+	storage = cvCreateMemStorage( MAX( elem_size*4, 1 << 16 ));
+	image_points_buf = (CvPoint2D32f*)cvAlloc( elem_size );
+	image_points_seq = cvCreateSeq( 0, sizeof(CvSeq), elem_size, storage );
+
+
+	// For loop which goes through all images specified above
+	for(int j = 1;; j++)
+	{
+		// Initializations
+		IplImage *view = 0, *view_gray = 0;
+		int count = 0, blink = 0;
+		CvSize text_size = {0,0};
+		int base_line = 0;
+		// Load the correct image...
+		if( f && fgets( imagename, sizeof(imagename)-2, f ))
+		{
+
+			int l = (int) strlen(imagename);
+			if( l > 0 && imagename[l-1] == '\n' )
+				imagename[--l] = '\0';
+			if( l > 0 )
+			{
+				if( imagename[0] == '#' )
+					continue;
+				// Load as BGR 3 channel image
+				view = cvLoadImage( imagename, 1 );
+				// Currently the following file formats 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
+				// NOTABLY: GIF IS NOT SUPPORTED!
+			}
+		}
+
+
+		// ...Or capture the correct frame from the video
+		else if( capture )
+		{
+			IplImage* view0 = cvQueryFrame( capture );
+			if( view0 )
+			{
+				view = cvCreateImage( cvGetSize(view0), IPL_DEPTH_8U, view0->nChannels );
+				if( view0->origin == IPL_ORIGIN_BL )
+					cvFlip( view0, view, 0 );
+				else
+					cvCopy( view0, view );
+			}
+		}
+
+		
+		// If no more images are to be processed -> break
+		if( !view)
+		{
+			break;
+		}
+
+		// If esc key was pressed -> break
+		int key = cvWaitKey(10);
+		if( key == 27)
+		{
+			break;
+		}
+
+		img_size = cvGetSize(view);
+		
+
+		// Perform the corner finding algorithm
+		// 0 = old method, 1 = New method by Martin Rufli
+		if (method == 0)
+		{
+			//found = cvFindChessboardCorners1( view, board_size,
+			//		image_points_buf, &count, CV_CALIB_CB_ADAPTIVE_THRESH );
+		}
+		else
+		{
+			found = cvFindChessboardCorners3( view, board_size,
+					image_points_buf, &count, min_number_of_corners );
+		}
+
+		if( !view )
+			break;
+		cvReleaseImage( &view );
+	}
+
+	if( capture )
+		cvReleaseCapture( &capture );
+	
+	return found;
+}
diff --git a/pictures.txt b/pictures.txt
new file mode 100644
index 0000000..5d4f25c
--- /dev/null
+++ b/pictures.txt
@@ -0,0 +1 @@
+./VMRImage0.jpg
\ No newline at end of file