OpenCV速度交通标志检测

时间:2015-09-26 12:15:37

标签: android opencv detection traffic hsv

我在使用opencv 2.4 for Android检测速度交通标志时遇到问题。 我做了以下事情:

"捕获帧 - >将其转换为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);

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

这是原始图片:

enter image description here

这会转换为HSV,因为您可以看到红色区域看起来与附近的树木颜色相同。多数民众赞成我怎么想知道它的红色但是我不能。

转换为HSV:

enter image description here

这是用红色提取的。如果颜色是正确的,我应该在符号周围得到几乎完美的圆/椭圆,但由于颜色不正确而不完整。

提取后的结果:

enter image description here

椭圆方法:

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

}

有问题的标志: enter image description here

4 个答案:

答案 0 :(得分:8)

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

你会发现有两种方法可以达到这个目的:

  1. 基于颜色(就像你现在正在做的那样)
  2. 基于形状的
  3. 根据我的经验,我发现基于形状的方法效果很好,因为在不同的光照条件,相机质量等下,颜色可能会发生很大变化。

    由于您需要检测速度交通标志,我认为这些交通标志始终是圆形的,您可以使用椭圆检测器查找图像中的所有圆形对象,然后应用一些验证来确定它是否是是否有交通标志。

    为什么要进行椭圆检测?

    好吧,既然你正在寻找透视扭曲的圆圈,你实际上在寻找椭圆。实时椭圆检测是一个有趣(虽然有限)的研究课题。我将向您发表2篇提供C ++源代码的论文(您可以通过本机JNI调用在您的app中使用):

    1. 升。 Libuda,I。Grothues,K.-F。 Kraiss,数字图像中的椭圆检测 使用几何特征的数据,在:J. Braz,A。Ranchordas,H。Arajo, J. Jorge(编辑),计算机图形学与计算机视觉进展, 计算机与信息科学通讯第4卷, Springer Berlin Heidelberg,2007,pp.229-239。 linkcode

    2. 微米。 Fornaciari,A。Prati,R。Cucchiara, “用于嵌入式视觉应用的快速有效的椭圆探测器”,模式识别,2014 linkcode

    3. <强>更新

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

      enter image description here

答案 1 :(得分:4)

参考您的文字:

  

这会转换为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);

这些是我的结果:

enter image description here

enter image description here

根据您的结果,请注意findContours改变输入图像,因此如果您在findContours之后保存图像,也许您已经提取了椭圆,但只是不再在图像中看到它。

答案 2 :(得分:1)

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

答案 3 :(得分:1)

你尝试过使用opencv ORB吗?它工作得很好。 我为交通标志(在我的情况下是环形交叉路口)创建了一个haar级联,并使用opencv ORB来匹配功能并删除任何误报。 对于图像识别使用谷歌的张量流和结果非常壮观。