1来源
为了实现一个简单的demo 就是拍取了物体的照片之后确定一下其具体的分布。
本文采用的方式是canny算子+闭运算+最大轮廓+最小包围矩阵的方式求解的。下面是代码。
轮廓提取参考
2代码
#include <Eigen/Dense>
#include <iostream>
#include <string>
#include <boost/format.hpp>
#include <vector>
//opencv
#include <opencv2/core/eigen.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
//#include <opencv2/rgbd.hpp>
#include <opencv2/highgui/highgui.hpp>
#include<opencv2/calib3d/calib3d.hpp>
using namespace std;
using namespace cv;
using namespace Eigen;
float getDistance(Point2f pointO, Point2f pointA)
{
float distance;
distance = powf((pointO.x - pointA.x), 2) + powf((pointO.y - pointA.y), 2);
distance = sqrtf(distance);
return distance;
}
int main()
{
Mat image,image_edge,kernel,image_edge_close,image_copy;
vector<vector<Point>> contours;
image = imread("D:\\vs2019_wkplace\\2DPART\\image1.png");
//深拷贝
image.copyTo(image_copy);
//imshow("test", image);
cv::Canny(image, image_edge, 50, 400);
//imshow("test1", image_edge);
//闭运算 先膨胀后腐蚀,保证是对的
kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
cv::morphologyEx(image_edge, image_edge_close, cv::MORPH_CLOSE, kernel, Point(-1, -1), 2);
imshow("test1", image_edge_close);
//寻找轮廓
vector<Vec4i> hierarchy;
cv::findContours(image_edge_close, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_NONE);
double maxarea = -1;
int maxAreaIdx = -1;
for (int i = 0; i < contours.size(); i++)
{
double tmparea = contourArea(contours[i]);
if (tmparea > maxarea)
{
maxarea = tmparea;
maxAreaIdx = i;//记录最大轮廓的索引号
}
}
if (maxAreaIdx != -1) {
cv::drawContours(image, contours, maxAreaIdx, (0, 0, 255), 2, 8);
cv::imshow("轮廓", image);
//cv::imwrite("image_right.png", image);
}
vector<Point> c = contours[maxAreaIdx];
RotatedRect rect = minAreaRect(contours[maxAreaIdx]);
//rectangle(image, rect.boundingRect(), Scalar(200));
//求中心
Point2f P[4], center,CENTER;
center.x = 0;
center.y = 0;
rect.points(P);
for (int j = 0; j <= 3; j++)
{
line(image_copy, P[j], P[(j + 1) % 4], Scalar(0, 0, 255), 10);
center.x = center.x+P[j].x;
center.y = center.y+P[j].y;
cout << center << endl;
}
CENTER.y = center.y / 4;
CENTER.x = center.x / 4;
cout << CENTER << endl;
circle(image_copy, CENTER, 3, Scalar(0, 255, 0),-1);
//求x最小的点
vector<Point2f> P_regroup;
int min_idx = -1;
float min_x = 9999;
for (int i = 0; i <= 3; i++)
{
if (P[i].x <min_x)
{
min_x = P[i].x;
min_idx = i;
}
}
cout << "x 最小点为" << min_idx << endl;
for (int i = 0; i <4; i++)
{
//P_regroup[i] = P[(min_idx + i) % 4];
P_regroup.push_back(P[(min_idx + i) % 4]);
cout << P[(min_idx + i) % 4 ]<< endl;
}
//长短边测试保证短边是X 长边是Y
vector<Point2f> P_regroup2;
vector<float> it;
it.push_back(getDistance(P_regroup[0], P_regroup[1]));
it.push_back(getDistance(P_regroup[0], P_regroup[3]));
if (it[0]<it[1])
{
cout << "顶点在下一个点" << endl;
for (int i = 0; i < 4; i++)
{
P_regroup2.push_back(P_regroup[(i + 1) % 4]);
}
}
else
{
cout << "顶点就是这个点" << endl;
for (int i = 0; i < 4; i++)
{
P_regroup2.push_back(P_regroup[i]);
}
}
float x_length = getDistance(P_regroup2[3], P_regroup2[0]);
vector<float> x_direction = { (P_regroup2[3].x - P_regroup2[0].x)/ x_length,(P_regroup2[3].y - P_regroup2[0].y)/ x_length };
float y_length = getDistance(P_regroup2[1], P_regroup2[0]);
vector<float> y_direction = { (P_regroup2[1].x - P_regroup2[0].x)/ y_length,(P_regroup2[1].y - P_regroup2[0].y)/ y_length };
//画轴
cv::Point frontpt_x, frontpt_y;
frontpt_x.x = CENTER.x + x_direction[0] * 50;
frontpt_x.y = CENTER.y + x_direction[1] * 50;
frontpt_y.x = CENTER.x + y_direction[0] * 50;
frontpt_y.y = CENTER.y + y_direction[1] * 50;
line(image_copy, CENTER, frontpt_x, (0, 255, 255), 10, 1);
line(image_copy, CENTER, frontpt_y, (255, 255, 0), 10, 1);
cout << "width*height*channel" << image.rows << "," << image.cols << "," << image.channels() << endl;
imshow("image", image_copy);
waitKey(0);
}
效果: