2013-04-30 2 views
1

Я пытаюсь написать метод, который найдет правильные пороговые значения в пространстве HSV для объекта, расположенного в центре экрана. Эти значения используются для алгоритма отслеживания объектов. Я тестировал этот фрагмент кода с пороговыми значениями ручной кодировки, и он работает хорошо. Идея метода заключается в том, что он должен вычислять гистограммы для каждого из каналов, а затем возвращать 5-й и 95-й процентиль для каждого, которые будут использоваться в качестве пороговых значений. (Кредит: How to find RGB/HSV color parameters for color tracking?) Изображение передается картина объекта отслеживаться (который задается пользователем перед началом всего процесса Вот кодПоиск порогов HSV с помощью гистограмм с помощью OpenCV

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; 
} 

То, что я пытаюсь сделать, это сумма. количество записей в каждом ведре до тех пор, пока я не получу число, которое больше или равно пяти процентам и девяносто пять процентов от общего числа. К сожалению, числа, которые я получаю, никогда не близки к тем, которые я получаю, если я делаю пороговое значение вручную

+0

Как далеко ли я получить от фактически найти 5% и 95% от каждого канала? Если вы сделаете обрезание 0-100%, верните ли вы число, равное totalEntries? –

+0

i довольно далеко, и я не понимаю вторую часть вопроса, делая отсечки, эти значения должны давать i's 0 и 255 или 179 – Pat

ответ

3
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 ... 

гораздо более простое решение -. просто вычислить среднее & зОго отклонение для области Interes. t, т.е. содержит значение оттенка. Поскольку Hue является наиболее стабильным компонентом на изображении, значение насыщенности других компонентов & должно быть отброшено, поскольку они слишком сильно отличаются. Однако при необходимости вы можете вычислить среднее значение для них.

Image results of the algorithm

Смежные вопросы