C++ OpenCV:如何检测特定颜色的线条?

C++ OpenCV:如何检测特定颜色的线条?,c++,opencv,feature-extraction,hough-transform,color-detection,C++,Opencv,Feature Extraction,Hough Transform,Color Detection,我正在进行一个小型OpenCV项目,以检测手机摄像头中特定颜色的线条 简言之,我想: 将输入图像转换为特定颜色的图像(例如,特定上下范围的红色) 对生成的图像应用Hough线变换,使其仅检测该特定颜色的线 将检测到的线条叠加在原始图像上 这些是我想使用的函数,但不确定如何填充缺少的部分 这是在处理来自CvVideoCamera实例的图像时,从智能手机应用程序调用的processImage函数 我无法理解C++的含义。 方法签名没有方法字段 取自示例代码,尚未正确理解其工作原理 (例如,θ的用法是

我正在进行一个小型OpenCV项目,以检测手机摄像头中特定颜色的线条

简言之,我想:

  • 将输入图像转换为特定颜色的图像(例如,特定上下范围的红色)
  • 对生成的图像应用Hough线变换,使其仅检测该特定颜色的线
  • 将检测到的线条叠加在原始图像上
  • 这些是我想使用的函数,但不确定如何填充缺少的部分

    这是在处理来自CvVideoCamera实例的图像时,从智能手机应用程序调用的processImage函数

    我无法理解C++的含义。 方法签名没有方法字段

    取自示例代码,尚未正确理解其工作原理

    (例如,θ的用法是什么?如何给出不同的角度 反映到线路检测中?)

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


    非常感谢您的帮助。

    您可以使用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;
    }
    
    intmain(intargc,char*argv[])
    {
    cv::Mat input=cv::imread(“C:/StackOverflow/input/coloredLines.png”);
    //转换为HSV颜色空间
    cv::Mat hsvImage;
    cv::cvtColor(输入,hsvImage,cv_BGR2HSV);
    //分割频道
    std::矢量hsv信道;
    cv::分割(HSV图像、HSV通道);
    //如果饱和度和值不太低,色调通道会告诉您色调。
    //红色是一种特殊情况,因为色调空间是圆形的,而红色正好位于圆形的开始/结束处。
    //在文献中,色调空间从0到360度,但OpenCV将范围重新缩放到0到180度,因为360不适合单个字节。或者,还有另一种模式,其中0..360被重新缩放到0..255,但这并不常见。
    int hueValue=0;//红色
    int hueRange=15;//如果您增加此值,则结果与我们希望包含的所需颜色的差异有多大,例如,红色也会检测到一些橙色值。
    int minSaturation=50;//我不确定这里哪个值好。。。
    int minValue=50;//不确定50在这里是否是一个好的最小值。。。
    cv::Mat hueImage=hsv通道[0];//[色调、饱和度、值]
    //颜色是否在较低的色调范围内?
    cv::Mat hueMask;
    cv::在范围内(胡埃梅格、胡埃瓦卢-胡兰格、胡埃瓦卢+胡兰格、胡埃马斯克);
    //如果所需颜色接近色调空间的边界,请检查另一侧:
    //TODO:如果“hueValue+hueRange>180”,这将不起作用-可能使用两种不同的if情况……int lowerHueValue=hueValue-180
    如果(呼出值-呼出值<0 | |呼出值+呼出值>180)
    {
    cv::Mat hueMaskUpper;
    int upperHueValue=hueValue+180;//实际上,这将是+360
    cv::范围内(hueImage,upperHueValue-hueRange,upperHueValue+hueRange,Huemaskuper);
    //将此掩码添加到另一个掩码
    hueMask=hueMask | hueMaskUpper;
    }
    //现在,我们必须过滤掉饱和度和值不符合限制的所有像素:
    cv::Mat saturationMask=hsv通道[1]>minSaturation;
    cv::Mat valueMask=hsvChannel[2]>minValue;
    hueMask=(hueMask和饱和掩码)和值掩码;
    cv::imshow(“所需颜色”,hueMask);
    //现在执行测线
    std::矢量线;
    cv::HoughLinesP(hueMask,lines,1,cv_PI/360,50,50,10);
    //将结果绘制为大绿线:
    for(无符号整数i=0;i
    使用此输入图像:

    将提取此“红色”颜色(调整
    hueValue
    hueRange
    以检测不同的颜色):

    HoughLinesP从遮罩中检测这些线条(应与
    HoughLines
    类似):

    这是另一组非直线图像

    关于您的不同问题:

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

  • 参数:

    图像-边缘图像(是否清晰?) 线-由角度和位置给出的线,没有长度或其他。它们被解释为无限长 rho-累加器分辨率。尺寸越大,在出现轻微扭曲的直线时,其鲁棒性越强,但提取直线的位置/角度越不准确 阈值-越大,误报越少,但您可能会漏掉一些行 θ-角度分辨率:越小,可以检测到的不同线条越多(取决于方向)。如果直线的方向与角度步长不匹配,则可能无法检测到该直线。例如,如果您的
    CV_PI/180
    将以
    分辨率进行检测,则如果您的线路具有
    0.5°
    (例如
    33.5°
    )方向,则可能会遗漏

  • 我不是非常确定所有的参数,也许你需要看看关于hough线检测的文献,或者其他人可以在这里添加一些提示

    如果改用
    cv::HoughLinesP
    ,将检测到具有起点和终点的线段
    vector<Vec2f> lines;
    
    HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0 ); 
    
    for( size_t i = 0; i < lines.size(); i++ )
    {
    
    }
    
    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;
    }