1.源码实现
#include <iostream>
#include <vector>
#include <math.h>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
double angle(const Point &pt1, const Point &pt2, const 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-10);
}
void findSquares(const Mat &image, Mat &out)
{
Mat src,dst, gray_one, gray;
vector<vector<Point>> squares;
vector<vector<Point>> squares2;
vector<Point> centers;
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
int thresh = 50, N = 5;
squares.clear();
src = image.clone();
out = image.clone();
gray_one = Mat(src.size(), CV_8U);
//滤波增强边缘检测
medianBlur(src, dst, 9);
dst = src;
//在图像的每个颜色通道中查找矩形
for (int c = 0; c < image.channels(); c++)
{
int ch[] = {c, 0};
//通道分离
mixChannels(&dst, 1, &gray_one, 1, ch, 1);
//尝试几个阈值
for(int l = 0; l < N; l++)
{
//用canny()提取边缘
if(l == 0)
{
//检测边缘
Canny(gray_one, gray, 5, thresh, 5);
//膨?
dilate(gray, gray, Mat(), Point(-1, -1));
//imshow("dilate", gray);
}
else
{
gray = gray_one >= (l + 1) * 255 / N;
}
//轮廓查找
findContours(gray, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
vector<Point> approx;
//检测所找到的轮廓
for(size_t i = 0; i < contours.size(); i++)
{
//使用图像轮廓点进行多边形拟合
approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);
//计算轮廓面积后,得到矩形4个顶点
if(approx.size() == 4 &&fabs(contourArea(Mat(approx))) > 1000 && isContourConvex(Mat(approx)))
{
double maxCosine = 0;
for(int j = 2; j < 5; j++)
{
//求轮廓边缘之间角度的最大余弦
double cosine = fabs(angle(approx[j % 4], approx[j - 2], approx[j - 1]));
maxCosine = MAX(maxCosine, cosine);
}
if(maxCosine < 0.3)
{
squares.push_back(approx);
}
}
}
}
}
//cout << squares.size() << endl;
int k = 0;
for(size_t i = 0; i < squares.size(); i++)
{
const Point* p = &squares[i][0];
Point center((squares[i][0].x+squares[i][1].x+squares[i][2].x+squares[i][3].x)/4.0, (squares[i][0].y+squares[i][1].y+squares[i][2].y+squares[i][3].y)/4.0);
int n = (int)squares[i].size();
bool flag = false;
//cout << "(" << center.x << ", ";
//cout << center.y << ")" << endl;
for(int j=0; j<centers.size(); j++)
{
if((centers[j].x - center.x)*(centers[j].x - center.x) + (centers[j].y - center.y)*(centers[j].y - center.y) < 16)
{
flag = true;
int max1 = 0;
int max2 = 0;
int max3 = 0;
int max4 = 0;
for(int u=0; u<4; u++)
{
if(squares[i][u].x - centers[j].x < 0)
{
max1 = centers[j].x - squares[i][u].x > max1 ? centers[j].x - squares[i][u].x : max1;
}
else
{
max1 = squares[i][u].x - centers[j].x > max1 ? squares[i][u].x - centers[j].x : max1;
}
if(squares[i][u].y - centers[j].y < 0)
{
max3 = centers[j].y - squares[i][u].y > max3 ? centers[j].y - squares[i][u].y : max3;
}
else
{
max3 = squares[i][u].y - squares[i][u].y > max3 ? squares[i][u].y - squares[i][u].y : max3;
}
}
for(int u=0; u<4; u++)
{
if(squares2[j][u].x - centers[j].x < 0)
{
max2 = centers[j].x - squares2[j][u].x > max1 ? centers[j].x - squares2[j][u].x : max2;
}
else
{
max2 = squares2[j][u].x - centers[j].x > max2 ? squares2[j][u].x - centers[j].x : max2;
}
if(squares2[j][u].y - centers[j].y < 0)
{
max4 = centers[j].y - squares2[j][u].y > max1 ? centers[j].y - squares2[j][u].y : max4;
}
else
{
max4 = squares2[j][u].y - centers[j].y > max4 ? squares2[j][u].y - centers[j].y : max4;
}
}
max1 = max1 > max2 ? max1 : max2;
max3 = max3 > max4 ? max3 : max4;
squares2[j][0] = Point(centers[j].x-max1, centers[j].y-max3);
squares2[j][1] = Point(centers[j].x+max1, centers[j].y-max3);
squares2[j][2] = Point(centers[j].x+max1, centers[j].y+max3);
squares2[j][3] = Point(centers[j].x-max1, centers[j].y+max3);
break;
}
}
if(!flag)
{
squares2.push_back(squares[i]);
centers.push_back(center);
if(p->x > 3 && p->y > 3)
{
cout << "center: " << center << endl;
k++;
//polylines(out, &p, &n, 1, true, Scalar(0, 0, 255), 2, LINE_AA);
}
}
}
for(int j=0; j<squares2.size(); j++)
{
const Point *p = &squares2[j][0];
int n = (int)squares2[j].size();
polylines(out, &p, &n, 1, true, Scalar(0, 0, 255), 1, LINE_AA);
}
cout << "square number: " << k << endl;
}
int main()
{
Mat src, dst;
src = imread("7.png");
findSquares(src, dst);
imwrite("8.png", dst);
return 0;
}
2.编译源码
$ g++ -o squares squares.cpp -std=c++11 -I/usr/local/opencv3/include -L/usr/local/opencv3/lib -lopencv_core -lopencv_imgproc -lopencv_imgcodecs -Wl,-rpath=/usr/local/opencv3/lib
3.原图及检测结果
7.png8.png
网友评论