Home | History | Annotate | Download | only in src
      1 /*M///////////////////////////////////////////////////////////////////////////////////////
      2  //
      3  //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
      4  //
      5  //  By downloading, copying, installing or using the software you agree to this license.
      6  //  If you do not agree to this license, do not download, install,
      7  //  copy or use the software.
      8  //
      9  //
     10  //                        Intel License Agreement
     11  //                For Open Source Computer Vision Library
     12  //
     13  // Copyright (C) 2000, Intel Corporation, all rights reserved.
     14  // Third party copyrights are property of their respective owners.
     15  //
     16  // Redistribution and use in source and binary forms, with or without modification,
     17  // are permitted provided that the following conditions are met:
     18  //
     19  //   * Redistribution's of source code must retain the above copyright notice,
     20  //     this list of conditions and the following disclaimer.
     21  //
     22  //   * Redistribution's in binary form must reproduce the above copyright notice,
     23  //     this list of conditions and the following disclaimer in the documentation
     24  //     and/or other materials provided with the distribution.
     25  //
     26  //   * The name of Intel Corporation may not be used to endorse or promote products
     27  //     derived from this software without specific prior written permission.
     28  //
     29  // This software is provided by the copyright holders and contributors "as is" and
     30  // any express or implied warranties, including, but not limited to, the implied
     31  // warranties of merchantability and fitness for a particular purpose are disclaimed.
     32  // In no event shall the Intel Corporation or contributors be liable for any direct,
     33  // indirect, incidental, special, exemplary, or consequential damages
     34  // (including, but not limited to, procurement of substitute goods or services;
     35  // loss of use, data, or profits; or business interruption) however caused
     36  // and on any theory of liability, whether in contract, strict liability,
     37  // or tort (including negligence or otherwise) arising in any way out of
     38  // the use of this software, even if advised of the possibility of such damage.
     39  //
     40  //M*/
     41 
     42 #include "precomp.hpp"
     43 #include "opencv2/imgproc/imgproc_c.h"
     44 #include "opencv2/calib3d/calib3d_c.h"
     45 
     46 #include <vector>
     47 #include <algorithm>
     48 
     49 //#define DEBUG_WINDOWS
     50 
     51 #if defined(DEBUG_WINDOWS)
     52 #  include "opencv2/opencv_modules.hpp"
     53 #  ifdef HAVE_OPENCV_HIGHGUI
     54 #    include "opencv2/highgui.hpp"
     55 #  else
     56 #    undef DEBUG_WINDOWS
     57 #  endif
     58 #endif
     59 
     60 static void icvGetQuadrangleHypotheses(CvSeq* contours, std::vector<std::pair<float, int> >& quads, int class_id)
     61 {
     62     const float min_aspect_ratio = 0.3f;
     63     const float max_aspect_ratio = 3.0f;
     64     const float min_box_size = 10.0f;
     65 
     66     for(CvSeq* seq = contours; seq != NULL; seq = seq->h_next)
     67     {
     68         CvBox2D box = cvMinAreaRect2(seq);
     69         float box_size = MAX(box.size.width, box.size.height);
     70         if(box_size < min_box_size)
     71         {
     72             continue;
     73         }
     74 
     75         float aspect_ratio = box.size.width/MAX(box.size.height, 1);
     76         if(aspect_ratio < min_aspect_ratio || aspect_ratio > max_aspect_ratio)
     77         {
     78             continue;
     79         }
     80 
     81         quads.push_back(std::pair<float, int>(box_size, class_id));
     82     }
     83 }
     84 
     85 static void countClasses(const std::vector<std::pair<float, int> >& pairs, size_t idx1, size_t idx2, std::vector<int>& counts)
     86 {
     87     counts.assign(2, 0);
     88     for(size_t i = idx1; i != idx2; i++)
     89     {
     90         counts[pairs[i].second]++;
     91     }
     92 }
     93 
     94 inline bool less_pred(const std::pair<float, int>& p1, const std::pair<float, int>& p2)
     95 {
     96     return p1.first < p2.first;
     97 }
     98 
     99 // does a fast check if a chessboard is in the input image. This is a workaround to
    100 // a problem of cvFindChessboardCorners being slow on images with no chessboard
    101 // - src: input image
    102 // - size: chessboard size
    103 // Returns 1 if a chessboard can be in this image and findChessboardCorners should be called,
    104 // 0 if there is no chessboard, -1 in case of error
    105 int cvCheckChessboard(IplImage* src, CvSize size)
    106 {
    107     if(src->nChannels > 1)
    108     {
    109         cvError(CV_BadNumChannels, "cvCheckChessboard", "supports single-channel images only",
    110                 __FILE__, __LINE__);
    111     }
    112 
    113     if(src->depth != 8)
    114     {
    115         cvError(CV_BadDepth, "cvCheckChessboard", "supports depth=8 images only",
    116                 __FILE__, __LINE__);
    117     }
    118 
    119     const int erosion_count = 1;
    120     const float black_level = 20.f;
    121     const float white_level = 130.f;
    122     const float black_white_gap = 70.f;
    123 
    124 #if defined(DEBUG_WINDOWS)
    125     cvNamedWindow("1", 1);
    126     cvShowImage("1", src);
    127     cvWaitKey(0);
    128 #endif //DEBUG_WINDOWS
    129 
    130     CvMemStorage* storage = cvCreateMemStorage();
    131 
    132     IplImage* white = cvCloneImage(src);
    133     IplImage* black = cvCloneImage(src);
    134 
    135     cvErode(white, white, NULL, erosion_count);
    136     cvDilate(black, black, NULL, erosion_count);
    137     IplImage* thresh = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
    138 
    139     int result = 0;
    140     for(float thresh_level = black_level; thresh_level < white_level && !result; thresh_level += 20.0f)
    141     {
    142         cvThreshold(white, thresh, thresh_level + black_white_gap, 255, CV_THRESH_BINARY);
    143 
    144 #if defined(DEBUG_WINDOWS)
    145         cvShowImage("1", thresh);
    146         cvWaitKey(0);
    147 #endif //DEBUG_WINDOWS
    148 
    149         CvSeq* first = 0;
    150         std::vector<std::pair<float, int> > quads;
    151         cvFindContours(thresh, storage, &first, sizeof(CvContour), CV_RETR_CCOMP);
    152         icvGetQuadrangleHypotheses(first, quads, 1);
    153 
    154         cvThreshold(black, thresh, thresh_level, 255, CV_THRESH_BINARY_INV);
    155 
    156 #if defined(DEBUG_WINDOWS)
    157         cvShowImage("1", thresh);
    158         cvWaitKey(0);
    159 #endif //DEBUG_WINDOWS
    160 
    161         cvFindContours(thresh, storage, &first, sizeof(CvContour), CV_RETR_CCOMP);
    162         icvGetQuadrangleHypotheses(first, quads, 0);
    163 
    164         const size_t min_quads_count = size.width*size.height/2;
    165         std::sort(quads.begin(), quads.end(), less_pred);
    166 
    167         // now check if there are many hypotheses with similar sizes
    168         // do this by floodfill-style algorithm
    169         const float size_rel_dev = 0.4f;
    170 
    171         for(size_t i = 0; i < quads.size(); i++)
    172         {
    173             size_t j = i + 1;
    174             for(; j < quads.size(); j++)
    175             {
    176                 if(quads[j].first/quads[i].first > 1.0f + size_rel_dev)
    177                 {
    178                     break;
    179                 }
    180             }
    181 
    182             if(j + 1 > min_quads_count + i)
    183             {
    184                 // check the number of black and white squares
    185                 std::vector<int> counts;
    186                 countClasses(quads, i, j, counts);
    187                 const int black_count = cvRound(ceil(size.width/2.0)*ceil(size.height/2.0));
    188                 const int white_count = cvRound(floor(size.width/2.0)*floor(size.height/2.0));
    189                 if(counts[0] < black_count*0.75 ||
    190                    counts[1] < white_count*0.75)
    191                 {
    192                     continue;
    193                 }
    194                 result = 1;
    195                 break;
    196             }
    197         }
    198     }
    199 
    200 
    201     cvReleaseImage(&thresh);
    202     cvReleaseImage(&white);
    203     cvReleaseImage(&black);
    204     cvReleaseMemStorage(&storage);
    205 
    206     return result;
    207 }
    208