C++ 确定阈值参数的正确方法

C++ 确定阈值参数的正确方法,c++,opencv,C++,Opencv,我正在尝试实时查找三角形(蓝色轮廓)和梯形(黄色轮廓)。总的来说没关系 但也存在一些问题。首先是误报。三角形变成梯形,反之亦然。我不知道如何解决这个问题。 其次是“噪音”。我试图检查图形的面积,但噪音可以等于面积。因此,这没有多大帮助。噪声取决于阈值参数cv::adaptiveThreshold根本没有帮助。它增加了更多的噪音(而且速度很慢)侵蚀和扩张无法以适当的方式修复它 这是我的密码 cv::Mat detect(cv::Mat imageRGB) { //RGB -> GRA

我正在尝试实时查找三角形(蓝色轮廓)和梯形(黄色轮廓)。总的来说没关系
但也存在一些问题。首先是误报。三角形变成梯形,反之亦然。我不知道如何解决这个问题。 其次是“噪音”。我试图检查图形的面积,但噪音可以等于面积。因此,这没有多大帮助。噪声取决于阈值参数<代码>cv::adaptiveThreshold根本没有帮助。它增加了更多的噪音(而且速度很慢)
侵蚀
扩张
无法以适当的方式修复它

这是我的密码

cv::Mat detect(cv::Mat imageRGB)
{
    //RGB -> GRAY
    cv::Mat imageGray;
    cv::cvtColor(imageRGB, imageGray, CV_BGR2GRAY);
    //Bluring it
    cv::Mat image;
    cv::GaussianBlur(imageGray, image, cv::Size(5,5), 2);
    //Thresholding
    cv::threshold(image, image, 100, 255, CV_THRESH_BINARY_INV);

    //SLOW and NOISE
    //cv::adaptiveThreshold(image, image, 255.0, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 21, 0);

    //Calculating canny params.
    cv::Scalar mu;
    cv::Scalar sigma;
    cv::meanStdDev(image, mu, sigma);

    cv::Mat imageCanny;

    cv::Canny(image,
              imageCanny,
              mu.val[0] + sigma.val[0],
              mu.val[0] - sigma.val[0]);

    //Detecting conturs.
    std::vector<std::vector<cv::Point> > contours;
    std::vector<cv::Vec4i> hierarchy;
    cv::findContours(imageCanny, contours, hierarchy,CV_RETR_TREE, CV_CHAIN_APPROX_NONE);

    //Hierarchy is not needed here so clear it.
    hierarchy.clear();

    for (std::size_t i = 0; i < contours.size(); i++)
    {
        //fitEllipse need at last 5 points.
        if (contours.at(i).size() < 5)
        {
            continue;
        }
        //Skip small contours.
        if (std::fabs(cv::contourArea(contours.at(i))) < 800.0)
        {
            continue;
        }
        //Calculating RotatedRect from contours NOT from hull
        //because fitEllipse need at last 5 points.

        cv::RotatedRect bEllipse = cv::fitEllipse(contours.at(i));

        //Finds the convex hull of a point set.
        std::vector<cv::Point> hull;
        cv::convexHull(contours.at(i), hull, true);
        //Approx it, so we'll get 3 point for triangles
        //and 4 points for trapez.
        cv::approxPolyDP(hull, hull, 15, true);
        //Is our contour convex. It's mast be.
        if (!cv::isContourConvex(hull))
        {
            continue;
        }
        //Triangle
        if (hull.size() == 3)
        {
            cv::drawContours(imageRGB, contours, i, cv::Scalar(255, 0, 0), 2);
            cv::circle(imageRGB, bEllipse.center, 3, cv::Scalar(0, 255, 0), 2);
        }
        //trapez
        if (hull.size() == 4)
        {
            cv::drawContours(imageRGB, contours, i, cv::Scalar(0, 255, 255), 2);
            cv::circle(imageRGB, bEllipse.center, 3, cv::Scalar(0, 0, 255), 2);
        }
    }
    return imageRGB;
}
cv::Mat检测(cv::Mat imageRGB)
{
//RGB->灰色
cv::灰色;
cv::CVT颜色(imageRGB、imageGray、cv_BGR2GRAY);
//模糊它
cv::Mat图像;
cv::高斯模糊(图像灰度,图像,cv::大小(5,5),2);
//阈值
cv::阈值(图像,图像,100255,cv\u阈值\u二进制\u INV);
//慢而嘈杂
//cv::adaptiveThreshold(图像,图像,255.0,cv_ADAPTIVE_THRESH_GAUSSIAN_C,cv_THRESH_BINARY,21,0);
//计算精明的参数。
cv::标量μ;
标量西格玛;
cv::meanStdDev(图像、mu、sigma);
cv::Mat imageCanny;
cv::Canny(图片,
伊格坎尼,
μval[0]+σval[0],
μval[0]-sigma.val[0]);
//检测接触。
矢量轮廓;
向量层次;
cv::findContours(图像扫描、轮廓、层次、cv树、cv链、近似无);
//这里不需要层次结构,所以要清楚。
hierarchy.clear();
对于(std::size_t i=0;i

所以。。。一般来说,所有问题都是由错误的阈值参数引起的,我如何才能以正确的方式(当然是自动地)计算它?我怎样才能(哈哈,对不起我的英语)防止误报呢?

我想你应该试试大津的二值化——这是一个理论,一幅很好的图片,也是一个文档。这种阈值化通常是试图在图像中找到两个最常见的值,并使用它们的平均值作为阈值

P>可选地考虑使用HSV颜色空间,可以更容易地区分黑白区域与其他区域。另一个想法是使用inRange函数(在RGB或HSV颜色空间中-应在woth情况下工作)-您需要找到两个范围(一个来自黑色区域,一个用于白色),并仅搜索这些区域(使用inRange函数)-查看

完成此任务的另一种方法可能是使用某个库进行blob提取,或者是OpenCV的一部分

区分三角形和梯形-我在这里看到了两种改进解决方案的基本方法:

  • 在这行
    cv::approxPolyDP(hull,hull,15,true)使第三个参数(在这种情况下为15)不是一个常量值,而是轮廓区域或长度的一部分。当然,它应该适应轮廓大小,它不能只是一个canstant值。如果不进行测试,很难说如何计算它——试着从轮廓面积或长度的1-5%开始(我会从长度开始,但这只是我的猜测),看看这个值是否合适/到大/到小,如果需要,检查其他值。不幸的是,没有其他方法,但是手动找到这个方程不需要很长时间
  • 当您有4或5个点时,计算连接连续点的直线方程(点1与点2,点2与点3,等等,不要忘记计算第一点和最后一点之间的直线),然后检查这些直线中的任何两条是否平行(或至少接近平行-它们之间的角度接近0度)-如果发现任何平行线,则该轮廓为梯形,否则为三角形

非常感谢您的建议。我以前试过大津,但还是有一些噪音。这里的HSV是不可接受的,因为三角形可以是蓝色的白色,黑色的白色,白色的蓝色等等(对不起,这是我的错误,我忘了说)。另外,我已经试着找到平行线,计算角度(三角形180,梯形360),比较边。在相同的参数下可能存在噪声。(Idk它是如何可能的:()。那么…你能给我一些关于如何计算approxPolyDP的参数的更多信息吗?(15是最好的)。再次感谢你。请参阅编辑后的答案。“另外,我已经试着找到平行线,计算角度(三角形为180,梯形为360),比较两侧。参数相同时可能存在噪声。(Idk ho)