本文介绍了OpenCV和C ++-形状和路标检测的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须编写一个程序来检测3种类型的路标(限速,禁止停车和警告).我知道如何使用HoughCircles来检测圆,但是我有几张图像,并且HoughCircles的参数对于每张图像都是不同的.有一种通用的方法可以检测圆形而不改变每个图像的参数?

I have to write a program that detect 3 types of road signs (speed limit, no parking and warnings). I know how to detect a circle using HoughCircles but I have several images and the parameters for HoughCircles are different for each image. There's a general way to detect circles without changing parameters for each image?

此外,我需要检测三角形(警告信号),因此我正在寻找通用的形状检测器.您是否有任何建议/代码可以帮助我完成此任务?

Moreover I need to detect triangle (warning signs) so I'm searching for a general shape detector. Have you any suggestions/code that can help me in this task?

最后,为了检测限速标志上的数字,我想使用SIFT并将图像与一些模板进行比较,以识别标志上的数字.可能是个好方法吗?

Finally for detect the number on speed limit signs I thought to use SIFT and compare the image with some templates in order to identify the number on the sign. Could it be a good approach?

谢谢您的回答!

推荐答案

我知道这是一个非常老的问题,但是我遇到了同样的问题,现在向您展示如何解决该问题.下图显示了opencv程序显示的一些最准确的结果.在以下图像中,检测到的路标用三种不同的颜色圈出,以区分三种路标(警告,禁止停车,限速).

I know this is a pretty old question but I had been through the same problem and now I show you how I solved it.The following images show some of the most accurate results that are displayed by the opencv program.In the following images the street signs detected are circled with three different colors that distinguish the three kinds of street signs (warning, no parking, speed limit).

  • 红色为警告标志
  • 蓝色禁止停车标志
  • 紫红色的限速标志

速度限制值在速度限制标志上方以绿色书写

The speed limit value is written in green above the speed limit signs

[![example][1]][1]
[![example][2]][2]
[![example][3]][3]
[![example][4]][4]

如您所见,该程序运行良好,能够检测和区分三种符号,并在有速度限制标志的情况下识别速度限制值.例如,当图像中有一些不属于这三种类别之一的信号时,一切都无需计算太多的误报即可.为了获得此结果,该软件分三个主要步骤计算检测量.第一步涉及一种基于颜色的方法,其中检测图像中的红色对象并提取其区域以进行分析.由于仅处理图像的一小部分,因此此步骤对于防止检测到误报特别有用.第二步使用机器学习算法:特别是,我们使用Cascade分类器来计算检测.该操作首先需要训练分类器,并在以后的阶段中使用它们来检测符号.在最后一步,读取速度限制符号内的速度限制值,在这种情况下,也通过机器学习算法但使用k最近邻居算法读取.现在,我们将详细了解每个步骤.

As you can see the program performs quite well, it is able to detect and distinguish the three kinds of sign and to recognize the speed limit value in case of speed limit signs. Everything is done without computing too many false positives when, for instance, in the image there are some signs that do not belong to one of the three categories.In order to achieve this result the software computes the detection in three main steps.The first step involves a color based approach where the red objects in the image are detected and their region are extract to be analyzed. This step is particularly useful in order to prevent the detection of false positives, because only a small part of the image is processed.The second step works with a machine learning algorithm: in particular we use a Cascade Classifier to compute the detection. This operation firstly requires to train the classifiers and on a later stage to use them to detect the signs.In the last step the speed limit values inside the speed limit signs are read, also in this case through a machine learning algorithm but using the k-nearest neighbor algorithm.Now we are going to see in detail each step.

由于路牌总是被红色框圈起来,因此我们只能拿出并分析仅检测到红色物体的区域.为了选择红色对象,我们考虑了红色的所有范围:即使这可能产生一些误报,也将在接下来的步骤中将其轻松丢弃.

Since the street signs are always circled by a red frame, we can afford to take out and analyze only the regions where the red objects are detected.In order to select the red objects, we consider all the ranges of the red color: even if this may produce some false positives, they will be easily discarded in the next steps.

inRange(image, Scalar(0, 70, 50), Scalar(10, 255, 255), mask1);
inRange(image, Scalar(170, 70, 50), Scalar(180, 255, 255), mask2);

在下图中,我们可以看到使用此方法检测到的红色物体的示例.

In the image below we can see an example of the red objects detected with this method.

找到红色像素后,我们可以使用聚类算法将它们收集起来以找到区域,我使用了方法

After having found the red pixels we can gather them to find the regions using a clustering algorithm, I use the method

partition(<#_ForwardIterator __first#>, _ForwardIterator __last, <#_Predicate __pred#>)

执行此方法后,我们可以将同一簇中的所有点保存在一个向量中(每个簇一个),并提取表示下一步要分析的区域.

After the execution of this method we can save all the points in the same cluster in a vector (one for each cluster) and extract the bounding boxes which represent theregions to be analyzed in the next step.

这是检测路牌的真实检测步骤.为了执行级联分类器,第一步在于建立正图像和负图像的数据集.现在,我解释如何构建自己的图像数据集.首先要注意的是,我们需要训练三个不同的Haar级联,以便区分必须检测的三种信号,因此,对于三种信号中的每一种,我们都必须重复以下步骤.

This is the real detection step where the street signs are detected. In order to perform a cascade classifier the first step consist in building a dataset of positives and negatives images. Now I explain how I have built my own datasets of images.The first thing to note is that we need to train three different Haar cascades in order to distinguish between the three kind of signs that we have to detect, hence we must repeat the following steps for each of the three kinds of sign.

我们需要两个数据集:一个用于正样本(必须是一组包含要检测的路标的图像),另一个用于负样本可以是任何类型的没有路标的图像.在两个不同的文件夹中收集了一组100个阳性样本图像和一组200个阴性样本图像之后,我们需要编写两个文本文件:

We need two datasets: one for the positive samples (which must be a set of images that contains the road signs that we are going to detect) and another one for the negative samples which can be any kind of image without street signs.After collecting a set of 100 images for the positive samples and a set of 200 images for the negatives in two different folders, we need to write two text files:

  1. Signs.info包含一个文件名列表,如下所示,一个为阳性文件夹中的每个阳性样品.

  1. Signs.info which contains a list of file names like the one below,one for each positive sample in the positive folder.

pos/image_name.png 1 0 0 50 45

在这里,名字后面的数字分别代表数字图像中路牌的数量,左上角的坐标路牌的一角,他的高度和宽度.

Here, the numbers after the name represent respectively the numberof street signs in the image, the coordinate of the upper leftcorner of the street sign, his height and his width.

Bg.txt,其中包含文件名列表,如下所示,一个否定文件夹中的每个符号.

Bg.txt which contains a list of file names like the one below, onefor each sign in the negative folder.

neg/street15.png

在下面的命令行中,我们生成.vect文件,其中包含软件从阳性样本中检索到的所有信息.

With the command line below we generate the .vect file which contains all the information that the software retrieves from the positive samples.

opencv_createsamples -info sign.info -num 100 -w 50 -h 50 -vec signs.vec

然后,我们使用以下命令训练级联分类器:

Afterwards we train the cascade classifier with the following command:

opencv_traincascade -data data -vec signs.vec -bg bg.txt -numPos 60 -numNeg 200 -numStages 15 -w 50 -h 50 -featureType LBP

其中级数表示将生成以构建级联的分类器的数量.在此过程结束时,我们将获得CascadeClassifier程序中使用的文件cascade.xml,以检测图像中的对象.现在我们已经训练了算法,可以为每种路牌声明一个CascadeClassifier,而不是通过以下方式检测图像中的路标

where the number of stages indicates the number of classifiers that will be generated in order to build the cascade.At the end of this process we gain a file cascade.xml which will be used from the CascadeClassifier program in order to detect the objects in the image.Now we have trained our algorithm and we can declare a CascadeClassifier for each kind of street sign, than we detect the signs in the image through

detectMultiScale(<#InputArray image#>, <#std::vector<Rect> &objects#>)

此方法在每个已检测到的对象周围创建一个Rect.重要的是要注意到,与每种机器学习算法一样,为了表现良好,我们需要数据集中的大量样本.我建立的数据集不是很大,因此在某些情况下它无法检测所有信号.大多数情况是在以下图像中看不到路牌的一小部分时出现的:

this method creates a Rect around each object that has been detected.It is important to note that exactly as every machine learning algorithm, in order to perform well, we need a large number of samples in the dataset. The dataset that I have built, is not extremely large, thus in some situations it is not able to detect all the signs. This mostly happens when a small part of the street sign is not visible in the image like in the warning sign below:

我将数据集扩展到可以获得相当准确的结果而没有 错误太多.

I have expanded my dataset up to the point where I have obtained a fairly accurate result without too many errors.

在这里我也像路牌检测一样,使用了机器学习算法,但是使用了不同的方法.经过一些工作,我意识到OCR(tesseract)解决方案不能很好地执行,因此我决定构建自己的ocr软件.

Like for the street signs detection also here I used a machine learning algorithm but with a different approach. After some work, I realized that an OCR (tesseract) solution does not perform well, so I decided to build my own ocr software.

对于机器学习算法,我将下图作为训练数据,其中包含一些速度极限值:

For the machine learning algorithm I took the image below as training data which contains some speed limit values:

训练数据量很小.但是,由于在限速标志中所有字母都具有相同的字体,所以这不是一个大问题.为了准备训练数据,我在OpenCV中编写了一个小代码.它执行以下操作:

The amount of training data is small. But, since in speed limit signs all letters have the same font, it is not a huge problem.To prepare the data for training, I made a small code in OpenCV. It does the following things:

  1. 它将图像加载到左侧;
  2. 它选择数字(显然是通过轮廓查找并在字母的面积和高度上施加限制,以避免错误检测).
  3. 它将围绕一个字母绘制边界矩形,并等待手动按下该键.这次用户自己按了框中对应字母的数字键.
  4. 一旦按下相应的数字键,它将在一个数组中保存100个像素值,而在另一个数组中保存相应的手动输入的数字.
  5. 最终它将两个数组都保存在单独的txt文件中.

按照手动数字分类,火车数据(train.png)中的所有数字都被手动标记,图像看起来像下面的数字.

Following the manual digit classification all the digits in the train data( train.png) are manually labeled, and the image will look like the one below.

现在我们进入培训和测试部分.

对于培训,我们执行以下操作:

For training we do as follows:

  1. 加载我们之前已保存的txt文件
  2. 创建将要使用的分类器的实例(KNearest)
  3. 然后我们使用KNearest.train函数来训练数据

现在进行检测:

  1. 我们在检测到速度限制标志的情况下加载图像
  2. 像以前一样处理图像并使用轮廓法提取每个数字
  3. 为其绘制边界框,然后将其尺寸调整为10x10,并将其像素值存储在数组中,就像之前所做的一样.
  4. 然后,我们使用KNearest.find_nearest()函数查找与我们提供的商品最接近的商品.
    并且它可以识别正确的数字.
  1. We load the image with the speed limit sign detected
  2. Process the image as before and extract each digit using contour methods
  3. Draw bounding box for it, then resize to 10x10, and store its pixel values in an array as done earlier.
  4. Then we use KNearest.find_nearest() function to find the nearest item to the one we gave.
    And it recognizes the correct digit.

我在许多图像上测试了这个小的OCR,仅通过这个小的数据集,我就获得了大约90%的准确度.

I tested this little OCR on many images, and just with this small dataset I have obtained an accuracy of about 90%.

下面,我将所有openCv c ++代码发布到一个类中,按照我的指示,您应该可以达到我的结果.

Below I post all my openCv c++ code in a single class, following my instruction you should be able to achive my result.

#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <stdlib.h>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui.hpp"
#include <string.h>
#include <opencv2/ml/ml.hpp>

using namespace std;
using namespace cv;

std::vector<cv::Rect> getRedObjects(cv::Mat image);
vector<Mat> detectAndDisplaySpeedLimit( Mat frame );
vector<Mat> detectAndDisplayNoParking( Mat frame );
vector<Mat> detectAndDisplayWarning( Mat frame );
void trainDigitClassifier();
string getDigits(Mat image);
vector<Mat> loadAllImage();
int getSpeedLimit(string speed);

//path of the haar cascade files
String no_parking_signs_cascade = "/Users/giuliopettenuzzo/Desktop/cascade_classifiers/no_parking_cascade.xml";
String speed_signs_cascade = "/Users/giuliopettenuzzo/Desktop/cascade_classifiers/speed_limit_cascade.xml";
String warning_signs_cascade = "/Users/giuliopettenuzzo/Desktop/cascade_classifiers/warning_cascade.xml";

CascadeClassifier speed_limit_cascade;
CascadeClassifier no_parking_cascade;
CascadeClassifier warning_cascade;

int main(int argc, char** argv)
{
    //train the classifier for digit recognition, this require a manually train, read the report for more details
    trainDigitClassifier();

    cv::Mat sceneImage;
    vector<Mat> allImages = loadAllImage();

    for(int i = 0;i<=allImages.size();i++){
        sceneImage = allImages[i];

        //load the haar cascade files
        if( !speed_limit_cascade.load( speed_signs_cascade ) ){ printf("--(!)Error loading\n"); return -1; };
        if( !no_parking_cascade.load( no_parking_signs_cascade ) ){ printf("--(!)Error loading\n"); return -1; };
        if( !warning_cascade.load( warning_signs_cascade ) ){ printf("--(!)Error loading\n"); return -1; };

        Mat scene = sceneImage.clone();

        //detect the red objects
        std::vector<cv::Rect> allObj = getRedObjects(scene);

        //use the three cascade classifier for each object detected by the getRedObjects() method
        for(int j = 0;j<allObj.size();j++){
            Mat img = sceneImage(Rect(allObj[j]));
            vector<Mat> warningVec = detectAndDisplayWarning(img);
            if(warningVec.size()>0){
                Rect box = allObj[j];
            }
            vector<Mat> noParkVec = detectAndDisplayNoParking(img);
            if(noParkVec.size()>0){
                Rect box = allObj[j];
            }
            vector<Mat> speedLitmitVec = detectAndDisplaySpeedLimit(img);
            if(speedLitmitVec.size()>0){
                Rect box = allObj[j];
                for(int i = 0; i<speedLitmitVec.size();i++){
                    //get speed limit and skatch it in the image
                    int digit = getSpeedLimit(getDigits(speedLitmitVec[i]));
                    if(digit > 0){
                        Point point = box.tl();
                        point.y = point.y + 30;
                        cv::putText(sceneImage,
                                    "SPEED LIMIT " + to_string(digit),
                                    point,
                                    cv::FONT_HERSHEY_COMPLEX_SMALL,
                                    0.7,
                                    cv::Scalar(0,255,0),
                                    1,
                                    cv::CV__CAP_PROP_LATEST);
                    }
                }
            }
        }
        imshow("currentobj",sceneImage);
        waitKey(0);
    }
}

/*
 *  detect the red object in the image given in the param,
 *  return a vector containing all the Rect of the red objects
 */
std::vector<cv::Rect> getRedObjects(cv::Mat image)
{
    Mat3b res = image.clone();
    std::vector<cv::Rect> result;

    cvtColor(image, image, COLOR_BGR2HSV);

    Mat1b mask1, mask2;
    //ranges of red color
    inRange(image, Scalar(0, 70, 50), Scalar(10, 255, 255), mask1);
    inRange(image, Scalar(170, 70, 50), Scalar(180, 255, 255), mask2);

    Mat1b mask = mask1 | mask2;
    Mat nonZeroCoordinates;
    vector<Point> pts;

    findNonZero(mask, pts);
    for (int i = 0; i < nonZeroCoordinates.total(); i++ ) {
        cout << "Zero#" << i << ": " << nonZeroCoordinates.at<Point>(i).x << ", " << nonZeroCoordinates.at<Point>(i).y << endl;
    }

    int th_distance = 2; // radius tolerance

     // Apply partition
     // All pixels within the radius tolerance distance will belong to the same class (same label)
    vector<int> labels;

     // With lambda function (require C++11)
    int th2 = th_distance * th_distance;
    int n_labels = partition(pts, labels, [th2](const Point& lhs, const Point& rhs) {
        return ((lhs.x - rhs.x)*(lhs.x - rhs.x) + (lhs.y - rhs.y)*(lhs.y - rhs.y)) < th2;
    });

     // You can save all points in the same class in a vector (one for each class), just like findContours
    vector<vector<Point>> contours(n_labels);
    for (int i = 0; i < pts.size(); ++i){
        contours[labels[i]].push_back(pts[i]);
    }

     // Get bounding boxes
    vector<Rect> boxes;
    for (int i = 0; i < contours.size(); ++i)
    {
        Rect box = boundingRect(contours[i]);
        if(contours[i].size()>500){//prima era 1000
            boxes.push_back(box);

            Rect enlarged_box = box + Size(100,100);
            enlarged_box -= Point(30,30);

            if(enlarged_box.x<0){
                enlarged_box.x = 0;
            }
            if(enlarged_box.y<0){
                enlarged_box.y = 0;
            }
            if(enlarged_box.height + enlarged_box.y > res.rows){
                enlarged_box.height = res.rows - enlarged_box.y;
            }
            if(enlarged_box.width + enlarged_box.x > res.cols){
                enlarged_box.width = res.cols - enlarged_box.x;
            }

            Mat img = res(Rect(enlarged_box));
            result.push_back(enlarged_box);
        }
     }
     Rect largest_box = *max_element(boxes.begin(), boxes.end(), [](const Rect& lhs, const Rect& rhs) {
         return lhs.area() < rhs.area();
     });

    //draw the rects in case you want to see them
     for(int j=0;j<=boxes.size();j++){
         if(boxes[j].area() > largest_box.area()/3){
             rectangle(res, boxes[j], Scalar(0, 0, 255));

             Rect enlarged_box = boxes[j] + Size(20,20);
             enlarged_box -= Point(10,10);

             rectangle(res, enlarged_box, Scalar(0, 255, 0));
         }
     }

     rectangle(res, largest_box, Scalar(0, 0, 255));

     Rect enlarged_box = largest_box + Size(20,20);
     enlarged_box -= Point(10,10);

     rectangle(res, enlarged_box, Scalar(0, 255, 0));

     return result;
}

/*
 *  code for detect the speed limit sign , it draws a circle around the speed limit signs
 */
vector<Mat> detectAndDisplaySpeedLimit( Mat frame )
{
    std::vector<Rect> signs;
    vector<Mat> result;
    Mat frame_gray;

    cvtColor( frame, frame_gray, CV_BGR2GRAY );
    //normalizes the brightness and increases the contrast of the image
    equalizeHist( frame_gray, frame_gray );

    //-- Detect signs
    speed_limit_cascade.detectMultiScale( frame_gray, signs, 1.1, 3, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );
    cout << speed_limit_cascade.getFeatureType();

    for( size_t i = 0; i < signs.size(); i++ )
    {
        Point center( signs[i].x + signs[i].width*0.5, signs[i].y + signs[i].height*0.5 );
        ellipse( frame, center, Size( signs[i].width*0.5, signs[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );


        Mat resultImage = frame(Rect(center.x - signs[i].width*0.5,center.y - signs[i].height*0.5,signs[i].width,signs[i].height));
        result.push_back(resultImage);
    }
    return result;
}

/*
 *  code for detect the warning sign , it draws a circle around the warning signs
 */
vector<Mat> detectAndDisplayWarning( Mat frame )
{
    std::vector<Rect> signs;
    vector<Mat> result;
    Mat frame_gray;

    cvtColor( frame, frame_gray, CV_BGR2GRAY );
    equalizeHist( frame_gray, frame_gray );

    //-- Detect signs
    warning_cascade.detectMultiScale( frame_gray, signs, 1.1, 3, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );
    cout << warning_cascade.getFeatureType();
    Rect previus;


    for( size_t i = 0; i < signs.size(); i++ )
    {
        Point center( signs[i].x + signs[i].width*0.5, signs[i].y + signs[i].height*0.5 );
        Rect newRect = Rect(center.x - signs[i].width*0.5,center.y - signs[i].height*0.5,signs[i].width,signs[i].height);
        if((previus & newRect).area()>0){
            previus = newRect;
        }else{
            ellipse( frame, center, Size( signs[i].width*0.5, signs[i].height*0.5), 0, 0, 360, Scalar( 0, 0, 255 ), 4, 8, 0 );
            Mat resultImage = frame(newRect);
            result.push_back(resultImage);
            previus = newRect;
        }
    }
    return result;
}

/*
 *  code for detect the no parking sign , it draws a circle around the no parking signs
 */
vector<Mat> detectAndDisplayNoParking( Mat frame )
{
    std::vector<Rect> signs;
    vector<Mat> result;
    Mat frame_gray;

    cvtColor( frame, frame_gray, CV_BGR2GRAY );
    equalizeHist( frame_gray, frame_gray );

    //-- Detect signs
    no_parking_cascade.detectMultiScale( frame_gray, signs, 1.1, 3, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );
    cout << no_parking_cascade.getFeatureType();
    Rect previus;

    for( size_t i = 0; i < signs.size(); i++ )
    {
        Point center( signs[i].x + signs[i].width*0.5, signs[i].y + signs[i].height*0.5 );
        Rect newRect = Rect(center.x - signs[i].width*0.5,center.y - signs[i].height*0.5,signs[i].width,signs[i].height);
        if((previus & newRect).area()>0){
            previus = newRect;
        }else{
            ellipse( frame, center, Size( signs[i].width*0.5, signs[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 0 ), 4, 8, 0 );
            Mat resultImage = frame(newRect);
            result.push_back(resultImage);
            previus = newRect;
        }
    }
    return result;
}

/*
 *  train the classifier for digit recognition, this could be done only one time, this method save the result in a file and
 *  it can be used in the next executions
 *  in order to train user must enter manually the corrisponding digit that the program shows, press space if the red box is just a point (false positive)
 */
void trainDigitClassifier(){
    Mat thr,gray,con;
    Mat src=imread("/Users/giuliopettenuzzo/Desktop/all_numbers.png",1);
    cvtColor(src,gray,CV_BGR2GRAY);
    threshold(gray,thr,125,255,THRESH_BINARY_INV); //Threshold to find contour
    imshow("ci",thr);
    waitKey(0);
    thr.copyTo(con);

    // Create sample and label data
    vector< vector <Point> > contours; // Vector for storing contour
    vector< Vec4i > hierarchy;
    Mat sample;
    Mat response_array;
    findContours( con, contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ); //Find contour

    for( int i = 0; i< contours.size(); i=hierarchy[i][0] ) // iterate through first hierarchy level contours
    {
        Rect r= boundingRect(contours[i]); //Find bounding rect for each contour
        rectangle(src,Point(r.x,r.y), Point(r.x+r.width,r.y+r.height), Scalar(0,0,255),2,8,0);
        Mat ROI = thr(r); //Crop the image
        Mat tmp1, tmp2;
        resize(ROI,tmp1, Size(10,10), 0,0,INTER_LINEAR ); //resize to 10X10
        tmp1.convertTo(tmp2,CV_32FC1); //convert to float

        imshow("src",src);

        int c=waitKey(0); // Read corresponding label for contour from keyoard
        c-=0x30;     // Convert ascii to intiger value
        response_array.push_back(c); // Store label to a mat
        rectangle(src,Point(r.x,r.y), Point(r.x+r.width,r.y+r.height), Scalar(0,255,0),2,8,0);
        sample.push_back(tmp2.reshape(1,1)); // Store  sample data
    }

    // Store the data to file
    Mat response,tmp;
    tmp=response_array.reshape(1,1); //make continuous
    tmp.convertTo(response,CV_32FC1); // Convert  to float

    FileStorage Data("TrainingData.yml",FileStorage::WRITE); // Store the sample data in a file
    Data << "data" << sample;
    Data.release();

    FileStorage Label("LabelData.yml",FileStorage::WRITE); // Store the label data in a file
    Label << "label" << response;
    Label.release();
    cout<<"Training and Label data created successfully....!! "<<endl;

    imshow("src",src);
    waitKey(0);


}

/*
 *  get digit from the image given in param, using the classifier trained before
 */
string getDigits(Mat image)
{
    Mat thr1,gray1,con1;
    Mat src1 = image.clone();
    cvtColor(src1,gray1,CV_BGR2GRAY);
    threshold(gray1,thr1,125,255,THRESH_BINARY_INV); // Threshold to create input
    thr1.copyTo(con1);


    // Read stored sample and label for training
    Mat sample1;
    Mat response1,tmp1;
    FileStorage Data1("TrainingData.yml",FileStorage::READ); // Read traing data to a Mat
    Data1["data"] >> sample1;
    Data1.release();

    FileStorage Label1("LabelData.yml",FileStorage::READ); // Read label data to a Mat
    Label1["label"] >> response1;
    Label1.release();


    Ptr<ml::KNearest>  knn(ml::KNearest::create());

    knn->train(sample1, ml::ROW_SAMPLE,response1); // Train with sample and responses
    cout<<"Training compleated.....!!"<<endl;

    vector< vector <Point> > contours1; // Vector for storing contour
    vector< Vec4i > hierarchy1;

    //Create input sample by contour finding and cropping
    findContours( con1, contours1, hierarchy1,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
    Mat dst1(src1.rows,src1.cols,CV_8UC3,Scalar::all(0));
    string result;

    for( int i = 0; i< contours1.size(); i=hierarchy1[i][0] ) // iterate through each contour for first hierarchy level .
    {
        Rect r= boundingRect(contours1[i]);
        Mat ROI = thr1(r);
        Mat tmp1, tmp2;
        resize(ROI,tmp1, Size(10,10), 0,0,INTER_LINEAR );
        tmp1.convertTo(tmp2,CV_32FC1);
        Mat bestLabels;
        float p=knn -> findNearest(tmp2.reshape(1,1),4, bestLabels);
        char name[4];
        sprintf(name,"%d",(int)p);
        cout << "num = " << (int)p;
        result = result + to_string((int)p);

        putText( dst1,name,Point(r.x,r.y+r.height) ,0,1, Scalar(0, 255, 0), 2, 8 );
    }

    imwrite("dest.jpg",dst1);
    return  result ;
}
/*
 *  from the digits detected, it returns a speed limit if it is detected correctly, -1 otherwise
 */
int getSpeedLimit(string numbers){
    if ((numbers.find("30") != std::string::npos) || (numbers.find("03") != std::string::npos)) {
        return 30;
    }
    if ((numbers.find("50") != std::string::npos) || (numbers.find("05") != std::string::npos)) {
        return 50;
    }
    if ((numbers.find("80") != std::string::npos) || (numbers.find("08") != std::string::npos)) {
        return 80;
    }
    if ((numbers.find("70") != std::string::npos) || (numbers.find("07") != std::string::npos)) {
        return 70;
    }
    if ((numbers.find("90") != std::string::npos) || (numbers.find("09") != std::string::npos)) {
        return 90;
    }
    if ((numbers.find("100") != std::string::npos) || (numbers.find("001") != std::string::npos)) {
        return 100;
    }
    if ((numbers.find("130") != std::string::npos) || (numbers.find("031") != std::string::npos)) {
        return 130;
    }
    return -1;
}

/*
 *  load all the image in the file with the path hard coded below
 */
vector<Mat> loadAllImage(){
    vector<cv::String> fn;
    glob("/Users/giuliopettenuzzo/Desktop/T1/dataset/*.jpg", fn, false);

    vector<Mat> images;
    size_t count = fn.size(); //number of png files in images folder
    for (size_t i=0; i<count; i++)
        images.push_back(imread(fn[i]));
    return images;
}

这篇关于OpenCV和C ++-形状和路标检测的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-01 17:14