Merge remote-tracking branch 'upstream/3.4' into merge-3.4
[platform/upstream/opencv.git] / modules / calib3d / src / calibinit.cpp
index 283a921..9297bd3 100644 (file)
 \************************************************************************************/
 
 #include "precomp.hpp"
-#include "opencv2/imgproc/imgproc_c.h"
-#include "opencv2/calib3d/calib3d_c.h"
 #include "circlesgrid.hpp"
-#include <stdarg.h>
-#include <vector>
 
-using namespace cv;
-using namespace std;
+#include <stack>
 
 //#define ENABLE_TRIM_COL_ROW
 
 //#define DEBUG_CHESSBOARD
+#define DEBUG_CHESSBOARD_TIMEOUT 0  // 0 - wait for 'q'
+
+#include <opencv2/core/utils/logger.defines.hpp>
+//#undef CV_LOG_STRIP_LEVEL
+//#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_VERBOSE + 1
+#include <opencv2/core/utils/logger.hpp>
 
 #ifdef DEBUG_CHESSBOARD
-static int PRINTF( const char* fmt, ... )
-{
-    va_list args;
-    va_start(args, fmt);
-    return vprintf(fmt, args);
-}
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
+#define DPRINTF(...)  CV_LOG_INFO(NULL, cv::format("calib3d: " __VA_ARGS__))
 #else
-#define PRINTF(...)
+#define DPRINTF(...)
 #endif
 
+namespace cv {
+
 //=====================================================================================
 // Implementation for the enhanced calibration object detection
 //=====================================================================================
 
 #define MAX_CONTOUR_APPROX  7
 
+#define USE_CV_FINDCONTOURS  // switch between cv::findContours() and legacy C API
+#ifdef USE_CV_FINDCONTOURS
+struct QuadCountour {
+    Point pt[4];
+    int parent_contour;
+
+    QuadCountour(const Point pt_[4], int parent_contour_) :
+        parent_contour(parent_contour_)
+    {
+        pt[0] = pt_[0]; pt[1] = pt_[1]; pt[2] = pt_[2]; pt[3] = pt_[3];
+    }
+};
+#else
+
+} // namespace
+#include "opencv2/imgproc/imgproc_c.h"
+namespace cv {
+
 struct CvContourEx
 {
     CV_CONTOUR_FIELDS()
     int counter;
 };
+#endif
 
-//=====================================================================================
 
-/// Corner info structure
 /** This structure stores information about the chessboard corner.*/
-struct CvCBCorner
+struct ChessBoardCorner
 {
-    CvPoint2D32f pt; // Coordinates of the corner
+    cv::Point2f pt;  // Coordinates of the corner
     int row;         // Board row index
     int count;       // Number of neighbor corners
-    struct CvCBCorner* neighbors[4]; // Neighbor corners
+    struct ChessBoardCorner* neighbors[4]; // Neighbor corners
+
+    ChessBoardCorner(const cv::Point2f& pt_ = cv::Point2f()) :
+        pt(pt_), row(0), count(0)
+    {
+        neighbors[0] = neighbors[1] = neighbors[2] = neighbors[3] = NULL;
+    }
 
-    float meanDist(int *_n) const
+    float sumDist(int& n_) const
     {
         float sum = 0;
         int n = 0;
-        for( int i = 0; i < 4; i++ )
+        for (int i = 0; i < 4; ++i)
         {
-            if( neighbors[i] )
+            if (neighbors[i])
             {
-                float dx = neighbors[i]->pt.x - pt.x;
-                float dy = neighbors[i]->pt.y - pt.y;
-                sum += sqrt(dx*dx + dy*dy);
+                sum += sqrt(normL2Sqr<float>(neighbors[i]->pt - pt));
                 n++;
             }
         }
-        if(_n)
-            *_n = n;
-        return sum/MAX(n,1);
+        n_ = n;
+        return sum;
     }
 };
 
-//=====================================================================================
-/// Quadrangle contour info structure
-/** This structure stores information about the chessboard quadrange.*/
-struct CvCBQuad
+
+/** This structure stores information about the chessboard quadrangle.*/
+struct ChessBoardQuad
 {
     int count;      // Number of quad neighbors
     int group_idx;  // quad group ID
@@ -148,140 +167,179 @@ struct CvCBQuad
     bool ordered;   // true if corners/neighbors are ordered counter-clockwise
     float edge_len; // quad edge len, in pix^2
     // neighbors and corners are synced, i.e., neighbor 0 shares corner 0
-    CvCBCorner *corners[4]; // Coordinates of quad corners
-    struct CvCBQuad *neighbors[4]; // Pointers of quad neighbors
+    ChessBoardCorner *corners[4]; // Coordinates of quad corners
+    struct ChessBoardQuad *neighbors[4]; // Pointers of quad neighbors
+
+    ChessBoardQuad(int group_idx_ = -1) :
+        count(0),
+        group_idx(group_idx_),
+        row(0), col(0),
+        ordered(0),
+        edge_len(0)
+    {
+        corners[0] = corners[1] = corners[2] = corners[3] = NULL;
+        neighbors[0] = neighbors[1] = neighbors[2] = neighbors[3] = NULL;
+    }
 };
 
-//=====================================================================================
+
 
 #ifdef DEBUG_CHESSBOARD
-#include "opencv2/highgui.hpp"
-#include "opencv2/imgproc.hpp"
 static void SHOW(const std::string & name, Mat & img)
 {
     imshow(name, img);
+#if DEBUG_CHESSBOARD_TIMEOUT
+    waitKey(DEBUG_CHESSBOARD_TIMEOUT);
+#else
     while ((uchar)waitKey(0) != 'q') {}
+#endif
 }
-static void SHOW_QUADS(const std::string & name, const Mat & img_, CvCBQuad * quads, int quads_count)
+static void SHOW_QUADS(const std::string & name, const Mat & img_, ChessBoardQuad * quads, int quads_count)
 {
     Mat img = img_.clone();
     if (img.channels() == 1)
         cvtColor(img, img, COLOR_GRAY2BGR);
     for (int i = 0; i < quads_count; ++i)
     {
-        CvCBQuad & quad = quads[i];
+        ChessBoardQuad & quad = quads[i];
         for (int j = 0; j < 4; ++j)
         {
-            line(img, quad.corners[j]->pt, quad.corners[(j + 1) % 4]->pt, Scalar(0, 240, 0), 1, LINE_AA);
+            line(img, quad.corners[j]->pt, quad.corners[(j + 1) & 3]->pt, Scalar(0, 240, 0), 1, LINE_AA);
         }
     }
     imshow(name, img);
+#if DEBUG_CHESSBOARD_TIMEOUT
+    waitKey(DEBUG_CHESSBOARD_TIMEOUT);
+#else
     while ((uchar)waitKey(0) != 'q') {}
+#endif
 }
 #else
 #define SHOW(...)
 #define SHOW_QUADS(...)
 #endif
 
-//=====================================================================================
 
-static int icvGenerateQuads( CvCBQuad **quads, CvCBCorner **corners,
-                             CvMemStorage *storage, const Mat &image_, int flags, int *max_quad_buf_size);
 
-static bool processQuads(CvCBQuad *quads, int quad_count, CvSize pattern_size, int max_quad_buf_size,
-                         CvMemStorage * storage, CvCBCorner *corners, CvPoint2D32f *out_corners, int *out_corner_count, int & prev_sqr_size);
+class ChessBoardDetector
+{
+public:
+    cv::Mat binarized_image;
+    Size pattern_size;
+
+    cv::AutoBuffer<ChessBoardQuad> all_quads;
+    cv::AutoBuffer<ChessBoardCorner> all_corners;
+
+    int all_quads_count;
 
-/*static int
-icvGenerateQuadsEx( CvCBQuad **out_quads, CvCBCorner **out_corners,
-    CvMemStorage *storage, CvMat *image, CvMat *thresh_img, int dilation, int flags );*/
+    ChessBoardDetector(const Size& pattern_size_) :
+        pattern_size(pattern_size_),
+        all_quads_count(0)
+    {
+    }
 
-static void icvFindQuadNeighbors( CvCBQuad *quads, int quad_count );
+    void reset()
+    {
+        all_quads.deallocate();
+        all_corners.deallocate();
+        all_quads_count = 0;
+    }
 
-static int icvFindConnectedQuads( CvCBQuad *quads, int quad_count,
-                                  CvCBQuad **quad_group, int group_idx,
-                                  CvMemStorage* storage );
+    void generateQuads(const cv::Mat& image_, int flags);
 
-static int icvCheckQuadGroup( CvCBQuad **quad_group, int count,
-                              CvCBCorner **out_corners, CvSize pattern_size );
+    bool processQuads(std::vector<cv::Point2f>& out_corners, int &prev_sqr_size);
 
-static int icvCleanFoundConnectedQuads( int quad_count,
-                CvCBQuad **quads, CvSize pattern_size );
+    void findQuadNeighbors();
 
-static int icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads,
-           int *all_count, CvCBQuad **all_quads, CvCBCorner **corners,
-           CvSize pattern_size, int max_quad_buf_size, CvMemStorage* storage );
+    void findConnectedQuads(std::vector<ChessBoardQuad*>& out_group, int group_idx);
 
-static void icvOrderQuad(CvCBQuad *quad, CvCBCorner *corner, int common);
+    int checkQuadGroup(std::vector<ChessBoardQuad*>& quad_group, std::vector<ChessBoardCorner*>& out_corners);
 
-#ifdef ENABLE_TRIM_COL_ROW
-static int icvTrimCol(CvCBQuad **quads, int count, int col, int dir);
+    int cleanFoundConnectedQuads(std::vector<ChessBoardQuad*>& quad_group);
 
-static int icvTrimRow(CvCBQuad **quads, int count, int row, int dir);
+    int orderFoundConnectedQuads(std::vector<ChessBoardQuad*>& quads);
+
+    void orderQuad(ChessBoardQuad& quad, ChessBoardCorner& corner, int common);
+
+#ifdef ENABLE_TRIM_COL_ROW
+    void trimCol(std::vector<ChessBoardQuad*>& quads, int col, int dir);
+    void trimRow(std::vector<ChessBoardQuad*>& quads, int row, int dir);
 #endif
 
-static int icvAddOuterQuad(CvCBQuad *quad, CvCBQuad **quads, int quad_count,
-                    CvCBQuad **all_quads, int all_count, CvCBCorner **corners, int max_quad_buf_size);
+    int addOuterQuad(ChessBoardQuad& quad, std::vector<ChessBoardQuad*>& quads);
 
-static void icvRemoveQuadFromGroup(CvCBQuad **quads, int count, CvCBQuad *q0);
+    void removeQuadFromGroup(std::vector<ChessBoardQuad*>& quads, ChessBoardQuad& q0);
 
-static int icvCheckBoardMonotony( CvPoint2D32f* corners, CvSize pattern_size );
+    bool checkBoardMonotony(const std::vector<cv::Point2f>& corners);
+};
 
 /***************************************************************************************************/
 //COMPUTE INTENSITY HISTOGRAM OF INPUT IMAGE
-static int icvGetIntensityHistogram( const Mat & img, std::vector<int>& piHist )
+template<typename ArrayContainer>
+static void icvGetIntensityHistogram256(const Mat& img, ArrayContainer& piHist)
 {
+    for (int i = 0; i < 256; i++)
+        piHist[i] = 0;
     // sum up all pixel in row direction and divide by number of columns
-    for ( int j=0; j<img.rows; j++ )
+    for (int j = 0; j < img.rows; ++j)
     {
-        const uchar * row = img.ptr(j);
-        for ( int i=0; i<img.cols; i++ )
+        const uchar* row = img.ptr<uchar>(j);
+        for (int i = 0; i < img.cols; i++)
         {
             piHist[row[i]]++;
         }
     }
-    return 0;
 }
 /***************************************************************************************************/
 //SMOOTH HISTOGRAM USING WINDOW OF SIZE 2*iWidth+1
-static int icvSmoothHistogram( const std::vector<int>& piHist, std::vector<int>& piHistSmooth, int iWidth )
+template<int iWidth_, typename ArrayContainer>
+static void icvSmoothHistogram256(const ArrayContainer& piHist, ArrayContainer& piHistSmooth, int iWidth = 0)
 {
-    int iIdx;
-    for ( int i=0; i<256; i++)
+    CV_DbgAssert(iWidth_ == 0 || (iWidth == iWidth_ || iWidth == 0));
+    iWidth = (iWidth_ != 0) ? iWidth_ : iWidth;
+    CV_Assert(iWidth > 0);
+    CV_DbgAssert(piHist.size() == 256);
+    CV_DbgAssert(piHistSmooth.size() == 256);
+    for (int i = 0; i < 256; ++i)
     {
+        int iIdx_min = std::max(0, i - iWidth);
+        int iIdx_max = std::min(255, i + iWidth);
         int iSmooth = 0;
-        for ( int ii=-iWidth; ii<=iWidth; ii++)
+        for (int iIdx = iIdx_min; iIdx <= iIdx_max; ++iIdx)
         {
-            iIdx = i+ii;
-            if (iIdx > 0 && iIdx < 256)
-            {
-                iSmooth += piHist[iIdx];
-            }
+            CV_DbgAssert(iIdx >= 0 && iIdx < 256);
+            iSmooth += piHist[iIdx];
         }
         piHistSmooth[i] = iSmooth/(2*iWidth+1);
     }
-    return 0;
 }
 /***************************************************************************************************/
 //COMPUTE FAST HISTOGRAM GRADIENT
-static int icvGradientOfHistogram( const std::vector<int>& piHist, std::vector<int>& piHistGrad )
+template<typename ArrayContainer>
+static void icvGradientOfHistogram256(const ArrayContainer& piHist, ArrayContainer& piHistGrad)
 {
+    CV_DbgAssert(piHist.size() == 256);
+    CV_DbgAssert(piHistGrad.size() == 256);
     piHistGrad[0] = 0;
-    for ( int i=1; i<255; i++)
+    int prev_grad = 0;
+    for (int i = 1; i < 255; ++i)
     {
-        piHistGrad[i] = piHist[i-1] - piHist[i+1];
-        if ( abs(piHistGrad[i]) < 100 )
+        int grad = piHist[i-1] - piHist[i+1];
+        if (std::abs(grad) < 100)
         {
-            if ( piHistGrad[i-1] == 0)
-                piHistGrad[i] = -100;
+            if (prev_grad == 0)
+                grad = -100;
             else
-                piHistGrad[i] = piHistGrad[i-1];
+                grad = prev_grad;
         }
+        piHistGrad[i] = grad;
+        prev_grad = grad;
     }
-    return 0;
+    piHistGrad[255] = 0;
 }
 /***************************************************************************************************/
 //PERFORM SMART IMAGE THRESHOLDING BASED ON ANALYSIS OF INTENSTY HISTOGRAM
-static bool icvBinarizationHistogramBased( Mat & img )
+static void icvBinarizationHistogramBased(Mat & img)
 {
     CV_Assert(img.channels() == 1 && img.depth() == CV_8U);
     int iCols = img.cols;
@@ -289,62 +347,79 @@ static bool icvBinarizationHistogramBased( Mat & img )
     int iMaxPix = iCols*iRows;
     int iMaxPix1 = iMaxPix/100;
     const int iNumBins = 256;
-    std::vector<int> piHistIntensity(iNumBins, 0);
-    std::vector<int> piHistSmooth(iNumBins, 0);
-    std::vector<int> piHistGrad(iNumBins, 0);
-    std::vector<int> piAccumSum(iNumBins, 0);
-    std::vector<int> piMaxPos(20, 0);
-    int iThresh = 0;
-    int iIdx;
-    int iWidth = 1;
+    const int iMaxPos = 20;
+    cv::AutoBuffer<int, 256> piHistIntensity(iNumBins);
+    cv::AutoBuffer<int, 256> piHistSmooth(iNumBins);
+    cv::AutoBuffer<int, 256> piHistGrad(iNumBins);
+    cv::AutoBuffer<int> piMaxPos(iMaxPos);
 
-    icvGetIntensityHistogram( img, piHistIntensity );
+    icvGetIntensityHistogram256(img, piHistIntensity);
 
+#if 0
     // get accumulated sum starting from bright
+    cv::AutoBuffer<int, 256> piAccumSum(iNumBins);
     piAccumSum[iNumBins-1] = piHistIntensity[iNumBins-1];
-    for ( int i=iNumBins-2; i>=0; i-- )
+    for (int i = iNumBins - 2; i >= 0; --i)
     {
         piAccumSum[i] = piHistIntensity[i] + piAccumSum[i+1];
     }
+#endif
 
     // first smooth the distribution
-    icvSmoothHistogram( piHistIntensity, piHistSmooth, iWidth );
+    //const int iWidth = 1;
+    icvSmoothHistogram256<1>(piHistIntensity, piHistSmooth);
 
     // compute gradient
-    icvGradientOfHistogram( piHistSmooth, piHistGrad );
+    icvGradientOfHistogram256(piHistSmooth, piHistGrad);
 
     // check for zeros
-    int iCntMaxima = 0;
-    for ( int i=iNumBins-2; (i>2) && (iCntMaxima<20); i--)
+    unsigned iCntMaxima = 0;
+    for (int i = iNumBins-2; (i > 2) && (iCntMaxima < iMaxPos); --i)
     {
-        if ( (piHistGrad[i-1] < 0) && (piHistGrad[i] > 0) )
+        if ((piHistGrad[i-1] < 0) && (piHistGrad[i] > 0))
         {
-            piMaxPos[iCntMaxima] = i;
-            iCntMaxima++;
+            int iSumAroundMax = piHistSmooth[i-1] + piHistSmooth[i] + piHistSmooth[i+1];
+            if (!(iSumAroundMax < iMaxPix1 && i < 64))
+            {
+                piMaxPos[iCntMaxima++] = i;
+            }
         }
     }
 
-    iIdx = 0;
-    int iSumAroundMax = 0;
-    for ( int i=0; i<iCntMaxima; i++ )
+    DPRINTF("HIST: MAXIMA COUNT: %d (%d, %d, %d, ...)", iCntMaxima,
+            iCntMaxima > 0 ? piMaxPos[0] : -1,
+            iCntMaxima > 1 ? piMaxPos[1] : -1,
+            iCntMaxima > 2 ? piMaxPos[2] : -1);
+
+    int iThresh = 0;
+
+    CV_Assert((size_t)iCntMaxima <= piMaxPos.size());
+
+    DPRINTF("HIST: MAXIMA COUNT: %d (%d, %d, %d, ...)", iCntMaxima,
+                iCntMaxima > 0 ? piMaxPos[0] : -1,
+                iCntMaxima > 1 ? piMaxPos[1] : -1,
+                iCntMaxima > 2 ? piMaxPos[2] : -1);
+
+    if (iCntMaxima == 0)
     {
-        iIdx = piMaxPos[i];
-        iSumAroundMax = piHistSmooth[iIdx-1] + piHistSmooth[iIdx] + piHistSmooth[iIdx+1];
-        if ( iSumAroundMax < iMaxPix1 && iIdx < 64 )
+        // no any maxima inside (only 0 and 255 which are not counted above)
+        // Does image black-write already?
+        const int iMaxPix2 = iMaxPix / 2;
+        for (int sum = 0, i = 0; i < 256; ++i) // select mean intensity
         {
-            for ( int j=i; j<iCntMaxima-1; j++ )
+            sum += piHistIntensity[i];
+            if (sum > iMaxPix2)
             {
-                piMaxPos[j] = piMaxPos[j+1];
+                iThresh = i;
+                break;
             }
-            iCntMaxima--;
-            i--;
         }
     }
-    if ( iCntMaxima == 1)
+    else if (iCntMaxima == 1)
     {
         iThresh = piMaxPos[0]/2;
     }
-    else if ( iCntMaxima == 2)
+    else if (iCntMaxima == 2)
     {
         iThresh = (piMaxPos[0] + piMaxPos[1])/2;
     }
@@ -352,7 +427,7 @@ static bool icvBinarizationHistogramBased( Mat & img )
     {
         // CHECKING THRESHOLD FOR WHITE
         int iIdxAccSum = 0, iAccum = 0;
-        for (int i=iNumBins-1; i>0; i--)
+        for (int i = iNumBins - 1; i > 0; --i)
         {
             iAccum += piHistIntensity[i];
             // iMaxPix/18 is about 5,5%, minimum required number of pixels required for white part of chessboard
@@ -363,12 +438,12 @@ static bool icvBinarizationHistogramBased( Mat & img )
             }
         }
 
-        int iIdxBGMax = 0;
+        unsigned iIdxBGMax = 0;
         int iBrightMax = piMaxPos[0];
         // printf("iBrightMax = %d\n", iBrightMax);
-        for ( int n=0; n<iCntMaxima-1; n++)
+        for (unsigned n = 0; n < iCntMaxima - 1; ++n)
         {
-            iIdxBGMax = n+1;
+            iIdxBGMax = n + 1;
             if ( piMaxPos[n] < iIdxAccSum )
             {
                 break;
@@ -380,15 +455,15 @@ static bool icvBinarizationHistogramBased( Mat & img )
         int iMaxVal = piHistIntensity[piMaxPos[iIdxBGMax]];
 
         //IF TOO CLOSE TO 255, jump to next maximum
-        if ( piMaxPos[iIdxBGMax] >= 250 && iIdxBGMax < iCntMaxima )
+        if (piMaxPos[iIdxBGMax] >= 250 && iIdxBGMax + 1 < iCntMaxima)
         {
             iIdxBGMax++;
             iMaxVal = piHistIntensity[piMaxPos[iIdxBGMax]];
         }
 
-        for ( int n=iIdxBGMax + 1; n<iCntMaxima; n++)
+        for (unsigned n = iIdxBGMax + 1; n < iCntMaxima; n++)
         {
-            if ( piHistIntensity[piMaxPos[n]] >= iMaxVal )
+            if (piHistIntensity[piMaxPos[n]] >= iMaxVal)
             {
                 iMaxVal = piHistIntensity[piMaxPos[n]];
                 iIdxBGMax = n;
@@ -398,70 +473,54 @@ static bool icvBinarizationHistogramBased( Mat & img )
         //SETTING THRESHOLD FOR BINARIZATION
         int iDist2 = (iBrightMax - piMaxPos[iIdxBGMax])/2;
         iThresh = iBrightMax - iDist2;
-        PRINTF("THRESHOLD SELECTED = %d, BRIGHTMAX = %d, DARKMAX = %d\n", iThresh, iBrightMax, piMaxPos[iIdxBGMax]);
+        DPRINTF("THRESHOLD SELECTED = %d, BRIGHTMAX = %d, DARKMAX = %d", iThresh, iBrightMax, piMaxPos[iIdxBGMax]);
     }
 
-
-    if ( iThresh > 0 )
+    if (iThresh > 0)
     {
-        for ( int jj=0; jj<iRows; jj++)
-        {
-            uchar * row = img.ptr(jj);
-            for ( int ii=0; ii<iCols; ii++)
-            {
-                if ( row[ii] < iThresh )
-                    row[ii] = 0;
-                else
-                    row[ii] = 255;
-            }
-        }
+        img = (img >= iThresh);
     }
-
-    return true;
 }
 
-CV_IMPL
-int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
-                             CvPoint2D32f* out_corners, int* out_corner_count,
-                             int flags )
+bool findChessboardCorners(InputArray image_, Size pattern_size,
+                           OutputArray corners_, int flags)
 {
-    int found = 0;
-    CvCBQuad *quads = 0;
-    CvCBCorner *corners = 0;
+    CV_INSTRUMENT_REGION()
 
-    cv::Ptr<CvMemStorage> storage;
+    DPRINTF("==== findChessboardCorners(img=%dx%d, pattern=%dx%d, flags=%d)",
+            image_.cols(), image_.rows(), pattern_size.width, pattern_size.height, flags);
+
+    bool found = false;
 
-    CV_TRY
-    {
-    int k = 0;
     const int min_dilations = 0;
     const int max_dilations = 7;
 
-    if( out_corner_count )
-        *out_corner_count = 0;
+    int type = image_.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
+    Mat img = image_.getMat();
 
-    Mat img = cvarrToMat((CvMat*)arr).clone();
+    CV_CheckType(type, depth == CV_8U && (cn == 1 || cn == 3 || cn == 4),
+            "Only 8-bit grayscale or color images are supported");
 
-    if( img.depth() != CV_8U || (img.channels() != 1 && img.channels() != 3 && img.channels() != 4) )
-       CV_Error( CV_StsUnsupportedFormat, "Only 8-bit grayscale or color images are supported" );
+    if (pattern_size.width <= 2 || pattern_size.height <= 2)
+        CV_Error(Error::StsOutOfRange, "Both width and height of the pattern should have bigger than 2");
 
-    if( pattern_size.width <= 2 || pattern_size.height <= 2 )
-        CV_Error( CV_StsOutOfRange, "Both width and height of the pattern should have bigger than 2" );
+    if (!corners_.needed())
+        CV_Error(Error::StsNullPtr, "Null pointer to corners");
 
-    if( !out_corners )
-        CV_Error( CV_StsNullPtr, "Null pointer to corners" );
+    std::vector<cv::Point2f> out_corners;
 
     if (img.channels() != 1)
     {
         cvtColor(img, img, COLOR_BGR2GRAY);
     }
 
+    int prev_sqr_size = 0;
 
     Mat thresh_img_new = img.clone();
-    icvBinarizationHistogramBased( thresh_img_new ); // process image in-place
+    icvBinarizationHistogramBased(thresh_img_new); // process image in-place
     SHOW("New binarization", thresh_img_new);
 
-    if( flags & CV_CALIB_CB_FAST_CHECK)
+    if (flags & CALIB_CB_FAST_CHECK)
     {
         //perform new method for checking chessboard using a binary image.
         //image is binarised using a threshold dependent on the image histogram
@@ -469,24 +528,20 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
         {
             if (checkChessboard(img, pattern_size) <= 0)
             {
-                return found;
+                corners_.release();
+                return false;
             }
         }
     }
 
-    storage.reset(cvCreateMemStorage(0));
-
-    int prev_sqr_size = 0;
+    ChessBoardDetector detector(pattern_size);
 
     // Try our standard "1" dilation, but if the pattern is not found, iterate the whole procedure with higher dilations.
     // This is necessary because some squares simply do not separate properly with a single dilation.  However,
     // we want to use the minimum number of dilations possible since dilations cause the squares to become smaller,
     // making it difficult to detect smaller squares.
-    for( int dilations = min_dilations; dilations <= max_dilations; dilations++ )
+    for (int dilations = min_dilations; dilations <= max_dilations; dilations++)
     {
-        if (found)
-            break;      // already found it
-
         //USE BINARY IMAGE COMPUTED USING icvBinarizationHistogramBased METHOD
         dilate( thresh_img_new, thresh_img_new, Mat(), Point(-1, -1), 1 );
 
@@ -494,53 +549,59 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
         // 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()...
         rectangle( thresh_img_new, Point(0,0), Point(thresh_img_new.cols-1, thresh_img_new.rows-1), Scalar(255,255,255), 3, LINE_8);
-        int max_quad_buf_size = 0;
-        cvFree(&quads);
-        cvFree(&corners);
-        int quad_count = icvGenerateQuads( &quads, &corners, storage, thresh_img_new, flags, &max_quad_buf_size );
-        PRINTF("Quad count: %d/%d\n", quad_count, (pattern_size.width/2+1)*(pattern_size.height/2+1));
-        SHOW_QUADS("New quads", thresh_img_new, quads, quad_count);
-        if (processQuads(quads, quad_count, pattern_size, max_quad_buf_size, storage, corners, out_corners, out_corner_count, prev_sqr_size))
-            found = 1;
+
+        detector.reset();
+
+#ifdef USE_CV_FINDCONTOURS
+        Mat binarized_img = thresh_img_new;
+#else
+        Mat binarized_img = thresh_img_new.clone(); // make clone because cvFindContours modifies the source image
+#endif
+        detector.generateQuads(binarized_img, flags);
+        DPRINTF("Quad count: %d/%d", detector.all_quads_count, (pattern_size.width/2+1)*(pattern_size.height/2+1));
+        SHOW_QUADS("New quads", thresh_img_new, &detector.all_quads[0], detector.all_quads_count);
+        if (detector.processQuads(out_corners, prev_sqr_size))
+        {
+            found = true;
+            break;
+        }
     }
 
-    PRINTF("Chessboard detection result 0: %d\n", found);
+    DPRINTF("Chessboard detection result 0: %d", (int)found);
 
     // revert to old, slower, method if detection failed
     if (!found)
     {
-        if( flags & CV_CALIB_CB_NORMALIZE_IMAGE )
+        if (flags & CALIB_CB_NORMALIZE_IMAGE)
         {
-            equalizeHist( img, img );
+            img = img.clone();
+            equalizeHist(img, img);
         }
 
         Mat thresh_img;
         prev_sqr_size = 0;
 
-        PRINTF("Fallback to old algorithm\n");
-        const bool useAdaptive = flags & CV_CALIB_CB_ADAPTIVE_THRESH;
+        DPRINTF("Fallback to old algorithm");
+        const bool useAdaptive = flags & CALIB_CB_ADAPTIVE_THRESH;
         if (!useAdaptive)
         {
             // empiric threshold level
             // thresholding performed here and not inside the cycle to save processing time
             double mean = cv::mean(img).val[0];
-            int thresh_level = MAX(cvRound( mean - 10 ), 10);
-            threshold( img, thresh_img, thresh_level, 255, THRESH_BINARY );
+            int thresh_level = std::max(cvRound(mean - 10), 10);
+            threshold(img, thresh_img, thresh_level, 255, THRESH_BINARY);
         }
-        //if flag CV_CALIB_CB_ADAPTIVE_THRESH is not set it doesn't make sense to iterate over k
+        //if flag CALIB_CB_ADAPTIVE_THRESH is not set it doesn't make sense to iterate over k
         int max_k = useAdaptive ? 6 : 1;
-        for( k = 0; k < max_k; k++ )
+        for (int k = 0; k < max_k && !found; k++)
         {
-            for( int dilations = min_dilations; dilations <= max_dilations; dilations++ )
+            for (int dilations = min_dilations; dilations <= max_dilations; dilations++)
             {
-                if (found)
-                    break;      // already found it
-
                 // convert the input grayscale image to binary (black-n-white)
                 if (useAdaptive)
                 {
                     int block_size = cvRound(prev_sqr_size == 0
-                                             ? MIN(img.cols, img.rows) * (k % 2 == 0 ? 0.2 : 0.1)
+                                             ? std::min(img.cols, img.rows) * (k % 2 == 0 ? 0.2 : 0.1)
                                              : prev_sqr_size * 2);
                     block_size = block_size | 1;
                     // convert to binary
@@ -559,75 +620,74 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
                 // 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()...
                 rectangle( thresh_img, Point(0,0), Point(thresh_img.cols-1, thresh_img.rows-1), Scalar(255,255,255), 3, LINE_8);
-                int max_quad_buf_size = 0;
-                cvFree(&quads);
-                cvFree(&corners);
-                int quad_count = icvGenerateQuads( &quads, &corners, storage, thresh_img, flags, &max_quad_buf_size);
-                PRINTF("Quad count: %d/%d\n", quad_count, (pattern_size.width/2+1)*(pattern_size.height/2+1));
-                SHOW_QUADS("Old quads", thresh_img, quads, quad_count);
-                if (processQuads(quads, quad_count, pattern_size, max_quad_buf_size, storage, corners, out_corners, out_corner_count, prev_sqr_size))
+
+                detector.reset();
+
+#ifdef USE_CV_FINDCONTOURS
+                Mat binarized_img = thresh_img;
+#else
+                Mat binarized_img = (useAdaptive) ? thresh_img : thresh_img.clone(); // make clone because cvFindContours modifies the source image
+#endif
+                detector.generateQuads(binarized_img, flags);
+                DPRINTF("Quad count: %d/%d", detector.all_quads_count, (pattern_size.width/2+1)*(pattern_size.height/2+1));
+                SHOW_QUADS("Old quads", thresh_img, &detector.all_quads[0], detector.all_quads_count);
+                if (detector.processQuads(out_corners, prev_sqr_size))
+                {
                     found = 1;
+                    break;
+                }
             }
         }
     }
 
-    PRINTF("Chessboard detection result 1: %d\n", found);
+    DPRINTF("Chessboard detection result 1: %d", (int)found);
 
-    if( found )
-        found = icvCheckBoardMonotony( out_corners, pattern_size );
+    if (found)
+        found = detector.checkBoardMonotony(out_corners);
 
-    PRINTF("Chessboard detection result 2: %d\n", found);
+    DPRINTF("Chessboard detection result 2: %d", (int)found);
 
     // check that none of the found corners is too close to the image boundary
-    if( found )
+    if (found)
     {
         const int BORDER = 8;
-        for( k = 0; k < pattern_size.width*pattern_size.height; k++ )
+        for (int k = 0; k < pattern_size.width*pattern_size.height; ++k)
         {
             if( out_corners[k].x <= BORDER || out_corners[k].x > img.cols - BORDER ||
                 out_corners[k].y <= BORDER || out_corners[k].y > img.rows - BORDER )
+            {
+                found = false;
                 break;
+            }
         }
-
-        found = k == pattern_size.width*pattern_size.height;
     }
 
-    PRINTF("Chessboard detection result 3: %d\n", found);
+    DPRINTF("Chessboard detection result 3: %d", (int)found);
 
-    if( found )
+    if (found)
     {
-        if ( pattern_size.height % 2 == 0 && pattern_size.width % 2 == 0 )
+        if ((pattern_size.height & 1) == 0 && (pattern_size.width & 1) == 0 )
         {
             int last_row = (pattern_size.height-1)*pattern_size.width;
             double dy0 = out_corners[last_row].y - out_corners[0].y;
-            if( dy0 < 0 )
+            if (dy0 < 0)
             {
                 int n = pattern_size.width*pattern_size.height;
                 for(int i = 0; i < n/2; i++ )
                 {
-                    CvPoint2D32f temp;
-                    CV_SWAP(out_corners[i], out_corners[n-i-1], temp);
+                    std::swap(out_corners[i], out_corners[n-i-1]);
                 }
             }
         }
-        int wsize = 2;
-        CvMat old_img(img);
-        cvFindCornerSubPix( &old_img, out_corners, pattern_size.width*pattern_size.height,
-                            cvSize(wsize, wsize), cvSize(-1,-1),
-                            cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 15, 0.1));
+        cv::cornerSubPix(img, out_corners, Size(2, 2), Size(-1,-1),
+                         cv::TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 15, 0.1));
     }
-    }
-    CV_CATCH_ALL
-    {
-        cvFree(&quads);
-        cvFree(&corners);
-        CV_RETHROW();
-    }
-    cvFree(&quads);
-    cvFree(&corners);
+
+    Mat(out_corners).copyTo(corners_);
     return found;
 }
 
+
 //
 // Checks that each board row and column is pretty much monotonous curve:
 // It analyzes each row and each column of the chessboard as following:
@@ -638,35 +698,33 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
 // This function has been created as temporary workaround for the bug in current implementation
 // of cvFindChessboardCornes that produces absolutely unordered sets of corners.
 //
-
-static int
-icvCheckBoardMonotony( CvPoint2D32f* corners, CvSize pattern_size )
+bool ChessBoardDetector::checkBoardMonotony(const std::vector<cv::Point2f>& corners)
 {
-    int i, j, k;
-
-    for( k = 0; k < 2; k++ )
+    for (int k = 0; k < 2; ++k)
     {
-        for( i = 0; i < (k == 0 ? pattern_size.height : pattern_size.width); i++ )
+        int max_i = (k == 0 ? pattern_size.height : pattern_size.width);
+        int max_j = (k == 0 ? pattern_size.width: pattern_size.height) - 1;
+        for (int i = 0; i < max_i; ++i)
         {
-            CvPoint2D32f a = k == 0 ? corners[i*pattern_size.width] : corners[i];
-            CvPoint2D32f b = k == 0 ? corners[(i+1)*pattern_size.width-1] :
-                corners[(pattern_size.height-1)*pattern_size.width + i];
-            float prevt = 0, dx0 = b.x - a.x, dy0 = b.y - a.y;
-            if( fabs(dx0) + fabs(dy0) < FLT_EPSILON )
-                return 0;
-            for( j = 1; j < (k == 0 ? pattern_size.width : pattern_size.height) - 1; j++ )
+            cv::Point2f a = k == 0 ? corners[i*pattern_size.width] : corners[i];
+            cv::Point2f b = k == 0 ? corners[(i+1)*pattern_size.width-1]
+                                   : corners[(pattern_size.height-1)*pattern_size.width + i];
+            float dx0 = b.x - a.x, dy0 = b.y - a.y;
+            if (fabs(dx0) + fabs(dy0) < FLT_EPSILON)
+                return false;
+            float prevt = 0;
+            for (int j = 1; j < max_j; ++j)
             {
-                CvPoint2D32f c = k == 0 ? corners[i*pattern_size.width + j] :
-                    corners[j*pattern_size.width + i];
+                cv::Point2f c = k == 0 ? corners[i*pattern_size.width + j]
+                                       : corners[j*pattern_size.width + i];
                 float t = ((c.x - a.x)*dx0 + (c.y - a.y)*dy0)/(dx0*dx0 + dy0*dy0);
-                if( t < prevt || t > 1 )
-                    return 0;
+                if (t < prevt || t > 1)
+                    return false;
                 prevt = t;
             }
         }
     }
-
-    return 1;
+    return true;
 }
 
 //
@@ -680,18 +738,16 @@ icvCheckBoardMonotony( CvPoint2D32f* corners, CvSize pattern_size )
 // can change the number of quads in the group
 // can add quads, so we need to have quad/corner arrays passed in
 //
-
-static int
-icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads,
-        int *all_count, CvCBQuad **all_quads, CvCBCorner **corners,
-        CvSize pattern_size, int max_quad_buf_size, CvMemStorage* storage )
+int ChessBoardDetector::orderFoundConnectedQuads(std::vector<ChessBoardQuad*>& quads)
 {
-    cv::Ptr<CvMemStorage> temp_storage(cvCreateChildMemStorage( storage ));
-    CvSeq* stack = cvCreateSeq( 0, sizeof(*stack), sizeof(void*), temp_storage );
+    const int max_quad_buf_size = (int)all_quads.size();
+    int quad_count = (int)quads.size();
+
+    std::stack<ChessBoardQuad*> stack;
 
     // first find an interior quad
-    CvCBQuad *start = NULL;
-    for (int i=0; i<quad_count; i++)
+    ChessBoardQuad *start = NULL;
+    for (int i = 0; i < quad_count; i++)
     {
         if (quads[i]->count == 4)
         {
@@ -709,7 +765,7 @@ icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads,
     std::map<int, int> col_hist;
     std::map<int, int> row_hist;
 
-    cvSeqPush(stack, &start);
+    stack.push(start);
     start->row = 0;
     start->col = 0;
     start->ordered = true;
@@ -717,10 +773,10 @@ icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads,
     // Recursively order the quads so that all position numbers (e.g.,
     // 0,1,2,3) are in the at the same relative corner (e.g., lower right).
 
-    while( stack->total )
+    while (!stack.empty())
     {
-        CvCBQuad* q;
-        cvSeqPop( stack, &q );
+        ChessBoardQuad* q = stack.top(); stack.pop(); CV_Assert(q);
+
         int col = q->col;
         int row = q->row;
         col_hist[col]++;
@@ -732,9 +788,9 @@ icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads,
         if (col > col_max) col_max = col;
         if (col < col_min) col_min = col;
 
-        for(int i = 0; i < 4; i++ )
+        for (int i = 0; i < 4; i++)
         {
-            CvCBQuad *neighbor = q->neighbors[i];
+            ChessBoardQuad *neighbor = q->neighbors[i];
             switch(i)   // adjust col, row for this quad
             {           // start at top left, go clockwise
             case 0:
@@ -750,18 +806,21 @@ icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads,
             // just do inside quads
             if (neighbor && neighbor->ordered == false && neighbor->count == 4)
             {
-                PRINTF("col: %d  row: %d\n", col, row);
-                icvOrderQuad(neighbor, q->corners[i], (i+2)%4); // set in order
+                DPRINTF("col: %d  row: %d", col, row);
+                CV_Assert(q->corners[i]);
+                orderQuad(*neighbor, *(q->corners[i]), (i+2)&3); // set in order
                 neighbor->ordered = true;
                 neighbor->row = row;
                 neighbor->col = col;
-                cvSeqPush( stack, &neighbor );
+                stack.push(neighbor);
             }
         }
     }
 
-    for (int i=col_min; i<=col_max; i++)
-        PRINTF("HIST[%d] = %d\n", i, col_hist[i]);
+#ifdef DEBUG_CHESSBOARD
+    for (int i = col_min; i <= col_max; i++)
+        DPRINTF("HIST[%d] = %d", i, col_hist[i]);
+#endif
 
     // analyze inner quad structure
     int w = pattern_size.width - 1;
@@ -777,62 +836,67 @@ icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads,
         w = pattern_size.height - 1;
     }
 
-    PRINTF("Size: %dx%d  Pattern: %dx%d\n", dcol, drow, w, h);
+    DPRINTF("Size: %dx%d  Pattern: %dx%d", dcol, drow, w, h);
 
     // check if there are enough inner quads
     if (dcol < w || drow < h)   // found enough inner quads?
     {
-        PRINTF("Too few inner quad rows/cols\n");
+        DPRINTF("Too few inner quad rows/cols");
         return 0;   // no, return
     }
 #ifdef ENABLE_TRIM_COL_ROW
     // too many columns, not very common
     if (dcol == w+1)    // too many, trim
     {
-        PRINTF("Trimming cols\n");
+        DPRINTF("Trimming cols");
         if (col_hist[col_max] > col_hist[col_min])
         {
-            PRINTF("Trimming left col\n");
-            quad_count = icvTrimCol(quads,quad_count,col_min,-1);
+            DPRINTF("Trimming left col");
+            trimCol(quads, col_min, -1);
         }
         else
         {
-            PRINTF("Trimming right col\n");
-            quad_count = icvTrimCol(quads,quad_count,col_max,+1);
+            DPRINTF("Trimming right col");
+            trimCol(quads, col_max, +1);
         }
     }
 
     // too many rows, not very common
     if (drow == h+1)    // too many, trim
     {
-        PRINTF("Trimming rows\n");
+        DPRINTF("Trimming rows");
         if (row_hist[row_max] > row_hist[row_min])
         {
-            PRINTF("Trimming top row\n");
-            quad_count = icvTrimRow(quads,quad_count,row_min,-1);
+            DPRINTF("Trimming top row");
+            trimRow(quads, row_min, -1);
         }
         else
         {
-            PRINTF("Trimming bottom row\n");
-            quad_count = icvTrimRow(quads,quad_count,row_max,+1);
+            DPRINTF("Trimming bottom row");
+            trimRow(quads, row_max, +1);
         }
     }
+
+    quad_count = (int)quads.size(); // update after icvTrimCol/icvTrimRow
 #endif
 
     // check edges of inner quads
     // if there is an outer quad missing, fill it in
     // first order all inner quads
     int found = 0;
-    for (int i=0; i<quad_count; i++)
+    for (int i=0; i < quad_count; ++i)
     {
-        if (quads[i]->count == 4)
+        ChessBoardQuad& q = *quads[i];
+        if (q.count != 4)
+            continue;
+
         {   // ok, look at neighbors
-            int col = quads[i]->col;
-            int row = quads[i]->row;
-            for (int j=0; j<4; j++)
+            int col = q.col;
+            int row = q.row;
+            for (int j = 0; j < 4; j++)
             {
                 switch(j)   // adjust col, row for this quad
-                {       // start at top left, go clockwise
+                {           // start at top left, go clockwise
                 case 0:
                     row--; col--; break;
                 case 1:
@@ -842,15 +906,16 @@ icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads,
                 case 3:
                     col -= 2; break;
                 }
-                CvCBQuad *neighbor = quads[i]->neighbors[j];
+                ChessBoardQuad *neighbor = q.neighbors[j];
                 if (neighbor && !neighbor->ordered && // is it an inner quad?
                     col <= col_max && col >= col_min &&
                     row <= row_max && row >= row_min)
                 {
                     // if so, set in order
-                    PRINTF("Adding inner: col: %d  row: %d\n", col, row);
+                    DPRINTF("Adding inner: col: %d  row: %d", col, row);
                     found++;
-                    icvOrderQuad(neighbor, quads[i]->corners[j], (j+2)%4);
+                    CV_Assert(q.corners[j]);
+                    orderQuad(*neighbor, *q.corners[j], (j+2)&3);
                     neighbor->ordered = true;
                     neighbor->row = row;
                     neighbor->col = col;
@@ -863,18 +928,18 @@ icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads,
     //   which are missing
     if (found > 0)
     {
-        PRINTF("Found %d inner quads not connected to outer quads, repairing\n", found);
-        for (int i=0; i<quad_count && *all_count < max_quad_buf_size; i++)
+        DPRINTF("Found %d inner quads not connected to outer quads, repairing", found);
+        for (int i = 0; i < quad_count && all_quads_count < max_quad_buf_size; i++)
         {
-            if (quads[i]->count < 4 && quads[i]->ordered)
+            ChessBoardQuad& q = *quads[i];
+            if (q.count < 4 && q.ordered)
             {
-                int added = icvAddOuterQuad(quads[i],quads,quad_count,all_quads,*all_count,corners, max_quad_buf_size);
-                *all_count += added;
+                int added = addOuterQuad(q, quads);
                 quad_count += added;
             }
         }
 
-        if (*all_count >= max_quad_buf_size)
+        if (all_quads_count >= max_quad_buf_size)
             return 0;
     }
 
@@ -882,29 +947,27 @@ icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads,
     // final trimming of outer quads
     if (dcol == w && drow == h) // found correct inner quads
     {
-        PRINTF("Inner bounds ok, check outer quads\n");
-        int rcount = quad_count;
-        for (int i=quad_count-1; i>=0; i--) // eliminate any quad not connected to
-            // an ordered quad
+        DPRINTF("Inner bounds ok, check outer quads");
+        for (int i = quad_count - 1; i >= 0; i--) // eliminate any quad not connected to an ordered quad
         {
-            if (quads[i]->ordered == false)
+            ChessBoardQuad& q = *quads[i];
+            if (q.ordered == false)
             {
                 bool outer = false;
                 for (int j=0; j<4; j++) // any neighbors that are ordered?
                 {
-                    if (quads[i]->neighbors[j] && quads[i]->neighbors[j]->ordered)
+                    if (q.neighbors[j] && q.neighbors[j]->ordered)
                         outer = true;
                 }
                 if (!outer) // not an outer quad, eliminate
                 {
-                    PRINTF("Removing quad %d\n", i);
-                    icvRemoveQuadFromGroup(quads,rcount,quads[i]);
-                    rcount--;
+                    DPRINTF("Removing quad %d", i);
+                    removeQuadFromGroup(quads, q);
                 }
             }
 
         }
-        return rcount;
+        return (int)quads.size();
     }
 
     return 0;
@@ -915,69 +978,63 @@ icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads,
 // looks for the neighbor of <quad> that isn't present,
 //   tries to add it in.
 // <quad> is ordered
-
-static int
-icvAddOuterQuad( CvCBQuad *quad, CvCBQuad **quads, int quad_count,
-        CvCBQuad **all_quads, int all_count, CvCBCorner **corners, int max_quad_buf_size )
-
+int ChessBoardDetector::addOuterQuad(ChessBoardQuad& quad, std::vector<ChessBoardQuad*>& quads)
 {
     int added = 0;
-    for (int i=0; i<4 && all_count < max_quad_buf_size; i++) // find no-neighbor corners
+    int max_quad_buf_size = (int)all_quads.size();
+
+    for (int i = 0; i < 4 && all_quads_count < max_quad_buf_size; i++) // find no-neighbor corners
     {
-        if (!quad->neighbors[i])    // ok, create and add neighbor
+        if (!quad.neighbors[i])    // ok, create and add neighbor
         {
-            int j = (i+2)%4;
-            PRINTF("Adding quad as neighbor 2\n");
-            CvCBQuad *q = &(*all_quads)[all_count];
-            memset( q, 0, sizeof(*q) );
+            int j = (i+2)&3;
+            DPRINTF("Adding quad as neighbor 2");
+            int q_index = all_quads_count++;
+            ChessBoardQuad& q = all_quads[q_index];
+            q = ChessBoardQuad(0);
             added++;
-            quads[quad_count] = q;
-            quad_count++;
+            quads.push_back(&q);
 
             // set neighbor and group id
-            quad->neighbors[i] = q;
-            quad->count += 1;
-            q->neighbors[j] = quad;
-            q->group_idx = quad->group_idx;
-            q->count = 1;   // number of neighbors
-            q->ordered = false;
-            q->edge_len = quad->edge_len;
+            quad.neighbors[i] = &q;
+            quad.count += 1;
+            q.neighbors[j] = &quad;
+            q.group_idx = quad.group_idx;
+            q.count = 1;   // number of neighbors
+            q.ordered = false;
+            q.edge_len = quad.edge_len;
 
             // make corners of new quad
             // same as neighbor quad, but offset
-            CvPoint2D32f pt = quad->corners[i]->pt;
-            CvCBCorner* corner;
-            float dx = pt.x - quad->corners[j]->pt.x;
-            float dy = pt.y - quad->corners[j]->pt.y;
-            for (int k=0; k<4; k++)
+            const cv::Point2f pt_offset = quad.corners[i]->pt - quad.corners[j]->pt;
+            for (int k = 0; k < 4; k++)
             {
-                corner = &(*corners)[all_count*4+k];
-                pt = quad->corners[k]->pt;
-                memset( corner, 0, sizeof(*corner) );
-                corner->pt = pt;
-                q->corners[k] = corner;
-                corner->pt.x += dx;
-                corner->pt.y += dy;
+                ChessBoardCorner& corner = (ChessBoardCorner&)all_corners[q_index * 4 + k];
+                const cv::Point2f& pt = quad.corners[k]->pt;
+                corner = ChessBoardCorner(pt);
+                q.corners[k] = &corner;
+                corner.pt += pt_offset;
             }
             // have to set exact corner
-            q->corners[j] = quad->corners[i];
+            q.corners[j] = quad.corners[i];
 
             // now find other neighbor and add it, if possible
-            if (quad->neighbors[(i+3)%4] &&
-                quad->neighbors[(i+3)%4]->ordered &&
-                quad->neighbors[(i+3)%4]->neighbors[i] &&
-                quad->neighbors[(i+3)%4]->neighbors[i]->ordered )
+            int next_i = (i + 1) & 3;
+            int prev_i = (i + 3) & 3; // equal to (j + 1) & 3
+            ChessBoardQuad* quad_prev = quad.neighbors[prev_i];
+            if (quad_prev &&
+                quad_prev->ordered &&
+                quad_prev->neighbors[i] &&
+                quad_prev->neighbors[i]->ordered )
             {
-                CvCBQuad *qn = quad->neighbors[(i+3)%4]->neighbors[i];
-                q->count = 2;
-                q->neighbors[(j+1)%4] = qn;
-                qn->neighbors[(i+1)%4] = q;
+                ChessBoardQuad* qn = quad_prev->neighbors[i];
+                q.count = 2;
+                q.neighbors[prev_i] = qn;
+                qn->neighbors[next_i] = &q;
                 qn->count += 1;
                 // have to set exact corner
-                q->corners[(j+1)%4] = qn->corners[(i+1)%4];
+                q.corners[prev_i] = qn->corners[next_i];
             }
-
-            all_count++;
         }
     }
     return added;
@@ -986,151 +1043,141 @@ icvAddOuterQuad( CvCBQuad *quad, CvCBQuad **quads, int quad_count,
 
 // trimming routines
 #ifdef ENABLE_TRIM_COL_ROW
-static int
-icvTrimCol(CvCBQuad **quads, int count, int col, int dir)
+void ChessBoardDetector::trimCol(std::vector<ChessBoardQuad*>& quads, int col, int dir)
 {
-    int rcount = count;
+    std::vector<ChessBoardQuad*> quads_(quads);
     // find the right quad(s)
-    for (int i=0; i<count; i++)
+    for (size_t i = 0; i < quads_.size(); ++i)
     {
+        ChessBoardQuad& q = *quads_[i];
 #ifdef DEBUG_CHESSBOARD
-        if (quads[i]->ordered)
-            PRINTF("index: %d  cur: %d\n", col, quads[i]->col);
+        if (q.ordered)
+            DPRINTF("i: %d  index: %d  cur: %d", (int)i, col, q.col);
 #endif
-        if (quads[i]->ordered && quads[i]->col == col)
+        if (q.ordered && q.col == col)
         {
             if (dir == 1)
             {
-                if (quads[i]->neighbors[1])
+                if (q.neighbors[1])
                 {
-                    icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[1]);
-                    rcount--;
+                    removeQuadFromGroup(quads, *q.neighbors[1]);
                 }
-                if (quads[i]->neighbors[2])
+                if (q.neighbors[2])
                 {
-                    icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[2]);
-                    rcount--;
+                    removeQuadFromGroup(quads, *q.neighbors[2]);
                 }
             }
             else
             {
-                if (quads[i]->neighbors[0])
+                if (q.neighbors[0])
                 {
-                    icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[0]);
-                    rcount--;
+                    removeQuadFromGroup(quads, *q.neighbors[0]);
                 }
-                if (quads[i]->neighbors[3])
+                if (q.neighbors[3])
                 {
-                    icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[3]);
-                    rcount--;
+                    removeQuadFromGroup(quads, *q.neighbors[3]);
                 }
             }
-
         }
     }
-    return rcount;
 }
 
-static int
-icvTrimRow(CvCBQuad **quads, int count, int row, int dir)
+void ChessBoardDetector::trimRow(std::vector<ChessBoardQuad*>& quads, int row, int dir)
 {
-    int i, rcount = count;
+    std::vector<ChessBoardQuad*> quads_(quads);
     // find the right quad(s)
-    for (i=0; i<count; i++)
+    for (size_t i = 0; i < quads_.size(); ++i)
     {
+        ChessBoardQuad& q = *quads_[i];
 #ifdef DEBUG_CHESSBOARD
-        if (quads[i]->ordered)
-            PRINTF("index: %d  cur: %d\n", row, quads[i]->row);
+        if (q.ordered)
+            DPRINTF("i: %d  index: %d  cur: %d", (int)i, row, q.row);
 #endif
-        if (quads[i]->ordered && quads[i]->row == row)
+        if (q.ordered && q.row == row)
         {
             if (dir == 1)   // remove from bottom
             {
-                if (quads[i]->neighbors[2])
+                if (q.neighbors[2])
                 {
-                    icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[2]);
-                    rcount--;
+                    removeQuadFromGroup(quads, *q.neighbors[2]);
                 }
-                if (quads[i]->neighbors[3])
+                if (q.neighbors[3])
                 {
-                    icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[3]);
-                    rcount--;
+                    removeQuadFromGroup(quads, *q.neighbors[3]);
                 }
             }
             else    // remove from top
             {
-                if (quads[i]->neighbors[0])
+                if (q.neighbors[0])
                 {
-                    icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[0]);
-                    rcount--;
+                    removeQuadFromGroup(quads, *q.neighbors[0]);
                 }
-                if (quads[i]->neighbors[1])
+                if (q.neighbors[1])
                 {
-                    icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[1]);
-                    rcount--;
+                    removeQuadFromGroup(quads, *q.neighbors[1]);
                 }
             }
 
         }
     }
-    return rcount;
 }
 #endif
 
 //
 // remove quad from quad group
 //
-
-static void
-icvRemoveQuadFromGroup(CvCBQuad **quads, int count, CvCBQuad *q0)
+void ChessBoardDetector::removeQuadFromGroup(std::vector<ChessBoardQuad*>& quads, ChessBoardQuad& q0)
 {
-    int i, j;
+    const int count = (int)quads.size();
+
+    int self_idx = -1;
+
     // remove any references to this quad as a neighbor
-    for(i = 0; i < count; i++ )
+    for (int i = 0; i < count; ++i)
     {
-        CvCBQuad *q = quads[i];
-        for(j = 0; j < 4; j++ )
+        ChessBoardQuad* q = quads[i];
+        if (q == &q0)
+            self_idx = i;
+        for (int j = 0; j < 4; j++)
         {
-            if( q->neighbors[j] == q0 )
+            if (q->neighbors[j] == &q0)
             {
-                q->neighbors[j] = 0;
+                q->neighbors[j] = NULL;
                 q->count--;
-                for(int k = 0; k < 4; k++ )
-                    if( q0->neighbors[k] == q )
+                for (int k = 0; k < 4; ++k)
+                {
+                    if (q0.neighbors[k] == q)
                     {
-                        q0->neighbors[k] = 0;
-                        q0->count--;
+                        q0.neighbors[k] = 0;
+                        q0.count--;
+#ifndef _DEBUG
                         break;
+#endif
                     }
+                }
                 break;
             }
         }
     }
+    CV_Assert(self_idx >= 0); // item itself should be found
 
     // remove the quad
-    for(i = 0; i < count; i++ )
-    {
-        CvCBQuad *q = quads[i];
-        if (q == q0)
-        {
-            quads[i] = quads[count-1];
-            break;
-        }
-    }
+    if (self_idx != count-1)
+        quads[self_idx] = quads[count-1];
+    quads.resize(count - 1);
 }
 
 //
 // put quad into correct order, where <corner> has value <common>
 //
-
-static void
-icvOrderQuad(CvCBQuad *quad, CvCBCorner *corner, int common)
+void ChessBoardDetector::orderQuad(ChessBoardQuad& quad, ChessBoardCorner& corner, int common)
 {
+    CV_DbgAssert(common >= 0 && common <= 3);
+
     // find the corner
-    int tc;
-    for (tc=0; tc<4; tc++)
-        if (quad->corners[tc]->pt.x == corner->pt.x &&
-            quad->corners[tc]->pt.y == corner->pt.y)
+    int tc = 0;;
+    for (; tc < 4; ++tc)
+        if (quad.corners[tc]->pt == corner.pt)
             break;
 
     // set corner order
@@ -1138,62 +1185,52 @@ icvOrderQuad(CvCBQuad *quad, CvCBCorner *corner, int common)
     while (tc != common)
     {
         // shift by one
-        CvCBCorner *tempc;
-        CvCBQuad *tempq;
-        tempc = quad->corners[3];
-        tempq = quad->neighbors[3];
-        for (int i=3; i>0; i--)
+        ChessBoardCorner *tempc = quad.corners[3];
+        ChessBoardQuad *tempq = quad.neighbors[3];
+        for (int i = 3; i > 0; --i)
         {
-            quad->corners[i] = quad->corners[i-1];
-            quad->neighbors[i] = quad->neighbors[i-1];
+            quad.corners[i] = quad.corners[i-1];
+            quad.neighbors[i] = quad.neighbors[i-1];
         }
-        quad->corners[0] = tempc;
-        quad->neighbors[0] = tempq;
-        tc++;
-        tc = tc%4;
+        quad.corners[0] = tempc;
+        quad.neighbors[0] = tempq;
+        tc = (tc + 1) & 3;
     }
 }
 
 
 // if we found too many connect quads, remove those which probably do not belong.
-static int
-icvCleanFoundConnectedQuads( int quad_count, CvCBQuad **quad_group, CvSize pattern_size )
+int ChessBoardDetector::cleanFoundConnectedQuads(std::vector<ChessBoardQuad*>& quad_group)
 {
-    CvPoint2D32f center;
-    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...
-    if( quad_count <= count )
+    int quad_count = (int)quad_group.size();
+    if (quad_count <= count)
         return quad_count;
+    CV_DbgAssert(quad_count > 0);
 
     // create an array of quadrangle centers
-    cv::AutoBuffer<CvPoint2D32f> centers( quad_count );
-    cv::Ptr<CvMemStorage> temp_storage(cvCreateMemStorage(0));
+    cv::AutoBuffer<cv::Point2f> centers(quad_count);
 
-    for( i = 0; i < quad_count; i++ )
+    cv::Point2f center;
+    for (int i = 0; i < quad_count; ++i)
     {
-        CvPoint2D32f ci;
-        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;
-        }
+        ChessBoardQuad* q = quad_group[i];
 
-        ci.x *= 0.25f;
-        ci.y *= 0.25f;
+        const cv::Point2f ci = (
+                q->corners[0]->pt +
+                q->corners[1]->pt +
+                q->corners[2]->pt +
+                q->corners[3]->pt
+            ) * 0.25f;
 
         centers[i] = ci;
-        center.x += ci.x;
-        center.y += ci.y;
+        center += ci;
     }
-    center.x /= quad_count;
-    center.y /= quad_count;
+    center.x *= (1.0f / quad_count);
 
     // If we still have more quadrangles than we should,
     // we try to eliminate bad ones based on minimizing the bounding box.
@@ -1202,50 +1239,52 @@ icvCleanFoundConnectedQuads( int quad_count, CvCBQuad **quad_group, CvSize patte
     // (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-- )
+    for (; quad_count > count; quad_count--)
     {
         double min_box_area = DBL_MAX;
-        int skip, min_box_area_index = -1;
+        int min_box_area_index = -1;
 
         // For each point, calculate box area without that point
-        for( skip = 0; skip < quad_count; skip++ )
+        for (int skip = 0; skip < quad_count; ++skip)
         {
             // get bounding rectangle
-            CvPoint2D32f temp = centers[skip]; // temporarily make index 'skip' the same as
+            cv::Point2f temp = centers[skip]; // temporarily make index 'skip' the same as
             centers[skip] = center;            // pattern center (so it is not counted for convex hull)
-            CvMat pointMat = cvMat(1, quad_count, CV_32FC2, centers);
-            CvSeq *hull = cvConvexHull2( &pointMat, temp_storage, CV_CLOCKWISE, 1 );
+            std::vector<Point2f> hull;
+            Mat points(1, quad_count, CV_32FC2, &centers[0]);
+            cv::convexHull(points, hull, true);
             centers[skip] = temp;
-            double hull_area = fabs(cvContourArea(hull, CV_WHOLE_SEQ));
+            double hull_area = contourArea(hull, true);
 
             // remember smallest box area
-            if( hull_area < min_box_area )
+            if (hull_area < min_box_area)
             {
                 min_box_area = hull_area;
                 min_box_area_index = skip;
             }
-            cvClearMemStorage( temp_storage );
         }
 
-        CvCBQuad *q0 = quad_group[min_box_area_index];
+        ChessBoardQuad *q0 = quad_group[min_box_area_index];
 
         // remove any references to this quad as a neighbor
-        for( i = 0; i < quad_count; i++ )
+        for (int i = 0; i < quad_count; ++i)
         {
-            CvCBQuad *q = quad_group[i];
-            for( j = 0; j < 4; j++ )
+            ChessBoardQuad *q = quad_group[i];
+            for (int j = 0; j < 4; ++j)
             {
-                if( q->neighbors[j] == q0 )
+                if (q->neighbors[j] == q0)
                 {
                     q->neighbors[j] = 0;
                     q->count--;
-                    for( k = 0; k < 4; k++ )
-                        if( q0->neighbors[k] == q )
+                    for (int k = 0; k < 4; ++k)
+                    {
+                        if (q0->neighbors[k] == q)
                         {
                             q0->neighbors[k] = 0;
                             q0->count--;
                             break;
                         }
+                    }
                     break;
                 }
             }
@@ -1260,111 +1299,108 @@ icvCleanFoundConnectedQuads( int quad_count, CvCBQuad **quad_group, CvSize patte
     return quad_count;
 }
 
-//=====================================================================================
 
-static int
-icvFindConnectedQuads( CvCBQuad *quad, int quad_count, CvCBQuad **out_group,
-                       int group_idx, CvMemStorage* storage )
+
+void ChessBoardDetector::findConnectedQuads(std::vector<ChessBoardQuad*>& out_group, int group_idx)
 {
-    cv::Ptr<CvMemStorage> temp_storage(cvCreateChildMemStorage( storage ));
-    CvSeq* stack = cvCreateSeq( 0, sizeof(*stack), sizeof(void*), temp_storage );
-    int i, count = 0;
+    out_group.clear();
 
-    // 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;
-    }
+    std::stack<ChessBoardQuad*> stack;
 
-    // Recursively find a group of connected quads starting from the seed quad[i]
-    if( i < quad_count )
+    int i = 0;
+    for (; i < all_quads_count; i++)
     {
-        CvCBQuad* q = &quad[i];
-        cvSeqPush( stack, &q );
-        out_group[count++] = q;
+        ChessBoardQuad* q = (ChessBoardQuad*)&all_quads[i];
+
+        // Scan the array for a first unlabeled quad
+        if (q->count <= 0 || q->group_idx >= 0) continue;
+
+        // Recursively find a group of connected quads starting from the seed all_quads[i]
+        stack.push(q);
+        out_group.push_back(q);
         q->group_idx = group_idx;
         q->ordered = false;
 
-        while( stack->total )
+        while (!stack.empty())
         {
-            cvSeqPop( stack, &q );
-            for( i = 0; i < 4; i++ )
+            q = stack.top(); CV_Assert(q);
+            stack.pop();
+            for (int k = 0; k < 4; k++ )
             {
-                CvCBQuad *neighbor = q->neighbors[i];
-                ifneighbor && neighbor->count > 0 && neighbor->group_idx < 0 )
+                ChessBoardQuad *neighbor = q->neighbors[k];
+                if (neighbor && neighbor->count > 0 && neighbor->group_idx < 0 )
                 {
-                    cvSeqPush( stack, &neighbor );
-                    out_group[count++] = neighbor;
+                    stack.push(neighbor);
+                    out_group.push_back(neighbor);
                     neighbor->group_idx = group_idx;
                     neighbor->ordered = false;
                 }
             }
         }
+        break;
     }
-
-    return count;
 }
 
 
-//=====================================================================================
-
-static int
-icvCheckQuadGroup( CvCBQuad **quad_group, int quad_count,
-                   CvCBCorner **out_corners, CvSize pattern_size )
+int ChessBoardDetector::checkQuadGroup(std::vector<ChessBoardQuad*>& quad_group, std::vector<ChessBoardCorner*>& out_corners)
 {
     const int ROW1 = 1000000;
     const int ROW2 = 2000000;
     const int ROW_ = 3000000;
+
+    int quad_count = (int)quad_group.size();
+
+    std::vector<ChessBoardCorner*> corners(quad_count*4);
+    int corner_count = 0;
     int result = 0;
-    int i, out_corner_count = 0, corner_count = 0;
-    std::vector<CvCBCorner*> corners(quad_count*4);
 
-    int j, k, kk;
     int width = 0, height = 0;
     int hist[5] = {0,0,0,0,0};
-    CvCBCorner* first = 0, *first2 = 0, *right, *cur, *below, *c;
+    //ChessBoardCorner* first = 0, *first2 = 0, *right, *cur, *below, *c;
 
     // build dual graph, which vertices are internal quad corners
     // and two vertices are connected iff they lie on the same quad edge
-    for( i = 0; i < quad_count; i++ )
+    for (int i = 0; i < quad_count; ++i)
     {
-        CvCBQuad* q = quad_group[i];
+        ChessBoardQuad* q = quad_group[i];
         /*CvScalar color = q->count == 0 ? cvScalar(0,255,255) :
                          q->count == 1 ? cvScalar(0,0,255) :
                          q->count == 2 ? cvScalar(0,255,0) :
                          q->count == 3 ? cvScalar(255,255,0) :
                                          cvScalar(255,0,0);*/
 
-        for( j = 0; j < 4; j++ )
+        for (int j = 0; j < 4; ++j)
         {
             //cvLine( debug_img, cvPointFrom32f(q->corners[j]->pt), cvPointFrom32f(q->corners[(j+1)&3]->pt), color, 1, CV_AA, 0 );
-            if( q->neighbors[j] )
+            if (q->neighbors[j])
             {
-                CvCBCorner *a = q->corners[j], *b = q->corners[(j+1)&3];
+                int next_j = (j + 1) & 3;
+                ChessBoardCorner *a = q->corners[j], *b = q->corners[next_j];
                 // mark internal corners that belong to:
                 //   - a quad with a single neighbor - with ROW1,
                 //   - a quad with two neighbors     - with ROW2
                 // make the rest of internal corners with ROW_
                 int row_flag = q->count == 1 ? ROW1 : q->count == 2 ? ROW2 : ROW_;
 
-                if( a->row == 0 )
+                if (a->row == 0)
                 {
                     corners[corner_count++] = a;
                     a->row = row_flag;
                 }
-                else if( a->row > row_flag )
+                else if (a->row > row_flag)
+                {
                     a->row = row_flag;
+                }
 
-                if( q->neighbors[(j+1)&3] )
+                if (q->neighbors[next_j])
                 {
-                    if( a->count >= 4 || b->count >= 4 )
+                    if (a->count >= 4 || b->count >= 4)
                         goto finalize;
-                    for( k = 0; k < 4; k++ )
+                    for (int k = 0; k < 4; ++k)
                     {
-                        if( a->neighbors[k] == b )
+                        if (a->neighbors[k] == b)
                             goto finalize;
-                        if( b->neighbors[k] == a )
+                        if (b->neighbors[k] == a)
                             goto finalize;
                     }
                     a->neighbors[a->count++] = b;
@@ -1374,19 +1410,21 @@ icvCheckQuadGroup( CvCBQuad **quad_group, int quad_count,
         }
     }
 
-    if( corner_count != pattern_size.width*pattern_size.height )
+    if (corner_count != pattern_size.width*pattern_size.height)
         goto finalize;
 
-    for( i = 0; i < corner_count; i++ )
+{
+    ChessBoardCorner* first = NULL, *first2 = NULL;
+    for (int i = 0; i < corner_count; ++i)
     {
         int n = corners[i]->count;
-        assert( 0 <= n && n <= 4 );
+        CV_DbgAssert(0 <= n && n <= 4);
         hist[n]++;
-        if( !first && n == 2 )
+        if (!first && n == 2)
         {
-            if( corners[i]->row == ROW1 )
+            if (corners[i]->row == ROW1)
                 first = corners[i];
-            else if( !first2 && corners[i]->row == ROW2 )
+            else if (!first2 && corners[i]->row == ROW2)
                 first2 = corners[i];
         }
     }
@@ -1400,18 +1438,19 @@ icvCheckQuadGroup( CvCBQuad **quad_group, int quad_count,
         hist[3] != (pattern_size.width + pattern_size.height)*2 - 8 )
         goto finalize;
 
-    cur = first;
-    right = below = 0;
-    out_corners[out_corner_count++] = cur;
+    ChessBoardCorner* cur = first;
+    ChessBoardCorner* right = NULL;
+    ChessBoardCorner* below = NULL;
+    out_corners.push_back(cur);
 
-    for( k = 0; k < 4; k++ )
+    for (int k = 0; k < 4; ++k)
     {
-        c = cur->neighbors[k];
-        if( c )
+        ChessBoardCorner* c = cur->neighbors[k];
+        if (c)
         {
-            if( !right )
+            if (!right)
                 right = c;
-            else if( !below )
+            else if (!below)
                 below = c;
         }
     }
@@ -1424,28 +1463,30 @@ icvCheckQuadGroup( CvCBQuad **quad_group, int quad_count,
     //cvCircle( debug_img, cvPointFrom32f(cur->pt), 3, cvScalar(0,255,0), -1, 8, 0 );
 
     first = below; // remember the first corner in the next row
+
     // find and store the first row (or column)
-    for(j=1;;j++)
+    for (int j = 1; ; ++j)
     {
         right->row = 0;
-        out_corners[out_corner_count++] = right;
+        out_corners.push_back(right);
         //cvCircle( debug_img, cvPointFrom32f(right->pt), 3, cvScalar(0,255-j*10,0), -1, 8, 0 );
         if( right->count == 2 )
             break;
-        if( right->count != 3 || out_corner_count >= MAX(pattern_size.width,pattern_size.height) )
+        if( right->count != 3 || (int)out_corners.size() >= std::max(pattern_size.width,pattern_size.height) )
             goto finalize;
         cur = right;
-        for( k = 0; k < 4; k++ )
+        for (int k = 0; k < 4; ++k)
         {
-            c = cur->neighbors[k];
-            if( c && c->row > 0 )
+            ChessBoardCorner* c = cur->neighbors[k];
+            if (c && c->row > 0)
             {
-                for( kk = 0; kk < 4; kk++ )
+                int kk = 0;
+                for (; kk < 4; ++kk)
                 {
-                    if( c->neighbors[kk] == below )
+                    if (c->neighbors[kk] == below)
                         break;
                 }
-                if( kk < 4 )
+                if (kk < 4)
                     below = c;
                 else
                     right = c;
@@ -1453,109 +1494,114 @@ icvCheckQuadGroup( CvCBQuad **quad_group, int quad_count,
         }
     }
 
-    width = out_corner_count;
-    if( width == pattern_size.width )
+    width = (int)out_corners.size();
+    if (width == pattern_size.width)
         height = pattern_size.height;
-    else if( width == pattern_size.height )
+    else if (width == pattern_size.height)
         height = pattern_size.width;
     else
         goto finalize;
 
     // find and store all the other rows
-    for( i = 1; ; i++ )
+    for (int i = 1; ; ++i)
     {
         if( !first )
             break;
         cur = first;
         first = 0;
-        for( j = 0;; j++ )
+        int j = 0;
+        for (; ; ++j)
         {
             cur->row = i;
-            out_corners[out_corner_count++] = cur;
+            out_corners.push_back(cur);
             //cvCircle( debug_img, cvPointFrom32f(cur->pt), 3, cvScalar(0,0,255-j*10), -1, 8, 0 );
-            if( cur->count == 2 + (i < height-1) && j > 0 )
+            if (cur->count == 2 + (i < height-1) && j > 0)
                 break;
 
             right = 0;
 
             // find a neighbor that has not been processed yet
             // and that has a neighbor from the previous row
-            for( k = 0; k < 4; k++ )
+            for (int k = 0; k < 4; ++k)
             {
-                c = cur->neighbors[k];
-                if( c && c->row > i )
+                ChessBoardCorner* c = cur->neighbors[k];
+                if (c && c->row > i)
                 {
-                    for( kk = 0; kk < 4; kk++ )
+                    int kk = 0;
+                    for (; kk < 4; ++kk)
                     {
-                        if( c->neighbors[kk] && c->neighbors[kk]->row == i-1 )
+                        if (c->neighbors[kk] && c->neighbors[kk]->row == i-1)
                             break;
                     }
-                    if( kk < 4 )
+                    if(kk < 4)
                     {
                         right = c;
-                        if( j > 0 )
+                        if (j > 0)
                             break;
                     }
-                    else if( j == 0 )
+                    else if (j == 0)
                         first = c;
                 }
             }
-            if( !right )
+            if (!right)
                 goto finalize;
             cur = right;
         }
 
-        if( j != width - 1 )
+        if (j != width - 1)
             goto finalize;
     }
 
-    if( out_corner_count != corner_count )
+    if ((int)out_corners.size() != corner_count)
         goto finalize;
 
     // check if we need to transpose the board
-    if( width != pattern_size.width )
+    if (width != pattern_size.width)
     {
-        CV_SWAP( width, height, k );
+        std::swap(width, height);
 
-        memcpy( &corners[0], out_corners, corner_count*sizeof(corners[0]) );
-        for( i = 0; i < height; i++ )
-            for( j = 0; j < width; j++ )
-                out_corners[i*width + j] = corners[j*height + i];
+        std::vector<ChessBoardCorner*> tmp(out_corners);
+        for (int i = 0; i < height; ++i)
+            for (int j = 0; j < width; ++j)
+                out_corners[i*width + j] = tmp[j*height + i];
     }
 
     // check if we need to revert the order in each row
     {
-        CvPoint2D32f p0 = out_corners[0]->pt, p1 = out_corners[pattern_size.width-1]->pt,
-                     p2 = out_corners[pattern_size.width]->pt;
+        cv::Point2f p0 = out_corners[0]->pt,
+                    p1 = out_corners[pattern_size.width-1]->pt,
+                    p2 = out_corners[pattern_size.width]->pt;
         if( (p1.x - p0.x)*(p2.y - p1.y) - (p1.y - p0.y)*(p2.x - p1.x) < 0 )
         {
-            if( width % 2 == 0 )
+            if (width % 2 == 0)
             {
-                for( i = 0; i < height; i++ )
-                    for( j = 0; j < width/2; j++ )
-                        CV_SWAP( out_corners[i*width+j], out_corners[i*width+width-j-1], c );
+                for (int i = 0; i < height; ++i)
+                    for (int j = 0; j < width/2; ++j)
+                        std::swap(out_corners[i*width+j], out_corners[i*width+width-j-1]);
             }
             else
             {
-                for( j = 0; j < width; j++ )
-                    for( i = 0; i < height/2; i++ )
-                        CV_SWAP( out_corners[i*width+j], out_corners[(height - i - 1)*width+j], c );
+                for (int j = 0; j < width; ++j)
+                    for (int i = 0; i < height/2; ++i)
+                        std::swap(out_corners[i*width+j], out_corners[(height - i - 1)*width+j]);
             }
         }
     }
 
     result = corner_count;
+}
 
 finalize:
-
-    if( result <= 0 )
+    if (result <= 0)
     {
-        corner_count = MIN( corner_count, pattern_size.width*pattern_size.height );
-        for( i = 0; i < corner_count; i++ )
+        corner_count = std::min(corner_count, pattern_size.area());
+        out_corners.resize(corner_count);
+        for (int i = 0; i < corner_count; i++)
             out_corners[i] = corners[i];
+
         result = -corner_count;
 
-        if (result == -pattern_size.width*pattern_size.height)
+        if (result == -pattern_size.area())
             result = -result;
     }
 
@@ -1564,19 +1610,13 @@ finalize:
 
 
 
-
-//=====================================================================================
-
-static void icvFindQuadNeighbors( CvCBQuad *quads, int quad_count )
+void ChessBoardDetector::findQuadNeighbors()
 {
     const float thresh_scale = 1.f;
-    int idx, i, k, j;
-    float dx, dy, dist;
-
     // find quad neighbors
-    for( idx = 0; idx < quad_count; idx++ )
+    for (int idx = 0; idx < all_quads_count; idx++)
     {
-        CvCBQuad* cur_quad = &quads[idx];
+        ChessBoardQuad& cur_quad = (ChessBoardQuad&)all_quads[idx];
 
         // choose the points of the current quadrangle that are close to
         // some points of the other quadrangles
@@ -1584,167 +1624,272 @@ static void icvFindQuadNeighbors( CvCBQuad *quads, int quad_count )
         // checker board). Search only in other quadrangles!
 
         // for each corner of this quadrangle
-        for( i = 0; i < 4; i++ )
+        for (int i = 0; i < 4; i++)
         {
-            CvPoint2D32f pt;
+            if (cur_quad.neighbors[i])
+                continue;
+
             float min_dist = FLT_MAX;
             int closest_corner_idx = -1;
-            CvCBQuad *closest_quad = 0;
-            CvCBCorner *closest_corner = 0;
-
-            if( cur_quad->neighbors[i] )
-                continue;
+            ChessBoardQuad *closest_quad = 0;
 
-            pt = cur_quad->corners[i]->pt;
+            cv::Point2f pt = cur_quad.corners[i]->pt;
 
             // find the closest corner in all other quadrangles
-            for( k = 0; k < quad_count; k++ )
+            for (int k = 0; k < all_quads_count; k++)
             {
-                if( k == idx )
+                if (k == idx)
                     continue;
 
-                for( j = 0; j < 4; j++ )
+                ChessBoardQuad& q_k = all_quads[k];
+
+                for (int j = 0; j < 4; j++)
                 {
-                    if( quads[k].neighbors[j] )
+                    if (q_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;
-
-                    if( dist < min_dist &&
-                        dist <= cur_quad->edge_len*thresh_scale &&
-                        dist <= quads[k].edge_len*thresh_scale )
+                    float dist = normL2Sqr<float>(pt - q_k.corners[j]->pt);
+                    if (dist < min_dist &&
+                        dist <= cur_quad.edge_len*thresh_scale &&
+                        dist <= q_k.edge_len*thresh_scale )
                     {
                         // check edge lengths, make sure they're compatible
                         // edges that are different by more than 1:4 are rejected
-                        float ediff = cur_quad->edge_len - quads[k].edge_len;
-                        if (ediff > 32*cur_quad->edge_len ||
-                            ediff > 32*quads[k].edge_len)
+                        float ediff = cur_quad.edge_len - q_k.edge_len;
+                        if (ediff > 32*cur_quad.edge_len ||
+                            ediff > 32*q_k.edge_len)
                         {
-                            PRINTF("Incompatible edge lengths\n");
+                            DPRINTF("Incompatible edge lengths");
                             continue;
                         }
                         closest_corner_idx = j;
-                        closest_quad = &quads[k];
+                        closest_quad = &q_k;
                         min_dist = dist;
                     }
                 }
             }
 
             // we found a matching corner point?
-            if( closest_corner_idx >= 0 && min_dist < FLT_MAX )
+            if (closest_corner_idx >= 0 && min_dist < FLT_MAX)
             {
+                CV_Assert(closest_quad);
+
+                if (cur_quad.count >= 4 || closest_quad->count >= 4)
+                    continue;
+
                 // If another point from our current quad is closer to the found corner
                 // than the current one, then we don't count this one after all.
                 // This is necessary to support small squares where otherwise the wrong
                 // corner will get matched to closest_quad;
-                closest_corner = closest_quad->corners[closest_corner_idx];
+                ChessBoardCorner& closest_corner = *closest_quad->corners[closest_corner_idx];
 
-                for( j = 0; j < 4; j++ )
+                int j = 0;
+                for (; j < 4; j++)
                 {
-                    if( cur_quad->neighbors[j] == closest_quad )
+                    if (cur_quad.neighbors[j] == closest_quad)
                         break;
 
-                    dx = closest_corner->pt.x - cur_quad->corners[j]->pt.x;
-                    dy = closest_corner->pt.y - cur_quad->corners[j]->pt.y;
-
-                    if( dx * dx + dy * dy < min_dist )
+                    if (normL2Sqr<float>(closest_corner.pt - cur_quad.corners[j]->pt) < min_dist)
                         break;
                 }
-
-                if( j < 4 || cur_quad->count >= 4 || closest_quad->count >= 4 )
+                if (j < 4)
                     continue;
 
                 // Check that each corner is a neighbor of different quads
-                for( j = 0; j < closest_quad->count; j++ )
+                for(j = 0; j < closest_quad->count; j++ )
                 {
-                    if( closest_quad->neighbors[j] == cur_quad )
+                    if (closest_quad->neighbors[j] == &cur_quad)
                         break;
                 }
-                if( j < closest_quad->count )
+                if (j < closest_quad->count)
                     continue;
 
                 // check whether the closest corner to closest_corner
                 // is different from cur_quad->corners[i]->pt
-                for( k = 0; k < quad_count; k++ )
+                for (j = 0; j < all_quads_count; j++ )
                 {
-                    CvCBQuad* q = &quads[k];
-                    if( k == idx || q == closest_quad )
+                    ChessBoardQuad* q = &const_cast<ChessBoardQuad&>(all_quads[j]);
+                    if (j == idx || q == closest_quad)
                         continue;
 
-                    for( j = 0; j < 4; j++ )
-                        if( !q->neighbors[j] )
+                    int k = 0;
+                    for (; k < 4; k++ )
+                    {
+                        if (!q->neighbors[k])
                         {
-                            dx = closest_corner->pt.x - q->corners[j]->pt.x;
-                            dy = closest_corner->pt.y - q->corners[j]->pt.y;
-                            dist = dx*dx + dy*dy;
-                            if( dist < min_dist )
+                            if (normL2Sqr<float>(closest_corner.pt - q->corners[k]->pt) < min_dist)
                                 break;
                         }
-                    if( j < 4 )
+                    }
+                    if (k < 4)
                         break;
                 }
-
-                if( k < quad_count )
+                if (j < all_quads_count)
                     continue;
 
-                closest_corner->pt.x = (pt.x + closest_corner->pt.x) * 0.5f;
-                closest_corner->pt.y = (pt.y + closest_corner->pt.y) * 0.5f;
+                closest_corner.pt = (pt + closest_corner.pt) * 0.5f;
 
                 // We've found one more corner - remember it
-                cur_quad->count++;
-                cur_quad->neighbors[i] = closest_quad;
-                cur_quad->corners[i] = closest_corner;
+                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->neighbors[closest_corner_idx] = &cur_quad;
             }
         }
     }
 }
 
-//=====================================================================================
 
 // returns corners in clockwise order
 // corners don't necessarily start at same position on quad (e.g.,
 //   top left corner)
-
-static int
-icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners,
-                  CvMemStorage *storage, const cv::Mat & image_, int flags, int *max_quad_buf_size )
+void ChessBoardDetector::generateQuads(const cv::Mat& image_, int flags)
 {
-    CvMat image_old(image_), *image = &image_old;
+    binarized_image = image_;  // save for debug purposes
+
     int quad_count = 0;
-    cv::Ptr<CvMemStorage> temp_storage;
 
-    if( out_quads )
-        *out_quads = 0;
+    all_quads.deallocate();
+    all_corners.deallocate();
 
-    if( out_corners )
-        *out_corners = 0;
+    // empiric bound for minimal allowed perimeter for squares
+    int min_size = 25; //cvRound( image->cols * image->rows * .03 * 0.01 * 0.92 );
 
-    CvSeq *src_contour = 0;
-    CvSeq *root;
-    CvContourEx* board = 0;
-    CvContourScanner scanner;
-    int i, idx, min_size;
+    bool filterQuads = (flags & CALIB_CB_FILTER_QUADS) != 0;
+#ifdef USE_CV_FINDCONTOURS // use cv::findContours
 
-    CV_Assert( out_corners && out_quads );
+    std::vector<std::vector<Point> > contours;
+    std::vector<Vec4i> hierarchy;
 
-    // empiric bound for minimal allowed perimeter for squares
-    min_size = 25; //cvRound( image->cols * image->rows * .03 * 0.01 * 0.92 );
+    cv::findContours(image_, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
+
+    if (contours.empty())
+    {
+        CV_LOG_DEBUG(NULL, "calib3d(chessboard): cv::findContours() returns no contours");
+        return;
+    }
+
+    std::vector<int> contour_child_counter(contours.size(), 0);
+    int boardIdx = -1;
+
+    std::vector<QuadCountour> contour_quads;
+
+    for (int idx = (int)(contours.size() - 1); idx >= 0; --idx)
+    {
+        int parentIdx = hierarchy[idx][3];
+        if (hierarchy[idx][2] != -1 || parentIdx == -1)  // holes only (no child contours and with parent)
+            continue;
+        const std::vector<Point>& contour = contours[idx];
+
+        Rect contour_rect = boundingRect(contour);
+        if (contour_rect.area() < min_size)
+            continue;
+
+        std::vector<Point> approx_contour;
+
+        const int min_approx_level = 1, max_approx_level = MAX_CONTOUR_APPROX;
+        for (int approx_level = min_approx_level; approx_level <= max_approx_level; approx_level++ )
+        {
+            approxPolyDP(contour, approx_contour, (float)approx_level, true);
+            if (approx_contour.size() == 4)
+                break;
+
+            // we call this again on its own output, because sometimes
+            // approxPoly() does not simplify as much as it should.
+            std::vector<Point> approx_contour_tmp;
+            std::swap(approx_contour, approx_contour_tmp);
+            approxPolyDP(approx_contour_tmp, approx_contour, (float)approx_level, true);
+            if (approx_contour.size() == 4)
+                break;
+        }
+
+        // reject non-quadrangles
+        if (approx_contour.size() != 4)
+            continue;
+        if (!cv::isContourConvex(approx_contour))
+            continue;
+
+        cv::Point pt[4];
+        for (int i = 0; i < 4; ++i)
+            pt[i] = approx_contour[i];
+        CV_LOG_VERBOSE(NULL, 9, "... contours(" << contour_quads.size() << " added):" << pt[0] << " " << pt[1] << " " << pt[2] << " " << pt[3]);
+
+        if (filterQuads)
+        {
+            double p = cv::arcLength(approx_contour, true);
+            double area = cv::contourArea(approx_contour, false);
+
+            double d1 = sqrt(normL2Sqr<double>(pt[0] - pt[2]));
+            double d2 = sqrt(normL2Sqr<double>(pt[1] - pt[3]));
+
+            // philipg.  Only accept those quadrangles which are more square
+            // than rectangular and which are big enough
+            double d3 = sqrt(normL2Sqr<double>(pt[0] - pt[1]));
+            double d4 = sqrt(normL2Sqr<double>(pt[1] - pt[2]));
+            if (!(d3*4 > d4 && d4*4 > d3 && d3*d4 < area*1.5 && area > min_size &&
+                d1 >= 0.15 * p && d2 >= 0.15 * p))
+                continue;
+        }
+
+        contour_child_counter[parentIdx]++;
+        if (boardIdx != parentIdx && (boardIdx < 0 || contour_child_counter[boardIdx] < contour_child_counter[parentIdx]))
+            boardIdx = parentIdx;
+
+        contour_quads.push_back(QuadCountour(pt, parentIdx));
+    }
+
+    size_t total = contour_quads.size();
+    size_t max_quad_buf_size = std::max((size_t)2, total * 3);
+    all_quads.allocate(max_quad_buf_size);
+    all_corners.allocate(max_quad_buf_size * 4);
+
+    // Create array of quads structures
+    for (size_t idx = 0; idx < total; ++idx)
+    {
+        QuadCountour& qc = contour_quads[idx];
+        if (filterQuads && qc.parent_contour != boardIdx)
+            continue;
+
+        int quad_idx = quad_count++;
+        ChessBoardQuad& q = all_quads[quad_idx];
+
+        // reset group ID
+        q = ChessBoardQuad();
+        for (int i = 0; i < 4; ++i)
+        {
+            Point2f pt(qc.pt[i]);
+            ChessBoardCorner& corner = all_corners[quad_idx * 4 + i];
+
+            corner = ChessBoardCorner(pt);
+            q.corners[i] = &corner;
+        }
+        q.edge_len = FLT_MAX;
+        for (int i = 0; i < 4; ++i)
+        {
+            float d = normL2Sqr<float>(q.corners[i]->pt - q.corners[(i+1)&3]->pt);
+            q.edge_len = std::min(q.edge_len, d);
+        }
+    }
+
+#else // use legacy API: cvStartFindContours / cvFindNextContour / cvEndFindContours
+
+    CvMat image_old = cvMat(image_), *image = &image_old;
+
+    CvContourEx* board = 0;
 
     // create temporary storage for contours and the sequence of pointers to found quadrangles
-    temp_storage.reset(cvCreateChildMemStorage( storage ));
-    root = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvSeq*), temp_storage );
+    cv::Ptr<CvMemStorage> temp_storage(cvCreateMemStorage(0));
+    CvSeq *root = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvSeq*), temp_storage);
 
     // initialize contour retrieving routine
-    scanner = cvStartFindContours( image, temp_storage, sizeof(CvContourEx),
-                                   CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
+    CvContourScanner 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* src_contour = NULL;
+    while ((src_contour = cvFindNextContour(scanner)) != NULL)
     {
         CvSeq *dst_contour = 0;
         CvRect rect = ((CvContour*)src_contour)->rect;
@@ -1753,8 +1898,7 @@ icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners,
         if( CV_IS_SEQ_HOLE(src_contour) && rect.width*rect.height >= min_size )
         {
             const int min_approx_level = 1, max_approx_level = MAX_CONTOUR_APPROX;
-            int approx_level;
-            for( approx_level = min_approx_level; approx_level <= max_approx_level; approx_level++ )
+            for (int 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 );
@@ -1773,34 +1917,24 @@ icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners,
             // reject non-quadrangles
             if( dst_contour->total == 4 && cvCheckContourConvexity(dst_contour) )
             {
-                CvPoint pt[4];
-                double d1, d2, p = cvContourPerimeter(dst_contour);
+                cv::Point2i pt[4];
+                double p = cvContourPerimeter(dst_contour);
                 double area = fabs(cvContourArea(dst_contour, CV_WHOLE_SEQ));
-                double dx, dy;
 
-                for( i = 0; i < 4; i++ )
+                for (int i = 0; i < 4; ++i)
                     pt[i] = *(CvPoint*)cvGetSeqElem(dst_contour, i);
+                CV_LOG_VERBOSE(NULL, 9, "... contours(" << root->total << " added):" << pt[0] << " " << pt[1] << " " << pt[2] << " " << pt[3]);
 
-                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);
+                double d1 = sqrt(normL2Sqr<double>(pt[0] - pt[2]));
+                double d2 = sqrt(normL2Sqr<double>(pt[1] - pt[3]));
 
                 // 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( !(flags & CV_CALIB_CB_FILTER_QUADS) ||
+                double d3 = sqrt(normL2Sqr<double>(pt[0] - pt[1]));
+                double d4 = sqrt(normL2Sqr<double>(pt[1] - pt[2]));
+                if (!filterQuads ||
                     (d3*4 > d4 && d4*4 > d3 && d3*d4 < area*1.5 && area > min_size &&
-                    d1 >= 0.15 * p && d2 >= 0.15 * p) )
+                    d1 >= 0.15 * p && d2 >= 0.15 * p))
                 {
                     CvContourEx* parent = (CvContourEx*)(src_contour->v_prev);
                     parent->counter++;
@@ -1818,151 +1952,152 @@ icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners,
     cvEndFindContours( &scanner );
 
     // allocate quad & corner buffers
-    *max_quad_buf_size = MAX(1, (root->total+root->total / 2)) * 2;
-    *out_quads = (CvCBQuad*)cvAlloc(*max_quad_buf_size * sizeof((*out_quads)[0]));
-    *out_corners = (CvCBCorner*)cvAlloc(*max_quad_buf_size * 4 * sizeof((*out_corners)[0]));
+    int total = root->total;
+    size_t max_quad_buf_size = std::max((size_t)2, (size_t)total * 3);
+    all_quads.allocate(max_quad_buf_size);
+    all_corners.allocate(max_quad_buf_size * 4);
 
     // Create array of quads structures
-    for( idx = 0; idx < root->total; idx++ )
+    for (int idx = 0; idx < 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 )
+        /* CvSeq* */src_contour = *(CvSeq**)cvGetSeqElem(root, idx);
+        if (filterQuads && src_contour->v_prev != (CvSeq*)board)
             continue;
 
+        int quad_idx = quad_count++;
+        ChessBoardQuad& q = all_quads[quad_idx];
+
         // reset group ID
-        memset( q, 0, sizeof(*q) );
-        q->group_idx = -1;
-        assert( src_contour->total == 4 );
-        for( i = 0; i < 4; i++ )
+        q = ChessBoardQuad();
+        CV_Assert(src_contour->total == 4);
+        for (int i = 0; i < 4; i++)
         {
-            CvPoint * onePoint = (CvPoint*)cvGetSeqElem(src_contour, i);
+            Point* onePoint = (Point*)cvGetSeqElem(src_contour, i);
             CV_Assert(onePoint != NULL);
-            CvPoint2D32f pt = cvPointTo32f(*onePoint);
-            CvCBCorner* corner = &(*out_corners)[quad_count*4 + i];
+            Point2f pt(*onePoint);
+            ChessBoardCorner& corner = all_corners[quad_idx*4 + i];
 
-            memset( corner, 0, sizeof(*corner) );
-            corner->pt = pt;
-            q->corners[i] = corner;
+            corner = ChessBoardCorner(pt);
+            q.corners[i] = &corner;
         }
-        q->edge_len = FLT_MAX;
-        for( i = 0; i < 4; i++ )
+        q.edge_len = FLT_MAX;
+        for (int 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;
+            float d = normL2Sqr<float>(q.corners[i]->pt - q.corners[(i+1)&3]->pt);
+            q.edge_len = std::min(q.edge_len, d);
         }
-        quad_count++;
     }
+#endif
 
-    return quad_count;
+    all_quads_count = quad_count;
+
+    CV_LOG_VERBOSE(NULL, 3, "Total quad contours: " << total);
+    CV_LOG_VERBOSE(NULL, 3, "max_quad_buf_size=" << max_quad_buf_size);
+    CV_LOG_VERBOSE(NULL, 3, "filtered quad_count=" << quad_count);
 }
 
-static bool processQuads(CvCBQuad *quads, int quad_count, CvSize pattern_size, int max_quad_buf_size,
-                         CvMemStorage * storage, CvCBCorner *corners, CvPoint2D32f *out_corners, int *out_corner_count, int & prev_sqr_size)
+bool ChessBoardDetector::processQuads(std::vector<cv::Point2f>& out_corners, int &prev_sqr_size)
 {
-    if( quad_count <= 0 )
+    out_corners.resize(0);
+    if (all_quads_count <= 0)
         return false;
 
-    bool found = false;
+    size_t max_quad_buf_size = all_quads.size();
 
     // Find quad's neighbors
-    icvFindQuadNeighbors( quads, quad_count );
-
-    // allocate extra for adding in icvOrderFoundQuads
-    CvCBQuad **quad_group = 0;
-    CvCBCorner **corner_group = 0;
+    findQuadNeighbors();
 
-    quad_group = (CvCBQuad**)cvAlloc( sizeof(quad_group[0]) * max_quad_buf_size);
-    corner_group = (CvCBCorner**)cvAlloc( sizeof(corner_group[0]) * max_quad_buf_size * 4 );
+    // allocate extra for adding in orderFoundQuads
+    std::vector<ChessBoardQuad*> quad_group;
+    std::vector<ChessBoardCorner*> corner_group; corner_group.reserve(max_quad_buf_size * 4);
 
-    for( int group_idx = 0; ; group_idx++ )
+    for (int group_idx = 0; ; group_idx++)
     {
-        int count = icvFindConnectedQuads( quads, quad_count, quad_group, group_idx, storage );
-
-        if( count == 0 )
+        findConnectedQuads(quad_group, group_idx);
+        if (quad_group.empty())
             break;
 
+        int count = (int)quad_group.size();
+
         // order the quad corners globally
         // maybe delete or add some
-        PRINTF("Starting ordering of inner quads (%d)\n", count);
-        count = icvOrderFoundConnectedQuads(count, quad_group, &quad_count, &quads, &corners,
-                                            pattern_size, max_quad_buf_size, storage );
-        PRINTF("Finished ordering of inner quads (%d)\n", count);
+        DPRINTF("Starting ordering of inner quads (%d)", count);
+        count = orderFoundConnectedQuads(quad_group);
+        DPRINTF("Finished ordering of inner quads (%d)", count);
 
         if (count == 0)
             continue;       // haven't found inner quads
 
         // If count is more than it should be, this will remove those quads
         // which cause maximum deviation from a nice square pattern.
-        count = icvCleanFoundConnectedQuads( count, quad_group, pattern_size );
-        PRINTF("Connected group: %d, count: %d\n", group_idx, count);
+        count = cleanFoundConnectedQuads(quad_group);
+        DPRINTF("Connected group: %d, count: %d", group_idx, count);
 
-        count = icvCheckQuadGroup( quad_group, count, corner_group, pattern_size );
-        PRINTF("Connected group: %d, count: %d\n", group_idx, count);
+        count = checkQuadGroup(quad_group, corner_group);
+        DPRINTF("Connected group: %d, count: %d", group_idx, count);
 
         int n = count > 0 ? pattern_size.width * pattern_size.height : -count;
-        n = MIN( n, pattern_size.width * pattern_size.height );
+        n = std::min(n, pattern_size.width * pattern_size.height);
         float sum_dist = 0;
         int total = 0;
 
         for(int i = 0; i < n; i++ )
         {
             int ni = 0;
-            float avgi = corner_group[i]->meanDist(&ni);
-            sum_dist += avgi*ni;
+            float sum = corner_group[i]->sumDist(ni);
+            sum_dist += sum;
             total += ni;
         }
-        prev_sqr_size = cvRound(sum_dist/MAX(total, 1));
+        prev_sqr_size = cvRound(sum_dist/std::max(total, 1));
 
-        if( count > 0 || (out_corner_count && -count > *out_corner_count) )
+        if (count > 0 || (-count > (int)out_corners.size()))
         {
             // copy corners to output array
-            for(int i = 0; i < n; i++ )
-                out_corners[i] = corner_group[i]->pt;
+            out_corners.reserve(n);
+            for (int i = 0; i < n; ++i)
+                out_corners.push_back(corner_group[i]->pt);
 
-            if( out_corner_count )
-                *out_corner_count = n;
-
-            if( count == pattern_size.width*pattern_size.height
-                    && icvCheckBoardMonotony( out_corners, pattern_size ))
+            if (count == pattern_size.width*pattern_size.height
+                    && checkBoardMonotony(out_corners))
             {
-                found = true;
-                break;
+                return true;
             }
         }
     }
 
-    cvFree(&quad_group);
-    cvFree(&corner_group);
-
-    return found;
+    return false;
 }
 
-//==================================================================================================
 
-CV_IMPL void
-cvDrawChessboardCorners( CvArr* _image, CvSize pattern_size,
-                         CvPoint2D32f* corners, int count, int found )
+
+void drawChessboardCorners( InputOutputArray image, Size patternSize,
+                                InputArray _corners,
+                                bool patternWasFound )
 {
+    CV_INSTRUMENT_REGION();
+
+    int type = image.type();
+    int cn = CV_MAT_CN(type);
+    CV_CheckType(type, cn == 1 || cn == 3 || cn == 4,
+            "Number of channels must be 1, 3 or 4" );
+
+    int depth = CV_MAT_DEPTH(type);
+    CV_CheckType(type, depth == CV_8U || depth == CV_16U || depth == CV_32F,
+            "Only 8-bit, 16-bit or floating-point 32-bit images are supported");
+
+    if (_corners.empty())
+        return;
+    Mat corners = _corners.getMat();
+    const Point2f* corners_data = corners.ptr<Point2f>(0);
+    int nelems = corners.checkVector(2, CV_32F, true);
+    CV_Assert(nelems >= 0);
+
     const int shift = 0;
     const int radius = 4;
     const int r = radius*(1 << shift);
-    int i;
-    CvMat stub, *image;
-    double scale = 1;
-    int type, cn, line_type;
-
-    image = cvGetMat( _image, &stub );
 
-    type = CV_MAT_TYPE(image->type);
-    cn = CV_MAT_CN(type);
-    if( cn != 1 && cn != 3 && cn != 4 )
-        CV_Error( CV_StsUnsupportedFormat, "Number of channels must be 1, 3 or 4" );
-
-    switch( CV_MAT_DEPTH(image->type) )
+    double scale = 1;
+    switch (depth)
     {
     case CV_8U:
         scale = 1;
@@ -1973,143 +2108,85 @@ cvDrawChessboardCorners( CvArr* _image, CvSize pattern_size,
     case CV_32F:
         scale = 1./255;
         break;
-    default:
-        CV_Error( CV_StsUnsupportedFormat,
-            "Only 8-bit, 16-bit or floating-point 32-bit images are supported" );
     }
 
-    line_type = type == CV_8UC1 || type == CV_8UC3 ? CV_AA : 8;
+    int line_type = (type == CV_8UC1 || type == CV_8UC3) ? LINE_AA : LINE_8;
 
-    if( !found )
+    if (!patternWasFound)
     {
-        CvScalar color(0,0,255,0);
-        if( cn == 1 )
-            color = cvScalarAll(200);
-        color.val[0] *= scale;
-        color.val[1] *= scale;
-        color.val[2] *= scale;
-        color.val[3] *= scale;
-
-        for( i = 0; i < count; i++ )
+        Scalar color(0,0,255,0);
+        if (cn == 1)
+            color = Scalar::all(200);
+        color *= scale;
+
+        for (int i = 0; i < nelems; i++ )
         {
-            CvPoint pt;
-            pt.x = cvRound(corners[i].x*(1 << shift));
-            pt.y = cvRound(corners[i].y*(1 << shift));
-            cvLine( image, cvPoint( pt.x - r, pt.y - r ),
-                    cvPoint( pt.x + r, pt.y + r ), color, 1, line_type, shift );
-            cvLine( image, cvPoint( pt.x - r, pt.y + r),
-                    cvPoint( pt.x + r, pt.y - r), color, 1, line_type, shift );
-            cvCircle( image, pt, r+(1<<shift), color, 1, line_type, shift );
+            cv::Point2i pt(
+                    cvRound(corners_data[i].x*(1 << shift)),
+                    cvRound(corners_data[i].y*(1 << shift))
+            );
+            line(image, Point(pt.x - r, pt.y - r), Point( pt.x + r, pt.y + r), color, 1, line_type, shift);
+            line(image, Point(pt.x - r, pt.y + r), Point( pt.x + r, pt.y - r), color, 1, line_type, shift);
+            circle(image, pt, r+(1<<shift), color, 1, line_type, shift);
         }
     }
     else
     {
-        int x, y;
-        CvPoint prev_pt;
         const int line_max = 7;
-        static const CvScalar line_colors[line_max] =
+        static const int line_colors[line_max][4] =
         {
-            CvScalar(0,0,255),
-            CvScalar(0,128,255),
-            CvScalar(0,200,200),
-            CvScalar(0,255,0),
-            CvScalar(200,200,0),
-            CvScalar(255,0,0),
-            CvScalar(255,0,255)
+            {0,0,255,0},
+            {0,128,255,0},
+            {0,200,200,0},
+            {0,255,0,0},
+            {200,200,0,0},
+            {255,0,0,0},
+            {255,0,255,0}
         };
 
-        for( y = 0, i = 0; y < pattern_size.height; y++ )
+        cv::Point2i prev_pt;
+        for (int y = 0, i = 0; y < patternSize.height; y++)
         {
-            CvScalar color = line_colors[y % line_max];
-            if( cn == 1 )
-                color = cvScalarAll(200);
-            color.val[0] *= scale;
-            color.val[1] *= scale;
-            color.val[2] *= scale;
-            color.val[3] *= scale;
-
-            for( x = 0; x < pattern_size.width; x++, i++ )
+            const int* line_color = &line_colors[y % line_max][0];
+            Scalar color(line_color[0], line_color[1], line_color[2], line_color[3]);
+            if (cn == 1)
+                color = Scalar::all(200);
+            color *= scale;
+
+            for (int x = 0; x < patternSize.width; x++, i++)
             {
-                CvPoint pt;
-                pt.x = cvRound(corners[i].x*(1 << shift));
-                pt.y = cvRound(corners[i].y*(1 << shift));
-
-                if( i != 0 )
-                    cvLine( image, prev_pt, pt, color, 1, line_type, shift );
-
-                cvLine( image, cvPoint(pt.x - r, pt.y - r),
-                        cvPoint(pt.x + r, pt.y + r), color, 1, line_type, shift );
-                cvLine( image, cvPoint(pt.x - r, pt.y + r),
-                        cvPoint(pt.x + r, pt.y - r), color, 1, line_type, shift );
-                cvCircle( image, pt, r+(1<<shift), color, 1, line_type, shift );
+                cv::Point2i pt(
+                        cvRound(corners_data[i].x*(1 << shift)),
+                        cvRound(corners_data[i].y*(1 << shift))
+                );
+
+                if (i != 0)
+                    line(image, prev_pt, pt, color, 1, line_type, shift);
+
+                line(image, Point(pt.x - r, pt.y - r), Point( pt.x + r, pt.y + r), color, 1, line_type, shift);
+                line(image, Point(pt.x - r, pt.y + r), Point( pt.x + r, pt.y - r), color, 1, line_type, shift);
+                circle(image, pt, r+(1<<shift), color, 1, line_type, shift);
                 prev_pt = pt;
             }
         }
     }
 }
 
-bool cv::findChessboardCorners( InputArray _image, Size patternSize,
-                            OutputArray corners, int flags )
+static int quiet_error(int /*status*/, const char* /*func_name*/,
+                       const char* /*err_msg*/, const char* /*file_name*/,
+                       int /*line*/, void* /*userdata*/)
 {
-    CV_INSTRUMENT_REGION()
-
-    int count = patternSize.area()*2;
-    std::vector<Point2f> tmpcorners(count+1);
-    Mat image = _image.getMat(); CvMat c_image = image;
-    bool ok = cvFindChessboardCorners(&c_image, patternSize,
-        (CvPoint2D32f*)&tmpcorners[0], &count, flags ) > 0;
-    if( count > 0 )
-    {
-        tmpcorners.resize(count);
-        Mat(tmpcorners).copyTo(corners);
-    }
-    else
-        corners.release();
-    return ok;
-}
-
-namespace
-{
-int quiet_error(int /*status*/, const char* /*func_name*/,
-                                       const char* /*err_msg*/, const char* /*file_name*/,
-                                       int /*line*/, void* /*userdata*/ )
-{
-  return 0;
-}
-}
-
-void cv::drawChessboardCorners( InputOutputArray _image, Size patternSize,
-                            InputArray _corners,
-                            bool patternWasFound )
-{
-    CV_INSTRUMENT_REGION()
-
-    Mat corners = _corners.getMat();
-    if( corners.empty() )
-        return;
-    Mat image = _image.getMat(); CvMat c_image = image;
-    int nelems = corners.checkVector(2, CV_32F, true);
-    CV_Assert(nelems >= 0);
-    cvDrawChessboardCorners( &c_image, patternSize, corners.ptr<CvPoint2D32f>(),
-                             nelems, patternWasFound );
-}
-
-bool cv::findCirclesGrid( InputArray image, Size patternSize,
-                                   OutputArray centers, int flags,
-                                   const Ptr<FeatureDetector> &blobDetector,
-                                   CirclesGridFinderParameters parameters)
-{
-    CirclesGridFinderParameters2 parameters2;
-    *((CirclesGridFinderParameters*)&parameters2) = parameters;
-    return cv::findCirclesGrid2(image, patternSize, centers, flags, blobDetector, parameters2);
+    return 0;
 }
 
-bool cv::findCirclesGrid2( InputArray _image, Size patternSize,
+bool findCirclesGrid( InputArray _image, Size patternSize,
                           OutputArray _centers, int flags, const Ptr<FeatureDetector> &blobDetector,
-                          CirclesGridFinderParameters2 parameters)
+                          const CirclesGridFinderParameters& parameters_)
 {
     CV_INSTRUMENT_REGION()
 
+    CirclesGridFinderParameters parameters = parameters_; // parameters.gridType is amended below
+
     bool isAsymmetricGrid = (flags & CALIB_CB_ASYMMETRIC_GRID) ? true : false;
     bool isSymmetricGrid  = (flags & CALIB_CB_SYMMETRIC_GRID ) ? true : false;
     CV_Assert(isAsymmetricGrid ^ isSymmetricGrid);
@@ -2149,7 +2226,7 @@ bool cv::findCirclesGrid2( InputArray _image, Size patternSize,
 #define BE_QUIET 1
 #if BE_QUIET
       void* oldCbkData;
-      ErrorCallback oldCbk = redirectError(quiet_error, 0, &oldCbkData);
+      ErrorCallback oldCbk = redirectError(quiet_error, 0, &oldCbkData); // FIXIT not thread safe
 #endif
       CV_TRY
       {
@@ -2173,7 +2250,7 @@ bool cv::findCirclesGrid2( InputArray _image, Size patternSize,
         boxFinder.getAsymmetricHoles(centers);
         break;
           default:
-            CV_Error(CV_StsBadArg, "Unknown pattern type");
+            CV_Error(Error::StsBadArg, "Unknown pattern type");
         }
 
         if (i != 0)
@@ -2198,10 +2275,11 @@ bool cv::findCirclesGrid2( InputArray _image, Size patternSize,
     return false;
 }
 
-bool cv::findCirclesGrid( InputArray _image, Size patternSize,
-                          OutputArray _centers, int flags, const Ptr<FeatureDetector> &blobDetector)
+bool findCirclesGrid(InputArray _image, Size patternSize,
+                     OutputArray _centers, int flags, const Ptr<FeatureDetector> &blobDetector)
 {
-    return cv::findCirclesGrid2(_image, patternSize, _centers, flags, blobDetector, CirclesGridFinderParameters2());
+    return cv::findCirclesGrid(_image, patternSize, _centers, flags, blobDetector, CirclesGridFinderParameters());
 }
 
+} // namespace
 /* End of file. */