2

我正在一个小型的OpenCV项目从手机摄像头检测到某种颜色的线条。OpenCV:如何检测特定颜色的线条?

总之想:

  1. 变换所述输入图像划分为特定颜色的一个图像(例如红色从一个特定的上限和下限范围)
  2. 应用霍夫线变换到所得到的图像,从而它检测出特定的颜色
  3. 叠加在原始图像上线检测的只有线

这些都是我想使用的功能,但不是曲iet确定如何填补缺失的位。

这是从CvVideoCamera的实例来处理图像时,从智能电话应用称为processImage来函数

- (void)processImage:(Mat&)image; 
{ 
cv::Mat orig_image = image.clone(); 

cv::Mat red_image = ?? 

// Apply houghes transformation to detect lines between a minimum length and a maximum length (I was thinking of using the CV_HOUGH_PROBABILISTIC method..) 
// Comment.. see below.. 

我无法理解documentation here作为C++ 方法签名没有方法字段

vector<Vec2f> lines; 

从官方文件:

C++:空隙HoughLines(InputArray图像,OutputArray线,双RHO,双THETA,INT阈值时,双SRN = 0,双STN = 0)

HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0); 

从示例代码两者,都没有正确的理解它是如何工作..

(例如theta的用法是什么?确实给人一种不同的角度 如何反映到在线检测?)

for(size_t i = 0; i < lines.size(); i++) 
{ 

在这里,我应该只考虑具有一定规模的线。(不知道如何)

} 

在这里,我应该然后将结果行添加到原始图像(不知道如何),以便它们可以显示在屏幕上..

任何帮助将不胜感激。

+0

要获取线条的大小,请使用概率霍夫变换。只有超过一定长度的线才会被它检测到。 – FadedCoder

+0

你可以发布(几个)图片吗?解释起来会更容易和更清晰。 – Miki

+0

您的“红色图像”的问题是您无法找到该功能,因为您自己不了解该任务。 “红色”可能不是一个单一的RGB值,而是许多相关的颜色。您想删除所有其他色调并将其替换为黑色。 – MSalters

回答

5

您可以使用HSV色彩空间来提取色调信息。

下面是一些代码有意见,如果有任何问题随时问:

int main(int argc, char* argv[]) 
{ 
    cv::Mat input = cv::imread("C:/StackOverflow/Input/coloredLines.png"); 

    // convert to HSV color space 
    cv::Mat hsvImage; 
    cv::cvtColor(input, hsvImage, CV_BGR2HSV); 

    // split the channels 
    std::vector<cv::Mat> hsvChannels; 
    cv::split(hsvImage, hsvChannels); 

    // hue channels tells you the color tone, if saturation and value aren't too low. 

    // red color is a special case, because the hue space is circular and red is exactly at the beginning/end of the circle. 
    // in literature, hue space goes from 0 to 360 degrees, but OpenCV rescales the range to 0 up to 180, because 360 does not fit in a single byte. Alternatively there is another mode where 0..360 is rescaled to 0..255 but this isn't as common. 
    int hueValue = 0; // red color 
    int hueRange = 15; // how much difference from the desired color we want to include to the result If you increase this value, for example a red color would detect some orange values, too. 

    int minSaturation = 50; // I'm not sure which value is good here... 
    int minValue = 50; // not sure whether 50 is a good min value here... 

    cv::Mat hueImage = hsvChannels[0]; // [hue, saturation, value] 

    // is the color within the lower hue range? 
    cv::Mat hueMask; 
    cv::inRange(hueImage, hueValue - hueRange, hueValue + hueRange, hueMask); 

    // if the desired color is near the border of the hue space, check the other side too: 
    // TODO: this won't work if "hueValue + hueRange > 180" - maybe use two different if-cases instead... with int lowerHueValue = hueValue - 180 
    if (hueValue - hueRange < 0 || hueValue + hueRange > 180) 
    { 
     cv::Mat hueMaskUpper; 
     int upperHueValue = hueValue + 180; // in reality this would be + 360 instead 
     cv::inRange(hueImage, upperHueValue - hueRange, upperHueValue + hueRange, hueMaskUpper); 

     // add this mask to the other one 
     hueMask = hueMask | hueMaskUpper; 
    } 

    // now we have to filter out all the pixels where saturation and value do not fit the limits: 
    cv::Mat saturationMask = hsvChannels[1] > minSaturation; 
    cv::Mat valueMask = hsvChannels[2] > minValue; 

    hueMask = (hueMask & saturationMask) & valueMask; 

    cv::imshow("desired color", hueMask); 

    // now perform the line detection 
    std::vector<cv::Vec4i> lines; 
    cv::HoughLinesP(hueMask, lines, 1, CV_PI/360, 50, 50, 10); 

    // draw the result as big green lines: 
    for (unsigned int i = 0; i < lines.size(); ++i) 
    { 
     cv::line(input, cv::Point(lines[i][0], lines[i][1]), cv::Point(lines[i][2], lines[i][3]), cv::Scalar(0, 255, 0), 5); 
    } 


    cv::imwrite("C:/StackOverflow/Output/coloredLines_mask.png", hueMask); 
    cv::imwrite("C:/StackOverflow/Output/coloredLines_detection.png", input); 

    cv::imshow("input", input); 
    cv::waitKey(0); 
    return 0; 
} 

使用该输入图像:

enter image description here

将解压这个“红”的颜色(调整hueValuehueRange来检测不同的颜色):

enter image description here

和HoughLinesP检测从面罩这些行(应与HoughLines与此类似):

enter image description here

这里的另一组与非线太图像...

enter image description here

enter image description here

enter image description here

关于您不同的问题:

  1. 有两个函数HoughLines和HoughLinesP。 HoughLines不提取线条长度,但可以在后期处理中通过再次检查边缘蒙版(HoughLines输入)的哪些像素对应于提取的线条来计算它。

  2. 参数:

    图像 - 边缘图像(应该清楚?) 线 - 通过角度和位置,没有长度或某物给定线。它们被无限地解释为 rho - 累加器分辨率。如果线条稍微有些扭曲,则线条越粗糙,但提取的线条的位置/角度的准确性越低 - 阈值越小,误报越少,但您可能会错过某些线条 - 角度分辨率:可以检测到更小,更多不同的线(取决于方向)。如果您的线的方向不符合角度步骤,则线可能不会被检测到。例如,如果CV_PI/180将在分辨率中检测到,如果您的线路有0.5°(例如33.5°),则可能会错过。

我不是那么非常肯定的所有参数,也许你会来看看有关霍夫线检测的文献,或其他人可以在这里添加一些提示。

如果改用cv::HoughLinesP,有开始和结束点线段将被检测到,这很容易解释,你可以从cv::norm(cv::Point(lines[i][0], lines[i][1]) - cv::Point(lines[i][2], lines[i][3]))

+0

谢谢!我现在要试试你的代码..我怎样才能在相机上显示图像?我正在使用“ - (void)processImage:(Mat&)图像”函数来处理输入帧图像..想要将检测到的图像叠加到它上面。 – mm24

+0

只需将我的代码中的'input'重命名为'orig_image',并确保'orig_image'为BGR格式。 – Micka

+0

我已经添加了一些关于参数 – Micka

1

计算行的长度我将不会显示的代码,但步骤与一些技巧。

假设您想要检测道路车道(即具有白色或淡黄色线条并具有某些特定属性的线路)。

原始图像(I添加一些额外的行,以使噪声)

enter image description here

步骤1:删除,并非需要使用图像的部分,保存CPU使用率(简单但有用)

enter image description here

步骤2:转换为灰度图像

enter image description here

第3步:门槛

使用根据你的线条的颜色阈值时,颜色就会变成白色和其他人将变成黑色

enter image description here

第4步:使用轮廓找到对象的边界

enter image description here

步骤5:用轮廓在以前的步骤中使用Fitline被输入到返回管线的方程

Fitline返回(X0,Y0)和矢量v =(A,B)

enter image description here

步骤6:用线的公式,你可以在任何线画出你想要

enter image description here