識別形狀
有九個圖案和最外面的正方形輪廓,識別出10個輪廓形狀和每個輪廓的重心座標。
#include<opencv2/opencv.hpp>
#include<opencv2\legacy\legacy.hpp>
#include<vector>
#include<iostream>
double angle(cv::Point pt1, cv::Point pt2, cv::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);
}
int main()
{
cv::Mat srcImg, tempImg,gary,thresh,srcImg1;
cv::Mat dstImg;
int j = 0;
double s = 0;
srcImg = cv::imread("90.bmp");
if (!srcImg.data)
{
std::cout << "no img" << std::endl;
return -1;
}
//圖片處理
resize(srcImg, srcImg, cv::Size(srcImg.cols / 2, srcImg.rows / 2), 0, 0);//縮放
cvtColor(srcImg, gary, CV_RGB2GRAY);//灰度圖
medianBlur(gary, gary, 3);//中值濾波
threshold(gary, thresh, 0, 255, cv::THRESH_OTSU);//二值化
srcImg1 = thresh.clone();
dstImg = cv::Mat(srcImg.size(), CV_8UC3, cv::Scalar(255, 255, 255));
//尋找輪廓
std::vector<std::vector<cv::Point>>contours;
findContours(srcImg1, contours, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
std::vector<cv::Point>approx;
//圓
std::vector<cv::Vec3f>circles;
HoughCircles(gary, circles, CV_HOUGH_GRADIENT, 1, srcImg.rows / 2, 100, 60, 0, 0);//單通道
for (size_t i = 0; i < circles.size(); i++)
{
cv::Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
circle(dstImg, center, radius, cv::Scalar(0, 255, 0), 5, 8, 0);
circle(dstImg, center, 3, cv::Scalar(0, 255, 0), -1);
std::cout << "圓心" << i + 1 << center << std::endl;
}
//菱形
std::vector<cv::Point>squares;
//長方形
std::vector<cv::Point>changfang;
//正方形
std::vector<cv::Point>zhengfang;
//三角形
std::vector<cv::Point>sanjiao;
//五角星
std::vector<cv::Point>wujiao;
//五邊形
std::vector<cv::Point>wubian;
//十字形
std::vector<cv::Point>shizi;
//梅花形
std::vector<cv::Point>meihua;
//畫四邊形
double t;
for (size_t i = 0; i < contours.size(); i++)
{
drawContours(dstImg, contours, i, cv::Scalar(100, 100, 100), 3);
approxPolyDP(contours[i], approx, arcLength(cv::Mat(contours[i]), true)*0.02, true);
if (approx.size() == 4 && fabs(contourArea(cv::Mat(approx))) > 1000 && isContourConvex(cv::Mat(approx)))//4條邊;面積大於1000;凸多邊形
{
double minDist = 1e10;
double d[5];
double maxCosine = 0.0;
for (int i = 0; i < 4; i++)//求最小邊
{
cv::Point side = approx[i] - approx[(i + 1) % 4];
double squaredSideLength = side.dot(side);
d[i] = squaredSideLength;
minDist = std::min(minDist, squaredSideLength);
}
if (minDist<2000)
continue;
for (int j = 0; j < 5; j++)
{
if (j >= 2)
{
double cosine = fabs(angle(approx[j % 4], approx[j - 2], approx[j - 1]));
maxCosine = MAX(maxCosine, cosine);
}
}
//std::cout << maxCosine << " ";
if (maxCosine < 0.1)
{
double sh = (d[1] / d[0]);
if (sh> 0.8&&sh<1.2)
{
for (int i = 0; i<4; i++)
zhengfang.push_back(cv::Point(approx[i].x, approx[i].y));
}
else
{
for (int i = 0; i<4; i++)
changfang.push_back(cv::Point(approx[i].x, approx[i].y));
}
}
else
{
for (int i = 0; i<4; i++)
squares.push_back(cv::Point(approx[i].x, approx[i].y));
}
}
}
for (size_t i = 0; i < squares.size(); i += 4)
{
cv::Point center;
center.x = (squares[i].x + squares[i + 2].x) / 2;
center.y = (squares[i].y + squares[i + 2].y) / 2;
line(dstImg, squares[i], squares[i + 1], cv::Scalar(0, 0, 255), 4);
line(dstImg, squares[i + 1], squares[i + 2], cv::Scalar(0, 0, 255), 4);
line(dstImg, squares[i + 2], squares[i + 3], cv::Scalar(0, 0, 255), 4);
line(dstImg, squares[i + 3], squares[i], cv::Scalar(0, 0, 255), 4);
std::cout << "菱形中心" << (i+4)/4 << center << std::endl;
circle(dstImg, center, 3, cv::Scalar(0, 0, 255), -1);
}
for (size_t i = 0; i < changfang.size(); i += 4)
{
cv::Point center;
center.x = (changfang[i].x + changfang[i + 2].x) / 2;
center.y = (changfang[i].y + changfang[i + 2].y) / 2;
line(dstImg, changfang[i], changfang[i + 1], cv::Scalar(0, 0, 80), 4);
line(dstImg, changfang[i + 1], changfang[i + 2], cv::Scalar(0, 0, 80), 4);
line(dstImg, changfang[i + 2], changfang[i + 3], cv::Scalar(0, 0, 80), 4);
line(dstImg, changfang[i + 3], changfang[i], cv::Scalar(0, 0, 80), 4);
std::cout << "長方形中心" << (i + 4) / 4 << center << std::endl;
circle(dstImg, center, 3, cv::Scalar(0, 0, 80), -1);
}
for (size_t i = 0; i < zhengfang.size(); i += 4)
{
cv::Point center;
center.x = (zhengfang[i].x + zhengfang[i + 2].x) / 2;
center.y = (zhengfang[i].y + zhengfang[i + 2].y) / 2;
line(dstImg, zhengfang[i], zhengfang[i + 1], cv::Scalar(111, 0, 111), 4);
line(dstImg, zhengfang[i + 1], zhengfang[i + 2], cv::Scalar(111, 0, 111), 4);
line(dstImg, zhengfang[i + 2], zhengfang[i + 3], cv::Scalar(111, 0, 111), 4);
line(dstImg, zhengfang[i + 3], zhengfang[i], cv::Scalar(111, 0, 111), 4);
std::cout << "正方形中心" << (i + 4) / 4 << center << std::endl;
circle(dstImg, center, 3, cv::Scalar(111, 0,111), -1);
}
//畫三角形
for (size_t i = 0; i < contours.size(); i++)
{
approxPolyDP(contours[i], approx, arcLength(cv::Mat(contours[i]), true)*0.1, true);
if (approx.size() == 3 && fabs(contourArea(cv::Mat(approx))) > 1000 && isContourConvex(cv::Mat(approx)))//3條邊;面積大於1000;凸多邊形
{
double minDist = 1e10;
for (int i = 0; i < 3; i++)//求最小邊
{
cv::Point side = approx[i] - approx[(i + 1) %3];
double squaredSideLength = side.dot(side);
minDist = std::min(minDist, squaredSideLength);
}
if (minDist<1000)
continue;
for (int i = 0; i<3; i++)
sanjiao.push_back(cv::Point(approx[i].x, approx[i].y));
drawContours(dstImg, contours, i, cv::Scalar(255, 0, 0), 3);
}
}
for (size_t i = 0; i < sanjiao.size(); i += 3)
{
cv::Point center;
center.x = (sanjiao[i].x + sanjiao[i + 1].x + sanjiao[i + 2].x) / 3;
center.y = (sanjiao[i].y + sanjiao[i + 1].y + sanjiao[i + 2].y) / 3;
std::cout << "三角形中心" << (i + 1) % 3 << center << std::endl;
circle(dstImg, center, 3, cv::Scalar(255, 0, 0), -1);
}
//畫五邊形
for (size_t i = 0; i < contours.size(); i++)
{
approxPolyDP(contours[i], approx, arcLength(cv::Mat(contours[i]), true)*0.03, true);
if (approx.size() == 5 && fabs(contourArea(cv::Mat(approx))) > 1000 && isContourConvex(cv::Mat(approx)))//5條邊;面積大於1000;凸多邊形
{
double minDist = 1e10;
//std::cout << approx;
for (int i = 0; i < 5; i++)//求最小邊
{
cv::Point side = approx[i] - approx[(i + 1) % 3];
double squaredSideLength = side.dot(side);
minDist = std::min(minDist, squaredSideLength);
}
if (minDist<1000)
continue;
for (int i = 0; i<5; i++)
wubian.push_back(cv::Point(approx[i].x, approx[i].y));
}
}
for (size_t i = 0; i < wubian.size(); i += 5)
{
cv::Point center,center1,center2,center3;
center1.x = (wubian[i].x + wubian[i + 1].x + wubian[i + 4].x) / 3;
center1.y = (wubian[i].y + wubian[i + 1].y + wubian[i + 4].y) / 3;
center2.x = (wubian[i+1].x + wubian[i + 2].x + wubian[i + 3].x) / 3;
center2.y = (wubian[i+1].y + wubian[i + 2].y + wubian[i + 3].y) / 3;
center3.x = (wubian[i+3].x + wubian[i + 1].x + wubian[i + 4].x) / 3;
center3.y = (wubian[i+3].y + wubian[i + 1].y + wubian[i + 4].y) / 3;
center.x = (center1.x + center2.x + center3.x) / 3;
center.y = (center1.y + center2.y + center3.y) / 3;
line(dstImg, wubian[i], wubian[i + 1], cv::Scalar(255, 255, 0), 4);
line(dstImg, wubian[i+2], wubian[i + 1], cv::Scalar(255, 255, 0), 4);
line(dstImg, wubian[i+2], wubian[i + 3], cv::Scalar(255, 255, 0), 4);
line(dstImg, wubian[i+3], wubian[i + 4], cv::Scalar(255, 255, 0), 4);
line(dstImg, wubian[i], wubian[i +4], cv::Scalar(255, 255, 0), 4);
std::cout << "五邊形中心" << (i + 1) % 5 << center << std::endl;
circle(dstImg, center, 3, cv::Scalar(255, 255, 0), -1);
}
//畫五角星
for (size_t i = 0; i < contours.size(); i++)
{
approxPolyDP(contours[i], approx, arcLength(cv::Mat(contours[i]), true)*0.02, true);
if (approx.size() == 10 && fabs(contourArea(cv::Mat(approx))) > 1000 )//10條邊;面積大於1000;凹多邊形
{
if (isContourConvex(cv::Mat(approx)))
continue;
double minDist = 1e10;
for (int i = 0; i <10; i++)//求最小邊
{
cv::Point side = approx[i] - approx[(i + 1) % 10];
double squaredSideLength = side.dot(side);
minDist = std::min(minDist, squaredSideLength);
}
if (minDist<1000)
continue;
for (int i = 0; i<10; i++)
wujiao.push_back(cv::Point(approx[i].x, approx[i].y));
}
}
for (size_t i = 0; i < wujiao.size(); i += 10)
{
cv::Point center;
double y1, y2, x1,x2,y3,y4,x3,x4;
y1 = wujiao[i].y;
y2 = wujiao[i+5].y;
x1 = wujiao[i].x;
x2 = wujiao[i+5].x;
double k1, k2, b1, b2;
k1 = (y1 - y2) / (x1- x2);
b1 =y1 - k1*y1;
y3 = wujiao[i+1].y;
y4 = wujiao[i + 6].y;
x3 = wujiao[i+1].x;
x4 = wujiao[i + 6].x;
k2 = (y3 - y4) / (x3 - x4);
b2 = y3 - k2*x3;
center.x = (b1 - b2) / (k2 - k1);
center.y = k1*center.x + b1;
for (size_t j = 0; j < 10; j++)
{
line(dstImg, wujiao[j], wujiao[(j + 1) % 10], cv::Scalar(0,255, 255), 4);
}
std::cout << "五角形中心" << (i + 1) % 5 << center << std::endl;
circle(dstImg, center, 3, cv::Scalar(0, 255, 255), -1);
}
//畫十字形
for (size_t i = 0; i < contours.size(); i++)
{
approxPolyDP(contours[i], approx, arcLength(cv::Mat(contours[i]), true)*0.02, true);
if (approx.size() == 12 && fabs(contourArea(cv::Mat(approx))) > 1000 )//12條邊;面積大於1000;凹多邊形
{
if (isContourConvex(cv::Mat(approx)))
continue;
double minDist = 1e10;
for (int i = 0; i < 12; i++)//求最小邊
{
cv::Point side = approx[i] - approx[(i + 1) % 12];
double squaredSideLength = side.dot(side);
minDist = std::min(minDist, squaredSideLength);
}
if (minDist<1000)
continue;
for (int i = 0; i<12; i++)
shizi.push_back(cv::Point(approx[i].x, approx[i].y));
}
}
for (size_t i = 0; i < shizi.size(); i += 12)
{
cv::Point center;
center.x = (shizi[i].x+shizi[i+6].x) /2;
center.y = (shizi[i].y + shizi[i + 6].y) / 2;
for (size_t j = 0; j < 12; j++)
{
line(dstImg, shizi[j],shizi[(j + 1) % 12], cv::Scalar(122, 122, 0), 4);
}
std::cout << "十字形中心" << (i + 1) % 12 << center << std::endl;
circle(dstImg, center, 3, cv::Scalar(122, 122, 0), -1);
}
//畫梅花形
for (size_t i = 0; i < contours.size(); i++)
{
approxPolyDP(contours[i], approx, arcLength(cv::Mat(contours[i]), true)*0.01, true);
if (approx.size()>10 && fabs(contourArea(cv::Mat(approx))) > 1000)//12條邊;面積大於1000;凹多邊形
{
if (isContourConvex(cv::Mat(approx)))
continue;
double perimeter = arcLength(contours[i], true);
cv::Point center;
cv::Rect rect = boundingRect(contours[i]);
double r = (rect.width + rect.height) / 8;
double area = contourArea(contours[i]);
double pi = 3.1415926;
double areajisuan = 2 * pi*r*r + r*r * 4;
double perimeterji = 4 * pi*r;
double perimeterDiff = abs((perimeterji - perimeter) * 2 / (perimeter + perimeterji)) * 100;
double areaDiff = abs((area - areajisuan) * 2 / (area + areajisuan)) * 100;
//std::cout << areaDiff << std::endl;
//std::cout << " " << perimeterDiff << std::endl;
if (areaDiff < 8 && perimeterDiff<11)
{
//std::cout << areaDiff << std::endl;
//std::cout << "1 " << perimeterDiff << std::endl;
center.x = rect.x + 2 * r;
center.y = rect.y + 2 * r;
drawContours(dstImg, contours, i, cv::Scalar(0, 122, 122), 3);
std::cout << "梅花形中心" << ++j << center << std::endl;
circle(dstImg, center, 3, cv::Scalar(0, 122, 122), -1);
}
}
}
imshow("1",dstImg);
cv::waitKey(0);
return 0;
}