In general, license plate recognition requires Sobel location, color location and SVM to evaluate and score the candidate license plate. Finally, it extracts HOG features to enter ANN recognition according to the training model.

This chapter introduces the logical codes related to positioning, in which positioning uses Sobel positioning (edge detection positioning) and color positioning: CarSobelPlateLocation and CarColorPlateLocation in corresponding codes; After both positioning, some candidate images are obtained, and these images are sent to SVM for evaluation. SVM extracts edge information features based on HOG, HOG is similar to LBP which deals with texture features before. The project code is developed on Clion, and the source address is used for license plate positioning

Sobel positioning

CarSobelPlateLocation, noise reduction through the following steps:

  • Gaussian blur
  • Gray,
  • marginalized
  • binarization
  • Close your operations
Gaussian blur
// Preprocessing: denoising makes the license plate area more prominent
    Mat blur;
    //1, gaussian blur (smooth) (1, for subsequent operation 2, noise reduction)
    GaussianBlur(src, blur, Size(5.5), 0);
    //imshow(" blur ",blur);
Copy the code
Gray,
 Mat gray;
    // Grayscale removes color because it does not use noise reduction here
    cvtColor(blur, gray, COLOR_BGR2GRAY);
    imshow("Gray", gray);
Copy the code
marginalized
 Mat sobel_16;
    //3, edge detection to make the license plate more prominent in the call to 16 bits to save the data in the subsequent operation and display need to switch back to 8 bits
    Sobel(gray, sobel_16, CV_16S, 1.0);
    // Convert to 8 bits
    Mat sobel;
    convertScaleAbs(sobel_16, sobel);
    imshow("Sobel", sobel);
Copy the code
binarization
//4. Binary black and white
    Mat shold;
    // Large law maximum class algorithm
    threshold(sobel, shold, 0.255, THRESH_OTSU + THRESH_BINARY);
    imshow("Binary", shold);
Copy the code
Close your operations
//5
    // Expand the adjacent white areas to form a whole
    Mat close;
    Mat element = getStructuringElement(MORPH_RECT, Size(17.3));
    morphologyEx(shold, close, MORPH_CLOSE, element);
    imshow("Closed operation", close);
Copy the code

The above operation is in the process of noise reduction, the sixth step of the preliminary selection.

The sixth step: maximum area, minimum area. Wide high force.

//6
    / / get a preliminary screening plate profile = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
    // Outline detection
    vector< vector<Point>> contours;
    // Extract the outermost contour and put the result into a sequence of points into the collection
    findContours(close, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);

    / / traverse
    vector<RotatedRect> vec_sobel_roi;
    for(vector<Point> point:contours){
        RotatedRect rotatedRect= minAreaRect(point);
        //rectangle(src, rotatedRect.boundingRect(), Scalar(255, 0, 255));
        // Perform a preliminary filter to exclude completely incompatible contours (e.g., 1x1, 5x1000)
        if(verifySizes(rotatedRect)) { vec_sobel_roi.push_back(rotatedRect); }}Copy the code

Float aspec (1 * 1, 5* 1000) float aspec

int CarPlateLocation::verifySizes(RotatedRect rotated_rect) {
    / / fault-tolerant rate
    float error = 0.75 f;

    // The width and height of the model are 136 * 32
    // Get the aspect ratio
    float aspect = float(136) / float(32);

    // Discard the minimum and maximum areas that do not meet the requirements
    // Give a rough idea
    // Make it as big as possible. This is still preliminary screening.
    int min = 20 * aspect * 20;
    int max = 180 * aspect * 180;

    // Scale float error is also satisfied
    // Minimum width and height ratio
    float rmin = aspect - aspect * error;
    // Maximum aspect ratio
    float rmax = aspect + aspect * error;
    // The area of the rectangle
    float area = rotated_rect.size.height * rotated_rect.size.width;
    // The ratio of the rectangle
    float r = (float) rotated_rect.size.width / (float) rotated_rect.size.height;
    if ((area < min || area > max) || (r < rmin || r > rmax))
        return 0;
    return 1;
}
Copy the code

Turning oblique pictures straight: affine transformation

Size of rectangle 4. Coordinates of the center point of rectangle 5
void CarPlateLocation::rotation(Mat src, Mat &dst, Size rect_size,
                                Point2f center, double angle) {

    // Get the rotation matrix
    Mat rot_mat = getRotationMatrix2D(center, angle, 1);

    // Apply affine transformation
    Mat mat_rotated;
    // After correction, the size will be different, but the diagonal will definitely accommodate
    int max = sqrt(pow(src.rows, 2) + pow(src.cols, 2));
    // Affine transformation
    warpAffine(src, mat_rotated, rot_mat, Size(max, max),
               CV_INTER_CUBIC);
    imshow("Before rotation", src);
    imshow("Rotation", mat_rotated);
    // Cut off as much of the license plate as possible
    getRectSubPix(mat_rotated, Size(rect_size.width, rect_size.height), center, dst);
    imshow("Capture", dst);
    mat_rotated.release();
    rot_mat.release();
}
Copy the code

Color orientation

HSV color model

Hue (H), saturation (S), brightness (V);

BGR 转成 HSV

cvtColor(src,hsv,COLOR_BGR2HSV);
Copy the code
Tonal H

In terms of Angle, the value ranges from 0° to 360°. Starting from red, the value is 0°, green is 120°, and blue is 240°. Their complementary colors are: yellow for 60 degrees, cyan for 180 degrees, magenta for 300 degrees;

Saturation S

Saturation S indicates the degree to which the color approximates the spectral color. A color that can be seen as the result of a certain spectral color mixed with white. The larger the proportion of spectral color, the higher the degree of color close to spectral color, the higher the saturation of color. High saturation, deep and bright color. The white component of spectral color is 0 and the saturation is the highest. The value ranges from 0% to 100%. A larger value indicates a more saturated color.

Lightness V

Brightness indicates the brightness of the color. For the color of the light source, the brightness value is related to the brightness of the illuminator. For object color, this value is related to the transmittance or reflectance of the object. Usually the value ranges from 0% (black) to 100% (white)

In OpenCV, if the HSV data is 8UC, the values are 0-180, 0-255, 0-255, that is, the blue value should be 120

Follow the table above to find the blue area (100 ~ 124), then change the H and S in HSV to 0, and the V to 255. The HSV value for the other areas is 0.

/ / 3
    int chanles = hsv.channels();
    / / high
    int h = hsv.rows;
    // Wide data length
    int w = hsv.cols * 3;

    // Determine whether the data is stored in a row
    // If there is enough memory, MAT's data is stored in a contiguous block of memory
    if (hsv.isContinuous()) {
        w *= h;
        h = 1;
    }

    for (size_t i = 0; i < h; ++i) {
        // HSV uchar = Java byte
        uchar *p = hsv.ptr<uchar>(i);

        for (size_t j = 0; j < w; j += 3) {
            int h = int(p[j]);
            int s = int(p[j + 1]);
            int v = int(p[j + 2]);

            bool blue = false;
            / / blue
            if (h >= 100 && h <= 124 && s >= 43 && s <= 255 && v >= 46 && v <= 255) {
                blue = true;
            }

            if (blue){
                p[j] = 0;
                p[j + 1] =0;
                p[j + 2] =255;
            }else {
                // HSV model H: 0 red is 0 in brightness and saturation, so it becomes black
                p[j] = 0;
                p[j + 1] = 0;
                p[j + 2] = 0; }}}Copy the code

The following graph is obtained:

Next, extract brightness:

// Pull out the brightness data
    // Separate h, s, and v
    vector<Mat> hsv_split;
    split(hsv, hsv_split);

Copy the code

And then, like Sobel, through binarization, grand law, etc

    // The whole image + the license plate selected in the preliminary competition + the candidate license plate obtained
    tortuosity(src, vec_sobel_roi, dst);

    for (Mat s: dst) {
        imshow("Candidate", s);
        waitKey();
    }
Copy the code

Filter out a set:

The two combinations are combined and then evaluated by SVM, because unlike face detection, there is no ready-made model.

vector< Mat > sobel_plates;
/ / sobel positioning
plateLocation->location(src, sobel_plates);

// Color localization
vector< Mat > color_plates;
plateColorLocation->location(src, color_plates);

vector<Mat> plates;
// Add all the contents of sobel_plates to the plates vector
plates.insert(plates.end(),sobel_plates.begin(), sobel_plates.end());
plates.insert(plates.end(), color_plates.begin(), color_plates.end());
Copy the code

SVM

Blog.csdn.net/liukun321/a…

Simply put, SVM is used to distinguish between different types (license plate and non-license plate). SVM training data has both features and labels. Through training, the machine can find the relationship between features and labels by itself, and judge labels when faced with data with only features and no labels. Supervised learning in machine learning. Linear separable, linear indivisible, indivisible with the kernel function to distinguish:

Kernel function: used to extract different types

LBP is used for face detection to extract features, and HOG is adopted here to extract features.

SVM load model, the model is also XML file

svm = SVM::load(svm_model);
CarPlateRecgnize p("/Users/xiuchengyin/Documents/Tina-NDK/OpencvCarRecgnize/resource/HOG_SVM_DATA2.xml");
Copy the code

HOG feature

Locally normalized histogram of gradient direction is an intensive descriptor for local overlapping regions of images. It constructs features by calculating the histogram of gradient direction of local regions.

The width of parameter 1(detection window) – the width of parameter 2(block size) and the remainder of parameter 3(block sliding increment) must be 0 high

Parameter 4 is cell size, and parameter 5 is gradient direction

HOGDescriptor hog(Size(128, 64), Size(16, 16), Size(8, 8), Size(8, 8), 3);

Initialize the HOG variable

 // Width of parameter 1 - width of parameter 2 turns out to be the same as height of parameter 3 with remainder 0
    svmHog = new HOGDescriptor(Size(128.64),Size(16.16),Size(8.8),Size(8.8),3);
Copy the code

Inspection window is divided into: ((128-16) / 8 + 1) * ((64-16) / 8 + 1) = 105 pieces (Block);

A Block has four cells;

The length of Hog descriptor vector of a Cell is 9;

The feature of statistical gradient histogram is to divide the gradient direction (0-360) into X intervals and convert the image into several Windows of 16×16. Each window is divided into X blocks, and each block is converted into 4 cells (8×8). For each cell, calculate the gradient direction of each pixel point, increase the corresponding bin value according to the gradient direction, and finally synthesize the gradient histogram of N cells to form features.

To put it simply, the edge of the license plate is a group of information composed of the internal text (the gradient value at the edge and corner is very large, and the edge and corner contain a lot of object shape information). HOG is to extract these information to form a histogram.

HOG: The gradient direction weakens the influence of light and is suitable for capturing contour.

LBP: The LBP value of the center pixel reflects the texture information of the surrounding area of the pixel.

SVM scores the candidate images according to the features extracted from HOG and selects the optimal one:

string CarPlateRecgnize::plateRecgnize(Mat src) {
    vector< Mat > sobel_plates;
    / / sobel positioning
    sobelPlateLocation->location(src, sobel_plates);
    // Color localization
    vector< Mat > color_plates;
    colorPlateLocation->location(src, color_plates);
    vector< Mat > plates;
    // Add all the contents of sobel_plates to the plates vector
    plates.insert(plates.end(),sobel_plates.begin(), sobel_plates.end());
    plates.insert(plates.end(), color_plates.begin(), color_plates.end());

    int index = - 1;
    float minScore = FLT_MAX; // The maximum value of float
    // Use SVM for profiling
    for (int i = 0; i< plates.size(); ++i) { Mat plate = plates[i];// Grayscale first, then binarization, grayscale only one channel
        Mat gray;
        cvtColor(plate, gray,COLOR_BGR2GRAY);
        // Binarization must be a single channel
        Mat shold;
        threshold(gray, shold, 0.255, THRESH_OTSU + THRESH_BINARY);
        // Extract the feature
        Mat features;
        getHogFeatures(svmHog, shold, features);
        // save the data into a single line
        Mat samples = features.reshape(1.1);
        // Convert the data store format
        samples.convertTo(samples, CV_32FC1 );

        // Original mode
        // SVM: tells you directly what type of data this data belongs to.
        // RAW_OUTPUT: let SVM give a score
// char name[100];
// sprintf(name, "%d", I);
// imshow(name, plate);

        float score = svm->predict(samples, noArray(), StatModel::Flags::RAW_OUTPUT);
        printf("Grade: %f\n",score);
        if (score < minScore) {
            minScore = score;
            index = i;
        }
        gray.release();
        shold.release();
        features.release();
        samples.release();
    }

    Mat dst;
    if (index >= 0) {
        dst = plates[index].clone();
    }
// imshow(" license ", DST);
// waitKey();
/ / release
    for (Mat p : plates) {
        p.release();
    }
    return string("123");
}
Copy the code

SVM scores are as follows:

/ Users/xiuchengyin/Documents/Tina - the NDK/OpencvCarRecgnize/cmake - build - the debug/OpencvCarRecgnize score: 1.224322 score: 1.255759 score: 1.831937 Score: -0.070820 Score: 1.525869 score: 1.117042Copy the code

What came out of the test was our license plate selection.

Reference: github.com/liuruoze/Ea…

www.cnblogs.com/subconsciou…