【问题标题】:OpenCV speed traffic sign detectionOpenCV 速度交通标志检测
【发布时间】:2015-12-24 03:58:00
【问题描述】:

我在使用适用于 Android 的 opencv 2.4 检测速度交通标志时遇到问题。 我执行以下操作:

“捕获帧 -> 将其转换为 HSV -> 提取红色区域 -> 使用椭圆检测检测标志”

到目前为止,只要图片质量好,椭圆检测就可以完美运行。 但是正如你在下面的图片中看到的那样,我认为红色提取不起作用,因为相框质量差。

将原始图像转换为 HSV:

Imgproc.cvtColor(this.source, this.source, Imgproc.COLOR_RGB2HSV, 3);

提取红色:

Core.inRange(this.source, new Scalar(this.h,this.s,this.v), new Scalar(230,180,180), this.source);

所以我的问题是有没有另一种方法可以检测这样的交通标志或从中提取红色区域,顺便说一下,这些区域可能像上一张图​​片一样非常微弱?强>

这是原图:

这将转换为 HSV,因为您可以看到红色区域看起来与附近的树木颜色相同。这就是我想知道它是红色的,但我不能。

转换为 HSV:

这是提取的红色。如果颜色正确,我应该在标志周围得到几乎完美的圆形/椭圆,但由于颜色错误,它是不完整的。

提取后的结果:

椭圆法:

private void findEllipses(Mat input){
Mat thresholdOutput = new Mat();
int thresh = 150;

List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
MatOfInt4 hierarchy = new MatOfInt4();

Imgproc.threshold(source, thresholdOutput, thresh, 255, Imgproc.THRESH_BINARY);
//Imgproc.Canny(source, thresholdOutput, 50, 180);
Imgproc.findContours(source, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
RotatedRect minEllipse[] = new RotatedRect[contours.size()];

for(int i=0; i<contours.size();i++){
    MatOfPoint2f temp=new MatOfPoint2f(contours.get(i).toArray());

    if(temp.size().height > minEllipseSize && temp.size().height < maxEllipseSize){
        double a = Imgproc.fitEllipse(temp).size.height;
        double b = Imgproc.fitEllipse(temp).size.width;
        if(Math.abs(a - b) < 10)
            minEllipse[i] = Imgproc.fitEllipse(temp);
    }
}
detectedObjects.clear();
for( int i = 0; i< contours.size(); i++ ){
    Scalar color = new Scalar(180, 255, 180);
    if(minEllipse[i] != null){
        detectedObjects.add(new DetectedObject(minEllipse[i].center));
        DetectedObject detectedObj = new DetectedObject(minEllipse[i].center);
        Core.ellipse(source, minEllipse[i], color, 2, 8);
    }
}

}

有问题的迹象:

【问题讨论】:

  • 你也可以上传原始(RGB)图像吗?
  • 抱歉,我之前只能发布 2 个链接
  • 有原图
  • 谢谢。顺便说一句,将 HSV 图像渲染为 BGR 图像可能不是一个直观的提示。在 tje hsv 图像中看到绿色只是意味着 S 通道占主导地位。由于 H 通道的范围较小,因此可能没有任何意义。请尝试对 H 通道设置阈值并尝试不同的范围。

标签: android opencv detection traffic hsv


【解决方案1】:

您可以查看交通标志检测方法herehere的评论。

您会发现有两种方法可以实现这一目标:

  1. 基于颜色(就像您现在所做的那样)
  2. 基于形状

根据我的经验,我发现基于形状的方法效果很好,因为在不同的光照条件、相机质量等情况下颜色可能会发生很大变化。

由于您需要检测 speed 交通标志(我假设它们始终是圆形的),您可以使用椭圆检测器来查找图像中的所有圆形物体,然后应用一些验证来确定它是否是交通标志与否。

为什么要进行椭圆检测?

好吧,既然您正在寻找透视扭曲的圆圈,那么您实际上是在寻找椭圆。实时椭圆检测是一个有趣(尽管有限)的研究课题。我将向您指出 2 篇具有可用 C++ 源代码的论文(您可以通过本机 JNI 调用在您的应用程序中使用):

  1. L. Libuda,I. Grothues,K.-F。 Kraiss,数字图像中的椭圆检测 使用几何特征的数据,在:J. Braz、A. Ranchordas、H. Arajo、 J. Jorge (Eds.),计算机图形学和计算机视觉的进展, 计算机和信息科学通信第 4 卷, 施普林格柏林海德堡,2007 年,第 229-239 页。 link, code

  2. M. Fornaciari, A. Prati, R. Cucchiara, “用于嵌入式视觉应用的快速有效的椭圆检测器”,模式识别,2014 link, code


更新

我尝试了方法 2) 没有任何预处理。可以看到,至少红色边框的标志被检测的很好:

【讨论】:

  • 我明白你的意思,但我已经有椭圆检测,它本身不起作用,因为周围有太多其他东西。它通常检测除交通标志以外的任何东西。这就是为什么我想隔离“红色”交通标志,然后用椭圆检测它们。
  • 导致颜色看起来不够不同的相同问题导致椭圆检测无效。
  • 此外,我还需要基于颜色的检测,因为圆形交通标志只是一个开始......
  • @skyhawk 只是出于好奇,您使用了哪种椭圆检测方法?我提到的那些都很好用。另外,作为个人意见,我认为基于颜色的方法在实践中行不通。
  • 你能告诉我,cpp中的这些函数在JNI中是如何使用的吗?
【解决方案2】:

参考你的文字:

这被转换为 HSV,因为您可以看到红色区域看起来相同的颜色 作为附近的树木。这就是我想知道它是红色的,但我不能。

我想向你展示我所做的基本上你所做的结果(简单的操作应该很容易转移到android openCV):

    // convert to HSV
    cv::Mat hsv;
    cv::cvtColor(input,hsv,CV_BGR2HSV);

    std::vector<cv::Mat> channels;
    cv::split(hsv,channels);

    // opencv = hue values are divided by 2 to fit 8 bit range
    float red1 = 25/2.0f;
    // red has one part at the beginning and one part at the end of the range (I assume 0° to 25° and 335° to 360°)
    float red2 = (360-25)/2.0f;

    // compute both thresholds
    cv::Mat thres1 = channels[0] < red1;
    cv::Mat thres2 = channels[0] > red2;

    // choose some minimum saturation
    cv::Mat saturationThres = channels[1] > 50;

    // combine the results
    cv::Mat redMask = (thres1 | thres2) & saturationThres;

    // display result
    cv::imshow("red", redMask);

这些是我的结果:

根据您的结果,请注意findContours 会更改输入图像,因此如果您在 findContours 之后保存了图像,可能您提取了椭圆但在图像中看不到它。

【讨论】:

  • 我会像你一样尝试它,但将其转换为 Java。但只是为了让你知道,我前段时间在 OpenCV 和 OpenCV for Android 中尝试了相同的方法,而用于 android 的方法给了我更糟糕的结果。
  • android openCV 中 HUE 值的范围是多少?是0..180 还是0..360
  • HUE 值从 0 - 179 到 255
  • 不知道 c++ 和 android 之间可能有什么不同
  • 有一些,我被警告过,虽然我还没有真正找到它们。不管怎样,等我下班回家我会再试一次。
【解决方案3】:
private void findEllipses(Mat input){
    Mat thresholdOutput = new Mat();
    int thresh = 150;

    List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
    MatOfInt4 hierarchy = new MatOfInt4();

    Imgproc.threshold(source, thresholdOutput, thresh, 255, Imgproc.THRESH_BINARY);
    //Imgproc.Canny(source, thresholdOutput, 50, 180);
    Imgproc.findContours(source, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
//      source = thresholdOutput;
    RotatedRect minEllipse[] = new RotatedRect[contours.size()];

    for(int i=0; i<contours.size();i++){
        MatOfPoint2f temp=new MatOfPoint2f(contours.get(i).toArray());

        if(temp.size().height > minEllipseSize && temp.size().height < maxEllipseSize){
            double a = Imgproc.fitEllipse(temp).size.height;
            double b = Imgproc.fitEllipse(temp).size.width;
            if(Math.abs(a - b) < 10)
                minEllipse[i] = Imgproc.fitEllipse(temp);
        }
    }

    detectedObjects.clear();
    for( int i = 0; i< contours.size(); i++ ){
        Scalar color = new Scalar(180, 255, 180);
        if(minEllipse[i] != null){
            detectedObjects.add(new DetectedObject(minEllipse[i].center));
            DetectedObject detectedObj = new DetectedObject(minEllipse[i].center);
            Core.ellipse(source, minEllipse[i], color, 2, 8);
        }
    }
}

【讨论】:

  • 这实际上是一种检测椭圆的非常糟糕的方法。毫不奇怪,这在现实世界的图像中不起作用。尝试我提到的一种方法,它们会更好地工作。另外,删除此答案并将代码编辑到问题中。
【解决方案4】:

您是否尝试过使用 opencv ORB?它工作得很好。 我为交通标志(在我的情况下为环形交叉路口)创建了一个 haar 级联,并使用 opencv ORB 来匹配特征并删除任何误报。 对于图像识别,使用了 Google 的 tensorflow,结果非常出色。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-01-17
    • 2019-10-11
    • 2019-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-28
    相关资源
    最近更新 更多