Yuk*_*awa 15 c++ opencv image-processing
我的目标是识别图像中存在的所有形状.这个想法是:
示例图片:

我用它fitEllipse()来找到轮廓最合适的椭圆,但结果有点乱:

可能正确的椭圆用蓝色填充,边界椭圆用黄色填充.可能不正确的轮廓用绿色填充,(错误的)边界椭圆是青色.
正如您所看到的,在第一行中限定三角形的椭圆看起来非常适合最佳拟合.第三行中三角形的边界椭圆似乎不是最合适的,但仍然可以作为拒绝不正确椭圆的标准.
但我无法理解为什么剩下的三角形在其轮廓之外完全具有边界椭圆.最坏的情况是最后一行中的第三个三角形:椭圆是完全错误的,但碰巧有一个区域靠近轮廓的区域,因此三角形被错误地识别为椭圆.
我想念什么吗?我的代码:
#include <iostream>
#include <opencv/cv.h>
#include <opencv/highgui.h>
using namespace std;
using namespace cv;
void getEllipses(vector<vector<Point> >& contours, vector<RotatedRect>& ellipses) {
ellipses.clear();
Mat img(Size(800,500), CV_8UC3);
for (unsigned i = 0; i<contours.size(); i++) {
if (contours[i].size() >= 5) {
RotatedRect temp = fitEllipse(Mat(contours[i]));
if (area(temp) <= 1.1 * contourArea(contours[i])) {
//cout << area(temp) << " < 1.1* " << contourArea(contours[i]) << endl;
ellipses.push_back(temp);
drawContours(img, contours, i, Scalar(255,0,0), -1, 8);
ellipse(img, temp, Scalar(0,255,255), 2, 8);
imshow("Ellipses", img);
waitKey();
} else {
//cout << "Reject ellipse " << i << endl;
drawContours(img, contours, i, Scalar(0,255,0), -1, 8);
ellipse(img, temp, Scalar(255,255,0), 2, 8);
imshow("Ellipses", img);
waitKey();
}
}
}
}
int main() {
Mat img = imread("image.png", CV_8UC1);
threshold(img, img, 127,255,CV_THRESH_BINARY);
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(img, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
vector<RotatedRect> ellipses;
getEllipses(contours, ellipses);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
Mic*_*cka 13
请记住,这fitEllipse不是边界椭圆的计算,而是假设点位于椭圆上的最小二乘优化.
我不能告诉你为什么它在最后一行的3个三角形上失败但是在上面一行的三角形上"起作用",但我看到的一件事是,最后一行中的所有3个三角形都适合于一个rotateRect用angle 0.可能最小的方形配件在那里失败了.
但我不知道openCV实现中是否存在错误,或者算法无法处理这些情况.使用此算法:http://www.bmva.org/bmvc/1995/bmvc-95-050.pdf
我的建议是,只有fitEllipse在你确定这些点真的属于椭圆时才使用.fitLine如果你有随机数据点,你不会假设得到合理的结果.您可能想要查看的其他功能是:minAreaRect和minEnclosingCircle
如果您使用RotatedRect temp = minAreaRect(Mat(contours[i]));而不是fitEllipse您将得到这样的图像:

也许你甚至可以使用这两种方法并拒绝在两个版本中都失败的所有省略号并接受两个版本中都接受的所有省略,但是在那些不同的版本中进一步调查?
如果您遇到问题cv::fitEllipse(),本文将讨论一些方法,以最大限度地减少在cv::RotatedRect没有任何进一步测试的情况下直接绘制时发生的错误.事实证明cv::fitEllipse()并不完美,可能会出现问题中提到的问题.
现在,还不完全清楚项目的约束是什么,但解决这个问题的另一种方法是根据轮廓的面积分离这些形状:

这种方法在这种特殊情况下非常简单而有效:圆形区域在1300-1699之间变化,三角形区域在1-1299之间变化.
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
int main()
{
cv::Mat img = cv::imread("input.png");
if (img.empty())
{
std::cout << "!!! Failed to open image" << std::endl;
return -1;
}
/* Convert to grayscale */
cv::Mat gray;
cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);
/* Convert to binary */
cv::Mat thres;
cv::threshold(gray, thres, 127, 255, cv::THRESH_BINARY);
/* Find contours */
std::vector<std::vector<cv::Point> > contours;
cv::findContours(thres, contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE);
int circles = 0;
int triangles = 0;
for (size_t i = 0; i < contours.size(); i++)
{
// Draw a contour based on the size of its area:
// - Area > 0 and < 1300 means it's a triangle;
// - Area >= 1300 and < 1700 means it's a circle;
double area = cv::contourArea(contours[i]);
if (area > 0 && area < 1300)
{
std::cout << "* Triangle #" << ++triangles << " area: " << area << std::endl;
cv::drawContours(img, contours, i, cv::Scalar(0, 255, 0), -1, 8); // filled (green)
cv::drawContours(img, contours, i, cv::Scalar(0, 0, 255), 2, 8); // outline (red)
}
else if (area >= 1300 && area < 1700)
{
std::cout << "* Circle #" << ++circles << " area: " << area << std::endl;
cv::drawContours(img, contours, i, cv::Scalar(255, 0, 0), -1, 8); // filled (blue)
cv::drawContours(img, contours, i, cv::Scalar(0, 0, 255), 2, 8); // outline (red)
}
else
{
std::cout << "* Ignoring area: " << area << std::endl;
continue;
}
cv::imshow("OBJ", img);
cv::waitKey(0);
}
cv::imwrite("output.png", img);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
您可以调用其他函数来绘制更精确的形状轮廓(边框).
| 归档时间: |
|
| 查看次数: |
15329 次 |
| 最近记录: |