【问题标题】:Finding HSV Thresholds Via Histograms with OpenCV使用 OpenCV 通过直方图查找 HSV 阈值
【发布时间】:2014-04-10 22:20:10
【问题描述】:

我正在尝试编写一种方法,该方法将在 HSV 空间中为放置在屏幕中心的对象找到适当的阈值。这些值用于对象跟踪算法。我已经用手动编码的阈值测试了那段代码,它运行良好。该方法背后的想法是,它应该计算每个通道的直方图,然后返回每个通道的第 5 个和第 95 个百分位数,以用作阈值。 (信用:How to find RGB/HSV color parameters for color tracking?)传递的图像是要跟踪的对象的图片(这是用户在整个过程开始之前设置的。这是代码

std::vector<cv::Scalar> HSV_Threshold_Determiner::Get_Threshold_Values(const cv::Mat& image)
{
    cv::Mat inputImage;
    cv::cvtColor(image, inputImage, CV_BGR2HSV);
    std::vector<cv::Mat> bgrPlanes;

    cv::split(inputImage, bgrPlanes);

    cv::Mat hHist, sHist, vHist;

    int hMax = 180, svMax = 256;

    float hRanges[] = { 0, (float)hMax };
    const float* hRange = { hRanges };
    float svRanges[] = { 0, (float)svMax };
    const float* svRange = { svRanges };
    //float sRanges[] = { 0, 256 };

    cv::calcHist(&bgrPlanes[0], 1, 0, cv::Mat(), hHist, 1, &hMax, &hRange);
    cv::calcHist(&bgrPlanes[1], 1, 0, cv::Mat(), sHist, 1, &svMax, &svRange);
    cv::calcHist(&bgrPlanes[2], 1, 0, cv::Mat(), vHist, 1, &svMax, &svRange);

    int totalEntries = image.cols * image.rows;
    int fiveCutoff = (int)(totalEntries * .05);
    int ninetyFiveCutoff = (int)(totalEntries * .95);

    float hTotal = 0, sTotal = 0, vTotal = 0;
    bool hMinFound = false, hMaxFound = false, sMinFound = false, sMaxFound = false,
        vMinFound = false, vMaxFound = false;

    cv::Scalar hThresholds;
    cv::Scalar sThresholds;
    cv::Scalar vThresholds;

    for(int i = 0; i < vHist.rows; ++i)
    {
        if(i < hHist.rows)
        {
            hTotal += hHist.at<float>(i, 0);

            if(hTotal >= fiveCutoff && !hMinFound)
            {
                hThresholds.val[0] = i;
                hMinFound = true;
            }
            else if(hTotal>= ninetyFiveCutoff && !hMaxFound)
            {
                hThresholds.val[1] = i;
                hMaxFound = true;
            }
        }

        sTotal += sHist.at<float>(i, 0);
        vTotal += vHist.at<float>(i, 0);

        if(sTotal >= fiveCutoff && !sMinFound)
        {
            sThresholds.val[0] = i;
            sMinFound = true;
        }
        else if(sTotal >= ninetyFiveCutoff && !sMaxFound)
        {
            sThresholds.val[1] = i;
            sMaxFound = true;
        }

        if(vTotal >= fiveCutoff && !vMinFound)
        {
            vThresholds.val[0] = i;
            vMinFound = true;
        }
        else if(vTotal >= ninetyFiveCutoff && !vMaxFound)
        {
            vThresholds.val[1] = i;
            vMaxFound = true;
        }


        if(vMaxFound && sMaxFound && hMaxFound)
        {
            break;
        }
    }

    std::vector<cv::Scalar> returnVect;
    returnVect.push_back(hThresholds);
    returnVect.push_back(sThresholds);
    returnVect.push_back(vThresholds);
    return returnVect;
}

我要做的是总结每个桶中的条目数,直到我得到一个大于或等于总数的百分之五和百分之九十五的数字。不幸的是,如果我手动进行阈值处理,我得到的数字永远不会接近我得到的数字。

【问题讨论】:

  • 我离实际找到每个频道的 5% 和 95% 有多远?如果你把截止值设为 0-100%,你会得到一个等于 totalEntries 的数字吗?
  • i 离得很远,我不明白问题的第二部分,使这些值的截止值应该产生 i 的 0 和 255 或 179

标签: c++ opencv image-processing


【解决方案1】:
Mat img =  ... // from camera or some other source

// STEP 1: learning phase
Mat hsv, imgThreshed, processed, denoised;
cv::GaussianBlur(img, denoised, cv::Size(5,5), 2, 2); // remove noise
cv::cvtColor(denoised, hsv, CV_BGR2HSV);

// lets say we picked manually a region of 100x100 px with the interested color/object using mouse
cv::Mat roi = hsv (cv::Range(mousex-50, mousey+50), cv::Range(mousex-50, mousey+50));

// must split all channels to get Hue only
std::vector<cv::Mat> hsvPlanes;
cv::split(roi, hsvPlanes);

// compute statistics for Hue value
cv::Scalar mean, stddev;
cv::meanStdDev(hsvPlanes[0], mean, stddev);

// ensure we get 95% of all valid Hue samples (statistics 3*sigma rule)
float minHue = mean[0] - stddev[0]*3;
float maxHue = mean[0] + stddev[0]*3;

// STEP 2: detection phase
cv::inRange(hsvPlanes[0], cv::Scalar(minHue), cv::Scalar(maxHue), imgThreshed);
imshow("thresholded", imgThreshed);

cv_erode(imgThreshed, processed, 5);  // minimizes noise
cv_dilate(processed, processed, 20);  // maximize left regions

imshow("final", processed);

//STEP 3: do some blob/contour detection on processed image & find maximum blob/region, etc ...

一个更简单的解决方案 - 只需计算均值和标准值。感兴趣区域的偏差,即包含色调值。 由于色调是图像中最稳定的成分,其他成分的饱和度和值应该被丢弃,因为它们变化太大。但是,如果需要,您仍然可以计算它们的平均值。

【讨论】:

  • 3-sigma 覆盖 99.7% 的样本!,2-sigma 覆盖 95% 的样本
猜你喜欢
  • 1970-01-01
  • 2016-02-03
  • 2019-12-19
  • 2012-08-25
  • 2017-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-27
相关资源
最近更新 更多