As mentioned in the previous article, license plate locating is based on an example in the opencv sample. I think it is theoretically feasible, but I have never performed any operations. Today I am free. I modified the code and tried several images. I found that the effect is good. The code is specially pasted to communicate with opencv learners and hope to give some guidance with high fingers. O (partition _ partition) O
The Code is as follows:
//////////////////////////////////////// //////////////////////////////////
//////////////////////////////////////// //////////////////////////////////
// Locate the license plate
// Modified by sing
// 2010-10-14
//
// The full "square detector" program.
// It loads several images subsequentally and tries to find squares in
// Each image
//
# Ifdef _ CH _
# Pragma package <opencv>
# Endif
# Define cv_no_backward_compatibility
# Include "cv. H"
# Include "highgui. H"
# Include <stdio. h>
# Include <math. h>
# Include <string. h>
Int thresh = 50;
Iplimage * IMG = 0;
Iplimage * img0 = 0;
Cvmemstorage * storage = 0;
Const char * wndname = "square detection Demo ";
// Helper function:
// Finds a cosine of angle between vectors
// From pt0-> pt1 and from pt0-> pt2
Double angle (cvpoint * pt1, cvpoint * pt2, cvpoint * pt0)
{
Double dx1 = pt1-> X-pt0-> X;
Double dy1 = pt1-> Y-pt0-> Y;
Double dx2 = pt2-> X-pt0-> X;
Double dy2 = pt2-> Y-pt0-> Y;
Return (dx1 * dx2 + dy1 * dy2)/SQRT (dx1 * dx1 + dy1 * dy1) * (dx2 * dx2 + dy2 * dy2) + 1e-10 );
}
// Returns sequence of squares detected on the image.
// The sequence is stored in the specified memory storage
Cvseq * findsquares4 (iplimage * IMG, cvmemstorage * storage)
{
Cvseq * contours;
Int I, C, L, n = 1;
Cvsize SZ = cvsize (IMG-> width &-2, IMG-> Height &-2); // ensure that the last digit is an even number, by sing
Iplimage * timg = cvcloneimage (IMG); // make a copy of input image
Iplimage * gray = cvcreateimage (SZ, 8, 1 );
Iplimage * Pyr = cvcreateimage (cvsize (SZ. width/2, Sz. Height/2), 8, 3 );
Iplimage * tgray;
Cvseq * result;
Double S, T;
// Create empty sequence that will contain points-
// 4 points per square (the square's vertices)
Cvseq * squares = cvcreateseq (0, sizeof (cvseq), sizeof (cvpoint), storage );
// Select the maximum ROI in the image
// With the width and height divisible by 2
Cvsetimageroi (timg, cvrect (0, 0, Sz. Width, Sz. Height ));
// Down-scale and upscale the image to filter out the noise
Cvpyrdown (timg, Pyr, 7 );
Cvpyrup (Pyr, timg, 7 );
Tgray = cvcreateimage (SZ, 8, 1 );
// Find squares in every color plane of the image
For (C = 0; C <3; C ++)
{
// Extract the C-th color plane
Cvsetimagecoi (timg, C + 1 );
Cvcopy (timg, tgray, 0 );
// Try several threshold levels
// For (L = 0; L <n; l ++)
{
// Hack: Use canny instead of zero threshold level.
// Canny helps to catch squares with gradient shading
// If (L = 0)
//{
/// Apply canny. Take the upper threshold from Slider
/// And set the lower to 0 (which forces edges merging)
// Cvmoderation (tgray, gray, 0, thresh, 5 );
/// Maid output to remove potential
/// Holes between edge segments
// Cvdilate (Gray, gray, 0, 1 );
//}
// Else
{
// Apply threshold if l! = 0:
// Tgray (x, y) = gray (x, y) <(L + 1) * 255/n? 255: 0
Cvthreshold (tgray, gray,/* (L + 1) x 255/N */100,255, cv_thresh_binary );
}
// Find every S and store them all as a list
Cvfindcontours (Gray, storage, & contours, sizeof (cvcontour ),
Cv_retr_list, cv_chain_approx_simple, cvpoint (0, 0 ));
// Test each Contour
While (contours)
{
// Approximate contour with accuracy proportional
// To the contour perimeter
Result = cvapproxpoly (contours, sizeof (cvcontour), storage,
Cv_poly_approx_dp, cv1_perimeter (contours) * 0.02, 0 );
// Square contours shocould have 4 vertices after Approximation
// Relatively large area (to filter out noisy contours)
// And be convex.
// Note: absolute value of an area is used because
// Area may be positive or negative-in accordance with
// Contour Orientation
If (result-> total = 4 &&
Cv1_area (result, cv_whole_seq, 0)> 1000 &&
Cv1_area (result, cv_whole_seq, 0) <(SZ. Width * Sz. Height/4 )&&
Cvcheck1_convexity (result ))
{
S = 0;
For (I = 0; I <5; I ++)
{
// Find minimum angle between joint
// Edges (maximum of cosine)
If (I> = 2)
{
T = FABS (angle (
(Cvpoint *) cvgetseqelem (result, I ),
(Cvpoint *) cvgetseqelem (result, I-2 ),
(Cvpoint *) cvgetseqelem (result, I-1 )));
S = s> T? S: T;
}
}
// If cosines of all angles are small
// (All angles are ~ 90 degree) then write quandrange
// Vertices to resultant Sequence
If (S <0.3)
For (I = 0; I <4; I ++)
Cvseqpush (squares,
(Cvpoint *) cvgetseqelem (result, I ));
}
// Take the next Contour
S = S-> h_next;
}
}
}
// Release all the temporary Images
Cvreleaseimage (& gray );
Cvreleaseimage (& Pyr );
Cvreleaseimage (& tgray );
Cvreleaseimage (& timg );
Return squares;
}
// Obtain the maximum rectangular area write by Sing 2010-10-14
Cvrect getboundingrect (cvpoint * points, int COUNT = 4)
{
Unsigned int Minx =-1, miny =-1;
Unsigned int Maxx = 0, Maxy = 0;
For (INT I = 0; I <count; I ++ ){
If (Minx> points [I]. X ){
Minx = points [I]. X;
}
If (miny> points [I]. Y ){
Miny = points [I]. Y;
}
If (Maxx <points [I]. X ){
Maxx = points [I]. X;
}
If (Maxy <points [I]. Y ){
Maxy = points [I]. Y;
}
}
Cvrect rc = cvrect (Minx, miny, Maxx-Minx, Maxy-miny );
Return RC;
}
// The function draws all the squares in the image
Void drawsquares (iplimage * IMG, cvseq * squares)
{
Cvseqreader reader;
Iplimage * CPY = cvcloneimage (IMG );
Int I;
// Initialize reader of the sequence
Cvstartreadseq (squares, & reader, 0 );
// Read 4 sequence elements at a time (all vertices of a square)
For (I = 0; I <squares-> total; I + = 4)
{
Cvpoint PT [4], * rect = pt;
Int COUNT = 4;
// Read 4 vertices
Cv_read_seq_elem (PT [0], Reader );
Cv_read_seq_elem (PT [1], Reader );
Cv_read_seq_elem (PT [2], Reader );
Cv_read_seq_elem (PT [3], Reader );
// Draw the square as a closed polyline
Cvpolyline (CPY, & rect, & count, 1, 1, cv_rgb (0,255, 0), 1, cv_aa, 0 );
// Capture the image and determine whether the image is a license plate
Cvrect rc = getboundingrect (PT, count );
// Printf ("[% d, % d]/n", RC. X, RC. Y, RC. Width, RC. Height );
Iplimage * img2 = cvcreateimage (cvsize (RC. Width, RC. Height), ipl_depth_8u, 3 );
Cvzero (img2 );
Cvsetimageroi (IMG, RC );
Cvcopyimage (IMG, img2 );
Cvresetimageroi (IMG );
Cvnamedwindow ("tmp", cv_window_autosize );
Cvshowimage ("tmp", img2 );
Cvreleaseimage (& img2 );
Cvwaitkey (0 );
}
// Show the resultant image
Cvshowimage (wndname, CPY );
Cvreleaseimage (& CPY );
}
Char * Names [] = {
"1.bmp", "2.bmp", "3.bmp ",
"4.bmp", "5.bmp", 0
};
Int main (INT argc, char ** argv)
{
Int I, C;
// Create memory storage that will contain in all the dynamic data
Storage = cvcreatememstorage (0 );
For (I = 0; names [I]! = 0; I ++)
{
// Load I-th Image
Img0 = cvloadimage (Names [I], 1 );
If (! Img0)
{
Printf ("couldn't load % s/n", Names [I]);
Continue;
}
IMG = cvcloneimage (img0 );
// Create window and a trackbar (slider) with parent "image" and set callback
// (The slider regulates upper threshold, passed to Canny edge detector)
Cvnamedwindow (wndname, 1 );
// Find and draw the squares
Drawsquares (IMG, findsquares4 (IMG, storage ));
// Wait for key.
// Also the function cvwaitkey takes care of Event Processing
C = cvwaitkey (0 );
// Release both images
Cvreleaseimage (& IMG );
Cvreleaseimage (& img0 );
// Clear memory storage-Reset free space position
Cvclearmemstorage (storage );
If (char) C = 27)
Break;
}
Cvdestroywindow (wndname );
Return 0;
}