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