// The "Square Detector" program.
// It loads several images sequentially and tries to find squares in
// each image #include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp" #include <iostream>
#include <math.h>
#include <string.h>
#include <vector> using namespace cv;
using namespace std; static void help()
{
cout <<
"\nA program using pyramid scaling, Canny, contours, contour simpification and\n"
"memory storage (it's got it all folks) to find\n"
"squares in a list of images pic1-6.png\n"
"Returns sequence of squares detected on the image.\n"
"the sequence is stored in the specified memory storage\n"
"Call:\n"
"./squares\n"
"Using OpenCV version %s\n" << CV_VERSION << "\n" << endl;
} int thresh = , N = ;
const char* wndname = "Square Detection Demo"; // helper function:
// finds a cosine of angle between vectors
// from pt0->pt1 and from pt0->pt2
static double angle( Point pt1, Point pt2, Point pt0 )
{
double dx1 = pt1.x - pt0.x;
double dy1 = pt1.y - pt0.y;
double dx2 = pt2.x - pt0.x;
double dy2 = pt2.y - pt0.y;
return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-);
} // returns sequence of squares detected on the image.
// the sequence is stored in the specified memory storage
static void findSquares( const Mat& image, vector<vector<Point> >& squares )
{
squares.clear(); Mat pyr, timg, gray0(image.size(), CV_8U), gray; // down-scale and upscale the image to filter out the noise
pyrDown(image, pyr, Size(image.cols/, image.rows/));
pyrUp(pyr, timg, image.size());
vector<vector<Point> > contours; // find squares in every color plane of the image
for( int c = ; c < ; c++ )
{
int ch[] = {c, };
mixChannels(&timg, , &gray0, , ch, );//分别将r,g,b三个通道的内容拷贝到gray0通道 // try several threshold levels
for( int l = ; l < N; l++ )
{
// hack: use Canny instead of zero threshold level.
// Canny helps to catch squares with gradient shading
if( l == )
{
// apply Canny. Take the upper threshold from slider
// and set the lower to 0 (which forces edges merging)
Canny(gray0, gray, , thresh, );
// dilate canny output to remove potential
// holes between edge segments
dilate(gray, gray, Mat(), Point(-,-)); }
else
{
// apply threshold if l!=0:
// tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0
gray = gray0 >= (l+)*/N;
} // find contours and store them all as a list
//imshow("temp",gray);
findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); vector<Point> approx; // test each contour
for( size_t i = ; i < contours.size(); i++ )
{
// approximate contour with accuracy proportional
// to the contour perimeter
approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true); // square contours should have 4 vertices after approximation
// relatively large area (to filter out noisy contours)
// and be convex.
// Note: absolute value of an area is used because
// area may be positive or negative - in accordance with the
// contour orientation int a=approx.size();
int b=abs(contourArea(Mat(approx)));
bool c=isContourConvex(Mat(approx));
if( approx.size() == &&
fabs(contourArea(Mat(approx))) > &&fabs(contourArea(Mat(approx)))<&&
isContourConvex(Mat(approx)) )
{
double maxCosine = ; for( int j = ; j < ; j++ )
{
// find the maximum cosine of the angle between joint edges
double cosine = fabs(angle(approx[j%], approx[j-], approx[j-]));
maxCosine = MAX(maxCosine, cosine);
} // if cosines of all angles are small
// (all angles are ~90 degree) then write quandrange
// vertices to resultant sequence
if( maxCosine < 0.5 )
squares.push_back(approx);
}
}
}
}
} // the function draws all the squares in the image
static void drawSquares( Mat& image, const vector<vector<Point> >& squares )
{
//vector<Point> pointsToTest;
vector<int> valueOfChannel0/*,valueOfChannel1,valueOfChannel2*/;
int differentPoint,normalPoint,tempPoint=;
bool setDifferentPoint=;
//bool setNormalPoint=0; for( size_t i = ; i < squares.size(); i++ )
{
const Point* p = &squares[i][];
int n = (int)squares[i].size(); //////////////////////////////////////////////////////////////////////////////////////////////
Point middlePoint((squares[i][].x+squares[i][].x)/,(squares[i][].y+squares[i][].y)/);
//pointsToTest.push_back(middlePoint);
tempPoint=(int)image.at<Vec3b>(middlePoint.y,middlePoint.x)[];
//cout<<tempPoint<<endl;
if (==i)
{
normalPoint=tempPoint;
polylines(image, &p, &n, , true, Scalar(,,), , CV_AA);
}
else
{
if (tempPoint!=normalPoint)
{
if (!setDifferentPoint)
{
differentPoint=tempPoint;
setDifferentPoint=;
}
polylines(image, &p, &n, , true, Scalar(,,), , CV_AA);
}
else
{
polylines(image, &p, &n, , true, Scalar(,,), , CV_AA);
} } } imshow(wndname, image);
} int main(int /*argc*/, char** /*argv*/)
{
static const char* names[] = { "Image 001.png", "Image 002.png", "Image 003.png",
"Image 004.png", "Image 005.png", "Image 006.png","Image 007.png", };
help();
namedWindow( wndname, );
vector<vector<Point> > squares; for( int i = ; names[i] != ; i++ )
{
Mat image = imread(names[i], );
if( image.empty() )
{
cout << "Couldn't load " << names[i] << endl;
continue;
} findSquares(image, squares);
drawSquares(image, squares); int c = waitKey();
if( (char)c == )
break;
remove("Image 001.png");
} return ;
}