LebGeeks

A community for technology geeks in Lebanon.

You are not logged in.

#26 June 13 2012

mesa177
Member

Re: License Plate Extraction, Processing, and Character Segmentation

Beast_C wrote:

Hello everyone!
Mesa177 Thank you alot for this amazing post...i was wondering if i may contact you regarding this project I have started working on it lately.

As I have posted earlier, any questions can be directly posted on this thread concerning this particular project. If you deem any question for whatsoever reason as private, then by all means PM me.

Offline

#27 July 2 2012

mesa177
Member

Re: License Plate Extraction, Processing, and Character Segmentation

Might as well continue with this post since Beast_C is showing interest in it, plus it's long overdue.

For better viewing of code and images, and for better referencing to the post number, I'll write each stage in a separate post (hope the moderators don't mind).

For the image masking stage (a continuation of my written code in post # 9):

% 2 - Image Masking:
% 
% The result of SCW segmentation is then used to identify which regions of
% the input image (currently studied from the five images) are accepted
% (logical ANDing).
%
figure(3)
for i = 1:M1                 % Image masking to form AND image
    for j = 1:N1
        if (I1_SCW(i,j))
           I1_AND(i,j) = I1(i,j);
        else
           I1_AND(i,j) = 0;
        end   
    end
end 
imshow(I1_AND,[]);

The resulting image would be:

2itke2q.jpg

Last edited by mesa177 (July 2 2012)

Offline

#28 July 2 2012

mesa177
Member

Re: License Plate Extraction, Processing, and Character Segmentation

For the Sauvola binarization:

% 3 - Sauvola Binarization (SB):
%
% The accepted regions are then thresholded according to Sauvola
% statistical means for each of the studied image.
%
figure(4)
I1_AND_ext = horzcat(I1_AND(:,1:5),I1_AND,I1_AND(:,N1-3:N1));
I1_AND_ext = vertcat(I1_AND_ext(1:5,:),I1_AND_ext,I1_AND_ext(M1-3:M1,:));
[M1_ext,N1_ext] = size(I1_AND_ext);
for i = 6:M1_ext-4           % Sauvola binarization (SB)
    for j = 6:N1_ext-4
        b = I1_AND_ext(i-5:i+4,j-5:j+4);
        m = mean(mean(b));
        s = std(std(b));
        T = m + (1 + 0.5*(s/128 - 1));
        if (I1_AND_ext(i,j) > T)
            I1_SB_ext(i,j) = 1;
        else
            I1_SB_ext(i,j) = 0;
        end    
        clear b m s T
    end
end 
I1_SB = I1_SB_ext(6:M1_ext-4,6:N1_ext-4);
imshow(I1_SB,[]);
clear I1_AND_ext I1_SB_ext M1_ext N1_ext

The resulting image would be:

2yp1cvq.jpg

Last edited by mesa177 (July 2 2012)

Offline

#29 July 2 2012

mesa177
Member

Re: License Plate Extraction, Processing, and Character Segmentation

For the connected-component analysis (CCA), stage object labeling:

(more info on Gaussian blurring is found here, and the concept of convolution here)

% Generating Gaussian mask to be used for blurring thresholded picture 
% before performing object labeling 

% The code block below is commented after identifying the best Sigma value for applying the Gaussian filter
% sig = fix(randn*10);           % Generating gradient of Gaussian masks for filtering
%                                % along x-axis (fx) and y-axis (fy)
% while (sig == 0)||(mod(sig,2)==0)||(abs(sig)>5)               
%       sig = fix(randn*10);     % Ensure that masks formed are odd matrices
% end                            % each of whose size is no greater than 15x15
% sig = abs(sig);                % Sigma should be positive

% After generating several Gaussian masks, best result obtained for sig = 1
sig = 1; 
n = 3*sig;
for i=1:n
    for j=1:n
      g(i,j) = exp(-(i^2+j^2)/2*sig^2);
    end
end

figure(5)
f1 = conv2(double(I1_SB),double(g)); % Convolution of the Gaussian filter and the SB image
f1 = f1(1:M1,1:N1);
[W1,num1] = bwlabel(f1,8);   % CCA of SB image with thickened contours   
imshow(W1,[]);                     % using Gaussian filter

The SB (Sauvola binarized) image after applying the Gaussian filter is:

10qf038.jpg

The result of the Canny edge detection on the filtered SB image is:

1fznk5.jpg

For those who are wondering why we apply the Gaussian filter before doing the edge detection, here's the result of edge detection without the filtering process:

5unz7m.jpg

Last edited by mesa177 (July 2 2012)

Offline

#30 July 2 2012

mesa177
Member

Re: License Plate Extraction, Processing, and Character Segmentation

Now, before finding the parameters of the LP (i.e. aspect ratio, orientation angle, and Euler's number) on the image under study to continue the CCA phase, it is important to identify the limits of these parameters (maximum and minimum required values to which the LP should be restricted). Generally, this should be done on a pool of images (like 50 plus images), but seeing that I was restricted to a pool of 5 images (my professor back then applied that restriction), that was what I did: use 5 images.

Note: The code for identifying the limits of each parameter is run on a separate m-file.

The code for detecting the LP aspect ratio limits is:

% Detecting Aspect Ratios of LP

% This program detects the aspect ratio of each of the five studied license
% plates. First, the objects in each image is labelled with bwlabel
% (classical approach of connected component labeling with 8-connectivity),
% then the label(s) identifying the boarders of the license plates are
% used to extract the position coordinates. The aspect ratio is then 
% calculated according to the equation: (cmax - cmin + 1)/(rmax - rmin + 1). 

clear all
clc

ob_cnt = 0;

% Generating Gaussian mask to be used for blurring thresholded picture 
% before performing object labeling

% sig = fix(randn*10);           % Generating gradient of Gaussian masks for filtering
%                                % along x-axis (fx) and y-axis (fy)
% while (sig == 0)||(mod(sig,2)==0)||(abs(sig)>5)               
%       sig = fix(randn*10);     % Ensure that masks formed are odd matrices
% end                            % each of whose size is no greater than 15x15
% sig = abs(sig);                % Sigma should be positive

% After generating several Gaussian masks, best result obtained for sig = 1
sig = 1; 
n = 3*sig;
for i=1:n
    for j=1:n
      g(i,j) = exp(-(i^2+j^2)/2*sig^2);
    end
end

figure(ob_cnt+1)
I1 = imread('image 1.jpg');  % Importing picture of license plate 1
I1 = rgb2gray(I1);
imshow(I1,[]);               % Show grayscale picture
[M1,N1] = size(I1);

figure(ob_cnt+2)
I_bin1 = edge(I1,'canny');   % Performing edge detection with Canny method
imshow(I_bin1,[]);           % Show edge detection

figure(ob_cnt+3)
f1 = conv2(double(I_bin1),double(g));
f1 = f1(1:M1,1:N1);
[W1,num1] = bwlabel(f1,8);   % Labeling with Matlab command bwlabel
imshow(W1,[]);

figure(ob_cnt+4)
% Extracting LP from middle section where expected to be (using a cropping algorithm which is not shown 
% here)
imshow(W1(600:910,990:1500),[]);

figure(ob_cnt+5)

% Tracking label of LP boarders at middle section where the LP is expected to be. This is done by conducting 
% a frequency count on each object label found in the extracted LP zone; since the LP is the largest object in 
% the restricted zone, the object label of the second highest frequency count (the first corresponding to the 
% image background) corresponds to the LP itself. This process is not shown here; instead, the object label 
% found i.e. 342 is used.
 
L1 = zeros(M1,N1);
[r1,c1,v1] = find(W1==342); % Final result
label1 = vertcat(r1',c1');
for i = 1:length(label1)
    L1(label1(1,i),label1(2,i)) = W1(label1(1,i),label1(2,i));
end    
imshow(L1,[]);
% clear L1 % Used for clearing image L1 upon label tracking until correct
           % label is found

r1_max = max(label1(1,:))
r1_min = min(label1(1,:))
c1_max = max(label1(2,:))
c1_min = min(label1(2,:))
a1 = (c1_max - c1_min + 1)/(r1_max - r1_min + 1)

%--------------------------------------------------------------------------

ob_cnt = ob_cnt + 5;

figure(ob_cnt+1)
I2 = imread('image 2.jpg');  % Importing picture of license plate 2
I2 = rgb2gray(I2);
imshow(I2,[]);               % Show grayscale picture
[M2,N2] = size(I2);

figure(ob_cnt+2)
I_bin2 = edge(I2,'canny');   % Performing edge detection with Canny method
imshow(I_bin2,[]);           % Show edge detection

figure(ob_cnt+3)
f2 = conv2(double(I_bin2),double(g));
f2 = f2(1:M2,1:N2);
[W2,num2] = bwlabel(f2,8);   % Labeling with Matlab command bwlabel
imshow(W2,[]);

figure(ob_cnt+4)
% Extracting LP from middle section where expected to be
imshow(W2(750:1100,900:1650),[]);

figure(ob_cnt+5)
% Tracking label of LP boarders at middle section where the LP is expected to be
L2 = zeros(M2,N2);
[r2,c2,v2] = find(W2==364); % Final result
label2 = vertcat(r2',c2');
for i = 1:length(label2)
    L2(label2(1,i),label2(2,i)) = W2(label2(1,i),label2(2,i));
end    
imshow(L2,[]);
% clear L2 % Used for clearing image L2 upon label tracking until correct
%          % label is found

r2_max = max(label2(1,:))
r2_min = min(label2(1,:))
c2_max = max(label2(2,:))
c2_min = min(label2(2,:))
a2 = (c2_max - c2_min + 1)/(r2_max - r2_min + 1)

%--------------------------------------------------------------------------

ob_cnt = ob_cnt + 5;

figure(ob_cnt+1)
I3 = imread('image 3.jpg');  % Importing picture of license plate 3
I3 = rgb2gray(I3);
imshow(I3,[]);               % Show grayscale picture
[M3,N3] = size(I3);

figure(ob_cnt+2)
I_bin3 = edge(I3,'canny');   % Performing edge detection with Canny method
imshow(I_bin3,[]);           % Show edge detection

figure(ob_cnt+3)
f3 = conv2(double(I_bin3),double(g));
f3 = f3(1:M3,1:N3);
[W3,num3] = bwlabel(f3,8);   % Labeling with Matlab command bwlabel
imshow(W3,[]);

figure(ob_cnt+4)
% Extracting LP from middle section where expected to be
imshow(W3(700:1100,1100:1700),[]);

figure(ob_cnt+5)
% Tracking label of LP boarders at middle section where the LP is expected to be
L3 = zeros(M3,N3);
[r3,c3,v3] = find(W3==369); % Final result
label3 = vertcat(r3',c3');
for i = 1:length(label3)
    L3(label3(1,i),label3(2,i)) = W3(label3(1,i),label3(2,i));
end    
imshow(L3,[]);
% clear L3 % Used for clearing image L3 upon label tracking until correct
%          % label is found

r3_max = max(label3(1,:))
r3_min = min(label3(1,:))
c3_max = max(label3(2,:))
c3_min = min(label3(2,:))
a3 = (c3_max - c3_min + 1)/(r3_max - r3_min + 1)

%--------------------------------------------------------------------------

ob_cnt = ob_cnt + 5;

figure(ob_cnt+1)
I4 = imread('image 4.jpg');  % Importing picture of license plate 4
I4 = rgb2gray(I4);
imshow(I4,[]);               % Show grayscale picture
[M4,N4] = size(I4);

figure(ob_cnt+2)
I_bin4 = edge(I4,'canny');   % Performing edge detection with Canny method
imshow(I_bin4,[]);           % Show edge detection

figure(ob_cnt+3)
f4 = conv2(double(I_bin4),double(g));
f4 = f4(1:M4,1:N4);
[W4,num4] = bwlabel(f4,8);   % Labeling with Matlab command bwlabel
imshow(W4,[]);

figure(ob_cnt+4)
% Extracting LP from middle section where expected to be
imshow(W4(620:1020,1000:1650),[]);

figure(ob_cnt+5)
% Tracking label of LP boarders at middle section where the LP is expected to be
L4 = zeros(M4,N4);
[r4,c4,v4] = find(W4==8); % Final result
label4 = vertcat(r4',c4');
for i = 1:length(label4)
    L4(label4(1,i),label4(2,i)) = W4(label4(1,i),label4(2,i));
end    
imshow(L4,[]);
% clear L4 % Used for clearing image L4 upon label tracking until correct
%          % label is found

r4_max = max(label4(1,:))
r4_min = min(label4(1,:))
c4_max = max(label4(2,:))
c4_min = min(label4(2,:))
a4 = (c4_max - c4_min + 1)/(r4_max - r4_min + 1)

%--------------------------------------------------------------------------

ob_cnt = ob_cnt + 5;

figure(ob_cnt+1)
I5 = imread('image 5.jpg');  % Importing picture of license plate 5
I5 = rgb2gray(I5);
imshow(I5,[]);               % Show grayscale picture
[M5,N5] = size(I5);

figure(ob_cnt+2)
I_bin5 = edge(I5,'canny');   % Performing edge detection with Canny method
imshow(I_bin5,[]);           % Show edge detection

figure(ob_cnt+3)
f5 = conv2(double(I_bin5),double(g));
f5 = f5(1:M5,1:N5);
[W5,num5] = bwlabel(f5,8);   % Labeling with Matlab command bwlabel
imshow(W5,[]);

figure(ob_cnt+4)
% Extracting LP from middle section where expected to be
imshow(W5(600:1100,710:1850),[]);

figure(ob_cnt+5)
% Tracking label of LP boarders at middle section where the LP is expected to be
L5 = zeros(M5,N5);
[r5,c5,v5] = find(W5==124); % Final result
label5 = vertcat(r5',c5');
for i = 1:length(label5)
    L5(label5(1,i),label5(2,i)) = W5(label5(1,i),label5(2,i));
end    
imshow(L5,[]);
% clear L5 % Used for clearing image L5 upon label tracking until correct
%          % label is found

r5_max = max(label5(1,:))
r5_min = min(label5(1,:))
c5_max = max(label5(2,:))
c5_min = min(label5(2,:))
a5 = (c5_max - c5_min + 1)/(r5_max - r5_min + 1)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

The code for detecting the LP orientation angle limits is:

% Detecting Orientation Angles of LP

% This program detects the orientation angle of each of the five studied 
% license plates. First, the objects in each image is labelled with bwlabel
% (classical approach of connected component labeling with 8-connectivity),
% then the labeled matrix is used for calculating the orientation angle,
% which is calculated according to the equation:
% tan(phi_i) = 2[r_sum(c_sum(rcWi(r,c))]/[r_sum(c_sum(r^2Wi(r,c)) - 
%                                         r_sum(c_sum(c^2Wi(r,c))]  

clear all
clc

ob_cnt = 0;

% Generating Gaussian mask to be used for blurring thresholded picture 
% before performing object labeling

% sig = fix(randn*10);           % Generating gradient of Gaussian masks for filtering
%                                % along x-axis (fx) and y-axis (fy)
% while (sig == 0)||(mod(sig,2)==0)||(abs(sig)>5)               
%       sig = fix(randn*10);     % Ensure that masks formed are odd matrices
% end                            % each of whose size is no greater than 15x15
% sig = abs(sig);                % Sigma should be positive

% After generating several Gaussian masks, best result obtained for sig = 1
sig = 1; 
n = 3*sig;
for i=1:n
    for j=1:n
      g(i,j) = exp(-(i^2+j^2)/2*sig^2);
    end
end

figure(ob_cnt+1)
I1 = imread('image 1.jpg');  % Importing picture of license plate 1
I1 = rgb2gray(I1);
imshow(I1,[]);               % Show grayscale picture
[M1,N1] = size(I1);

figure(ob_cnt+2)
I_bin1 = edge(I1,'canny');   % Performing edge detection with Canny method
imshow(I_bin1,[]);           % Show edge detection

figure(ob_cnt+3)
f1 = conv2(double(I_bin1),double(g));
f1 = f1(1:M1,1:N1);
[W1,num1] = bwlabel(f1,8);   % Labeling with Matlab command bwlabel
imshow(W1,[]);

figure(ob_cnt+4)
L1 = zeros(M1,N1);
[r1,c1,v1] = find(W1==342); 
label1 = vertcat(r1',c1');
for i = 1:length(label1)
    L1(label1(1,i),label1(2,i)) = W1(label1(1,i),label1(2,i));
end    
imshow(L1,[]);

for i = 1:M1
    for j = 1:N1
        rc_component1(i,j) = i*j*L1(i,j);
    end
end
for i = 1:M1
    for j = 1:N1
        r2_component1(i,j) = i^2*L1(i,j);
    end
end
for i = 1:M1
    for j = 1:N1
        c2_component1(i,j) = j^2*L1(i,j);
    end
end    
phi1 = atand((2*sum(sum(rc_component1)))/...
             (sum(sum(r2_component1))-sum(sum(c2_component1))))

%--------------------------------------------------------------------------

ob_cnt = ob_cnt + 4;

figure(ob_cnt+1)
I2 = imread('image 2.jpg');  % Importing picture of license plate 2
I2 = rgb2gray(I2);
imshow(I2,[]);               % Show grayscale picture
[M2,N2] = size(I2);

figure(ob_cnt+2)
I_bin2 = edge(I2,'canny');   % Performing edge detection with Canny method
imshow(I_bin2,[]);           % Show edge detection

figure(ob_cnt+3)
f2 = conv2(double(I_bin2),double(g));
f2 = f2(1:M2,1:N2);
[W2,num2] = bwlabel(f2,8);   % Labeling with Matlab command bwlabel
imshow(W2,[]);

figure(ob_cnt+4)
L2 = zeros(M2,N2);
[r2,c2,v2] = find(W2==364); 
label2 = vertcat(r2',c2');
for i = 1:length(label2)
    L2(label2(1,i),label2(2,i)) = W2(label2(1,i),label2(2,i));
end    
imshow(L2,[]);

for i = 1:M2
    for j = 1:N2
        rc_component2(i,j) = i*j*L2(i,j);
    end
end
for i = 1:M2
    for j = 1:N2
        r2_component2(i,j) = i^2*L2(i,j);
    end
end
for i = 1:M2
    for j = 1:N2
        c2_component2(i,j) = j^2*L2(i,j);
    end
end    
phi2 = atand((2*sum(sum(rc_component2)))/...
             (sum(sum(r2_component2))-sum(sum(c2_component2))))

%--------------------------------------------------------------------------

ob_cnt = ob_cnt + 4;

figure(ob_cnt+1)
I3 = imread('image 3.jpg');  % Importing picture of license plate 3
I3 = rgb2gray(I3);
imshow(I3,[]);               % Show grayscale picture
[M3,N3] = size(I3);

figure(ob_cnt+2)
I_bin3 = edge(I3,'canny');   % Performing edge detection with Canny method
imshow(I_bin3,[]);           % Show edge detection

figure(ob_cnt+3)
f3 = conv2(double(I_bin3),double(g));
f3 = f3(1:M3,1:N3);
[W3,num3] = bwlabel(f3,8);   % Labeling with Matlab command bwlabel
imshow(W3,[]);

figure(ob_cnt+4)
L3 = zeros(M3,N3);
[r3,c3,v3] = find(W3==369);
label3 = vertcat(r3',c3');
for i = 1:length(label3)
    L3(label3(1,i),label3(2,i)) = W3(label3(1,i),label3(2,i));
end    
imshow(L3,[]);

for i = 1:M3
    for j = 1:N3
        rc_component3(i,j) = i*j*L3(i,j);
    end
end
for i = 1:M3
    for j = 1:N3
        r2_component3(i,j) = i^2*L3(i,j);
    end
end
for i = 1:M3
    for j = 1:N3
        c2_component3(i,j) = j^2*L3(i,j);
    end
end    
phi3 = atand((2*sum(sum(rc_component3)))/...
             (sum(sum(r2_component3))-sum(sum(c2_component3))))

%--------------------------------------------------------------------------

ob_cnt = ob_cnt + 4;

figure(ob_cnt+1)
I4 = imread('image 4.jpg');  % Importing picture of license plate 4
I4 = rgb2gray(I4);
imshow(I4,[]);               % Show grayscale picture
[M4,N4] = size(I4);

figure(ob_cnt+2)
I_bin4 = edge(I4,'canny');   % Performing edge detection with Canny method
imshow(I_bin4,[]);           % Show edge detection

figure(ob_cnt+3)
f4 = conv2(double(I_bin4),double(g));
f4 = f4(1:M4,1:N4);
[W4,num4] = bwlabel(f4,8);   % Labeling with Matlab command bwlabel
imshow(W4,[]);

figure(ob_cnt+4)
L4 = zeros(M4,N4);
[r4,c4,v4] = find(W4==8); 
label4 = vertcat(r4',c4');
for i = 1:length(label4)
    L4(label4(1,i),label4(2,i)) = W4(label4(1,i),label4(2,i));
end    
imshow(L4,[]);

for i = 1:M4
    for j = 1:N4
        rc_component4(i,j) = i*j*L4(i,j);
    end
end
for i = 1:M4
    for j = 1:N4
        r2_component4(i,j) = i^2*L4(i,j);
    end
end
for i = 1:M4
    for j = 1:N4
        c2_component4(i,j) = j^2*L4(i,j);
    end
end    
phi4 = atand((2*sum(sum(rc_component4)))/...
             (sum(sum(r2_component4))-sum(sum(c2_component4))))

%--------------------------------------------------------------------------

ob_cnt = ob_cnt + 4;

figure(ob_cnt+1)
I5 = imread('image 5.jpg');  % Importing picture of license plate 5
I5 = rgb2gray(I5);
imshow(I5,[]);               % Show grayscale picture
[M5,N5] = size(I5);

figure(ob_cnt+2)
I_bin5 = edge(I5,'canny');   % Performing edge detection with Canny method
imshow(I_bin5,[]);           % Show edge detection

figure(ob_cnt+3)
f5 = conv2(double(I_bin5),double(g));
f5 = f5(1:M5,1:N5);
[W5,num5] = bwlabel(f5,8);   % Labeling with Matlab command bwlabel
imshow(W5,[]);

figure(ob_cnt+4)
L5 = zeros(M5,N5);
[r5,c5,v5] = find(W5==124); 
label5 = vertcat(r5',c5');
for i = 1:length(label5)
    L5(label5(1,i),label5(2,i)) = W5(label5(1,i),label5(2,i));
end    
imshow(L5,[]);

for i = 1:M5
    for j = 1:N5
        rc_component5(i,j) = i*j*L5(i,j);
    end
end
for i = 1:M5
    for j = 1:N5
        r2_component5(i,j) = i^2*L5(i,j);
    end
end
for i = 1:M5
    for j = 1:N5
        c2_component5(i,j) = j^2*L5(i,j);
    end
end    
phi5 = atand((2*sum(sum(rc_component5)))/...
             (sum(sum(r2_component5))-sum(sum(c2_component5))))
         
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

As for the Euler number, the limit is always 3, because in each LP there should be at least three characters. Hence, no code needed to identify limit.

The extracted LP zone in one of the pool images (which is also the studied image) is:

30ry04o.jpg

The image resulting from the LP's label tracking (not necessary to perform, but it would give you a good idea about the accuracy of your algorithm concerning aspect ratio) for the same pool image is:

35lw74m.jpg

The limit values of the aspect ratio are 1.5 and 5.5, while those of the orientation angle are 105 and 140 (offset by pi or 180 degrees, no reason for the offset except that I wanted to maintain a positive value for the angle).

Last edited by mesa177 (July 3 2012)

Offline

#31 July 2 2012

xterm
Moderator

Re: License Plate Extraction, Processing, and Character Segmentation

This is absolutely awesome Mesa, very nice. I'm very interested in the result and I'm sure as he'll going to try and port it to python as an exercise.

Edit: you may want to toss in a license as no license means it defaults to copyright.

Offline

#32 July 2 2012

mesa177
Member

Re: License Plate Extraction, Processing, and Character Segmentation

@xterm; Do whatever pleases you with the code, I couldn't care less. Port it, use it, go crazy, I don't mind. This project was just a final assignment on one of my masters courses, and the first post shows what papers I heavily relied on concerning the algorithms.

Continuing with the CCA phase parameters identification for the image under study:

figure(ob_cnt+6)
cnt1 = 0;
for k = 1:num1               % Calculate aspect ratio
    L1 = zeros(M1,N1);       
    [r1,c1,v1] = find(W1==k); 
    label1 = vertcat(r1',c1');
    for i = 1:size(label1,2)
        L1(label1(1,i),label1(2,i)) = W1(label1(1,i),label1(2,i));
    end 
    r1_max = max(label1(1,:));
    r1_min = min(label1(1,:));
    c1_max = max(label1(2,:));
    c1_min = min(label1(2,:));
    a1(k) = (c1_max - c1_min + 1)/(r1_max - r1_min + 1);
    clear L1 r1 c1 v1 label1
end
for k = 1:num1               % Calculate orientation angle
    L1 = zeros(M1,N1); 
    [r1,c1,v1] = find(W1==k); 
    label1 = vertcat(r1',c1');
    for i = 1:size(label1,2)
        L1(label1(1,i),label1(2,i)) = W1(label1(1,i),label1(2,i));
        rc_component1(label1(1,i),label1(2,i)) = label1(1,i)*label1(2,i)...
                                              *L1(label1(1,i),label1(2,i));
        r2_component1(label1(1,i),label1(2,i)) = label1(1,i)^2*...
                                               L1(label1(1,i),label1(2,i));
        c2_component1(label1(1,i),label1(2,i)) = label1(2,i)^2*...
                                               L1(label1(1,i),label1(2,i));
    end 
    phi1(k) = atand((2*sum(sum(rc_component1)))/...
                    (sum(sum(r2_component1))-sum(sum(c2_component1))));
    clear L1 r1 c1 v1 label1 rc_component1 r2_component1 c2_component1
end
for k = 1:num1               % Calculate Euler's number
    L1 = zeros(M1,N1);       
    [r1,c1,v1] = find(W1==k); 
    label1 = vertcat(r1',c1');
    for i = 1:size(label1,2)
        L1(label1(1,i),label1(2,i)) = W1(label1(1,i),label1(2,i));
    end 
    L1_ed = edge(L1,'canny');        
    euler_num1(k) = bweuler(L1_ed,8); 
    clear L1 r1 c1 v1 label1 L1_ed
end

Now to extract the LPs in the image (extracting the objects which meat the standards i.e. parameter limitations):

I1_ob = zeros(M1,N1);
I1_f = zeros(M1,N1);
for k = 1:num1               % Retrieve objects with specific aspect ratio,
                             % orientation angle, and Euler's number 
    if ((a1(k) > 1.5)&&(a1(k) < 5.5))&&...
       (((phi1(k)+180) > 105)&&((phi1(k)+180) < 140))&&...
       (euler_num1(k) >= 3)
        L1 = zeros(M1,N1);       
        [r1,c1,v1] = find(W1==k); 
        label1 = vertcat(r1',c1');
        for i = 1:size(label1,2)
            L1(label1(1,i),label1(2,i)) = W1(label1(1,i),label1(2,i));
        end 
        for i = 1:length(label1)
            I1_ob(label1(1,i),label1(2,i)) = L1(label1(1,i),label1(2,i));
        end
        r1_max = max(label1(1,:));
        r1_min = min(label1(1,:));
        c1_max = max(label1(2,:));
        c1_min = min(label1(2,:));
        A1(cnt1+1,:) = [r1_max,r1_min,c1_max,c1_min];
        I1_f(r1_min:r1_max,c1_min:c1_max) = ...
                                           I1(r1_min:r1_max,c1_min:c1_max);
        cnt1 = cnt1 + 1;
        clear L1 r1 c1 v1 label1 r1_max r1_min c1_max c1_min 
    end  
end

The resulting extracted LP in its binary form is:

25ahj48.jpg

Last edited by mesa177 (July 3 2012)

Offline

#33 July 2 2012

mesa177
Member

Re: License Plate Extraction, Processing, and Character Segmentation

For the studied image, there is no need to perform the image inversion. However, in some cases it is necessary.

The code for the image inversion is:

if (~cnt1)                   % Detect if image inversion is needed
    clear I1_SCW I1_AND I1_SB W1 I1_ob f1 a1 phi1 euler_num1
    figure(1)
    I11 = uint8(255*ones(M1,N1)-double(I1)); % Invert image
    I1 = I11;
    clear I11
    imshow(I1,[]);
    % Repeat prior steps of SCW, image masking, SB, and CCA
    figure(2)
    I1_ext = horzcat(I1(:,1:12),I1,I1(:,N1-10:N1));
    I1_ext = vertcat(I1_ext(1:4,:),I1_ext,I1_ext(M1-2:M1,:));
    [M1_ext,N1_ext] = size(I1_ext);
    for i = 5:M1_ext-3
        for j = 13:N1_ext-11
            A_SCW = I1_ext(i-2:i+1,j-6:j+5);
            B_SCW = I1_ext(i-4:i+3,j-12:j+11);
            mA = mean(mean(A_SCW));
            mB = mean(mean(B_SCW));
            if (mA/mB < TS)
               I1_SCW_ext(i,j) = 1;
            else
               I1_SCW_ext(i,j) = 0;
            end
            clear A_SCW B_SCW mA mB
        end
    end
    I1_SCW = I1_SCW_ext(5:M1_ext-3,13:N1_ext-11);
    imshow(I1_SCW,[]);           % Show SCW segmentation
    clear I1_ext I1_SCW_ext M1_ext N1_ext
    figure(3)
    for i = 1:M1                 % Image masking to form AND image
        for j = 1:N1
            if (I1_SCW(i,j))
               I1_AND(i,j) = I1(i,j);
            else
               I1_AND(i,j) = 0;
            end   
        end
    end 
    imshow(I1_AND,[]);
    figure(4)
    I1_AND_ext = horzcat(I1_AND(:,1:5),I1_AND,I1_AND(:,N1-3:N1));
    I1_AND_ext = vertcat(I1_AND_ext(1:5,:),I1_AND_ext,I1_AND_ext(M1-3:M1,:));
    [M1_ext,N1_ext] = size(I1_AND_ext);
    for i = 6:M1_ext-4           % Sauvola binarization (SB)
        for j = 6:N1_ext-4
            b = I1_AND_ext(i-5:i+4,j-5:j+4);
            m = mean(mean(b));
            s = std(std(b));
            T = m + (1 + 0.5*(s/128 - 1));
            if (I1_AND_ext(i,j) > T)
               I1_SB_ext(i,j) = 1;
            else
               I1_SB_ext(i,j) = 0;
            end    
            clear b m s T
        end
    end 
    I1_SB = I1_SB_ext(6:M1_ext-4,6:N1_ext-4);
    imshow(I1_SB,[]);
    clear I1_AND_ext I1_SB_ext M1_ext N1_ext
    figure(ob_cnt+5)
    f1 = conv2(double(I1_SB),double(g));
    f1 = f1(1:M1,1:N1);
    [W1,num1] = bwlabel(f1,8);   % CCA of SB image with thickened contours   
    imshow(W1,[]);               % using Gaussian filter
    figure(6)
    cnt1 = 0;
    for k = 1:num1               % Calculate aspect ratio
        L1 = zeros(M1,N1);       
        [r1,c1,v1] = find(W1==k); 
        label1 = vertcat(r1',c1');
        for i = 1:size(label1,2)
            L1(label1(1,i),label1(2,i)) = W1(label1(1,i),label1(2,i));
        end 
        r1_max = max(label1(1,:));
        r1_min = min(label1(1,:));
        c1_max = max(label1(2,:));
        c1_min = min(label1(2,:));
        a1(k) = (c1_max - c1_min + 1)/(r1_max - r1_min + 1);
        clear L1 r1 c1 v1 label1
    end
    for k = 1:num1               % Calculate orientation angle
        L1 = zeros(M1,N1); 
        [r1,c1,v1] = find(W1==k); 
        label1 = vertcat(r1',c1');
        for i = 1:size(label1,2)
            L1(label1(1,i),label1(2,i)) = W1(label1(1,i),label1(2,i));
            rc_component1(label1(1,i),label1(2,i)) = label1(1,i)*...
                                                     label1(2,i)*...
                                              L1(label1(1,i),label1(2,i));
            r2_component1(label1(1,i),label1(2,i)) = label1(1,i)^2*...
                                               L1(label1(1,i),label1(2,i));
            c2_component1(label1(1,i),label1(2,i)) = label1(2,i)^2*...
                                               L1(label1(1,i),label1(2,i));
        end 
        phi1(k) = atand((2*sum(sum(rc_component1)))/...
                       (sum(sum(r2_component1))-sum(sum(c2_component1))));
        clear L1 r1 c1 v1 label1 rc_component1 r2_component1 c2_component1
    end
    for k = 1:num1               % Calculate Euler's number
        L1 = zeros(M1,N1);       
        [r1,c1,v1] = find(W1==k); 
        label1 = vertcat(r1',c1');
        for i = 1:size(label1,2)
            L1(label1(1,i),label1(2,i)) = W1(label1(1,i),label1(2,i));
        end 
        L1_ed = edge(L1,'canny');        
        euler_num1(k) = bweuler(L1_ed,8); 
        clear L1 r1 c1 v1 label1 L1_ed
    end
    I1_ob = zeros(M1,N1);
    I1_f = zeros(M1,N1);
    for k = 1:num1               % Retrieve objects with specific aspect 
                                 % ratio, orientation angle, and Euler's 
                                 % number
        if ((a1(k) > 1.5)&&(a1(k) < 5.5))&&...
           (((phi1(k)+180) > 105)&&((phi1(k)+180) < 140))&&...
           (euler_num1(k) >= 3)
           L1 = zeros(M1,N1);       
           [r1,c1,v1] = find(W1==k); 
           label1 = vertcat(r1',c1');
           for i = 1:size(label1,2)
               L1(label1(1,i),label1(2,i)) = W1(label1(1,i),label1(2,i));
           end 
           for i = 1:length(label1)
               I1_ob(label1(1,i),label1(2,i)) = L1(label1(1,i),label1(2,i));
           end
           r1_max = max(label1(1,:));
           r1_min = min(label1(1,:));
           c1_max = max(label1(2,:));
           c1_min = min(label1(2,:));
           A1(cnt1+1,:) = [r1_max,r1_min,c1_max,c1_min];
           I1_f(r1_min:r1_max,c1_min:c1_max) = ...
                                           I1(r1_min:r1_max,c1_min:c1_max);
           cnt1 = cnt1 + 1;
           clear L1 r1 c1 v1 label1 r1_max r1_min c1_max c1_min
        end  
    end
end

Naturally, it would be common sense to squeeze the SCW, image masking, SB, and CCA processes in a nice function and call it once before image inversion and another time after, but for the sake of explanation I reposted the code.

Seeing that performing image inversion on the studied image is pointless, I chose another image from my pool to exemplify the situation:

14ne1xu.jpg

In grayscale:

bdhex.jpg

If you apply the SCW and image inversion, nothing of the LP remains and hence no objects i.e. LPs are detected. So image inversion is performed:

1hqctv.jpg

The resulting SCW:

2k4j79.jpg

And the image masking:

erx7q1.jpg

And the SB:

nwacg.jpg

Which finally yields after the CCA the binary LP:

2j3intd.jpg

Last edited by mesa177 (July 2 2012)

Offline

#34 July 2 2012

mesa177
Member

Re: License Plate Extraction, Processing, and Character Segmentation

If after image inversion no LPs are detected, an error is displayed:

if (~cnt1)
    disp('No LPs in image');
end

Otherwise, the code continues and the grayscale LP object is displayed:

imshow(I1_ob,[]);            % Located regions of LPs in image 1

figure(7)
imshow(I1_f,[]);             % Extracted LPs in image 1
save A1.txt -ascii -tabs A1 % Saving the matrix ensures that the dimensions of the LP can be derived for later 
                                       % stages and the LPR process doesn't have to be conducted again
                                       % Furthermore, the matrix elements will be used as well

Displayed grayscale LP for the first non-inverted image (successful):

2po6t90.jpg

Displayed grayscale LP for inverted image (partially successful):

2z3s55e.jpg

Since only the first image is successful in yielding the LP as a whole, the coding hereon concentrates on that image.

Last edited by mesa177 (July 2 2012)

Offline

#35 July 3 2012

mesa177
Member

Re: License Plate Extraction, Processing, and Character Segmentation

For the second stage, we perform the character segmentation for the LP(s) extracted, or LPCS.

Note: the code of the LPCS stage is run on a separate m-file than the LPR stage. Hence, all initializations are re-conducted. Also, the entire LPCS process is repeated for each LP extracted from the LPR stage; thus, the LPCS code is incorporated in a for loop as follows:

for cnt = 1:size(A1,1)       % Performing CS for each extracted LP
    ...
end                                 % For the original for loop

First, we start by specifying how many LPs have been recognized in the LPR stage through extracting boundary coordinates of each:

% Character Segmentation of LP
%
% This code implements the character segmentation (CS) as follows:
%
% 1 - Specifying Sub-images:
% 
% Using the matrix Ai, the boundary coordinates of identified LPs are used
% to extract each LP as a sub-image and subject it to CS processing.
%
%--------------------------------------------------------------------------

% Initialization Stage

clear all
clc

ob_cnt = 0;
TS = 0.9;                     % Threshold for segmentation rule
sig = 1; 
n = 3*sig;
for i=1:n
    for j=1:n
      g(i,j) = exp(-(i^2+j^2)/2*sig^2);
    end
end

%--------------------------------------------------------------------------

load A1.txt A1               % Loading matrix with coordinates of LP boundaries 
I1 = imread('image 1.jpg');
I1 = rgb2gray(I1);

for cnt = 1:size(A1,1)       % Performing CS for each extracted LP
    
    % Starting sub-image specification
    LP1 = I1(A1(cnt,2):A1(cnt,1),A1(cnt,4):A1(cnt,3));
    figure(ob_cnt+1)
    imshow(LP1,[]);
    [M1(cnt),N1(cnt)] = size(LP1);
    ar1(cnt) = N1(cnt)/M1(cnt);

The image of the first (and in this case only) LP extracted is:

2921zr8.jpg

Offline

#36 July 3 2012

mesa177
Member

Re: License Plate Extraction, Processing, and Character Segmentation

Before cropping them, the sub-images require some pre-processing, namely edge detection, connected-component labeling (CCL), and slant correction:

% 2 - Pre-processing Sub-images:
%
% Before cropping, some pre-processing is required. The grayscale
% sub-images are subjected to edge detection and then connected component
% labeling. This allows the specification of the objects in the image. The
% object with the aspect ratio closest to that recorded in previous LPR
% stage (error margin is 0.011) corresponds to the LP boarders. The label
% corresponding to the this aspect ratio is used to isolate the LP boarders
% in a separate image. Since the algorithm does not account for tilted LPs,
% the derived aspect ratio of the LP might not be the actual one. As such,
% the aspect ratio of the LP is calculated from a frontal partition of the
% separate LP-boarder image; the larger value is considered as the actual
% aspect ratio of the LP. This value determines the standard size of the
% cropped LP. Non-tilted LPs would have almost identical results to the
% already calculated aspect ratio. If the actual aspect ratio is smaller
% than derived aspect ratio with an error exceeding 0.01, the LP is tilted
% in the image. This tilt is corrected by a slant correction algorithm that
% is based upon feature point and principal component analysis. This allows
% the re-orientation of the original sub-image back into place (along 
% horizontal line).  
%
% Starting sub-image pre-processing
    LP1_ed = edge(LP1,'canny'); % Canny edge detection
    f1 = conv2(double(LP1_ed),double(g)); % Gaussian filtering
    f1 = f1(1:M1(cnt),1:N1(cnt));
    [W1,num1] = bwlabel(f1,8);
    for k = 1:num1           % Extracting LP boarders   
        [r1,c1,v1] = find(W1==k); 
        label1 = vertcat(r1',c1');
        r1_max = max(label1(1,:));
        r1_min = min(label1(1,:));
        c1_max = max(label1(2,:));
        c1_min = min(label1(2,:));
        a1(k) = (c1_max - c1_min + 1)/(r1_max - r1_min + 1);
        clear r1 c1 v1 label1 r1_max r1_min c1_max c1_min
    end
    [rLPB1,cLPB1,vLPB1] = find(abs(a1-ar1(cnt)) < 0.11);
    LPB1 = zeros(M1(cnt),N1(cnt));
    p = find(max(a1(cLPB1))); % Ensure that only LP boarder label remains       
    [r1,c1,v1] = find(W1==cLPB1(p)); 
    label1 = vertcat(r1',c1');
    for i = 1:size(label1,2)
        LPB1(label1(1,i),label1(2,i)) = W1(label1(1,i),label1(2,i));
    end
    clear p r1 c1 v1 label1 a1 rLPB1 cLPB1 vLPB1
    
    % Finding actual LP aspect ratio
    [r1,c1,v1] = find(LPB1(:,1:fix(N1(cnt)/4))~=0);
    label1 = vertcat(r1',c1');
    r1_max = max(label1(1,:));
    r1_min = min(label1(1,:));
    c1_max = max(label1(2,:));
    c1_min = min(label1(2,:));
    a1_LPB_f = (c1_max - c1_min + 1)/(r1_max - r1_min + 1);
    clear r1 c1 v1 label1 r1_max r1_min c1_max c1_min
    f = 0;                   % Flag to identify if rotation is needed
    
    if (abs(ar1(cnt)/4-a1_LPB_f) > 0.01) % Correcting LP slant orientation 
        LP1_bin = edge(LPB1,'log');
        [rf1,cf1,vf1] = find(LP1_bin==1);
        m1 = mean(rf1);
        m2 = mean(cf1);
        S1(1,1) = sum(sum((rf1-m1*ones(1,size(rf1,2)))*...
                          (rf1-m1*ones(1,size(rf1,2)))'));
        S1(1,2) = sum(sum((rf1-m1*ones(1,size(rf1,2)))*...
                          (cf1-m2*ones(1,size(cf1,2)))'));  
        S1(2,1) = sum(sum((rf1-m1*ones(1,size(rf1,2)))*...
                          (cf1-m2*ones(1,size(cf1,2)))')); 
        S1(2,2) = sum(sum((cf1-m2*ones(1,size(cf1,2)))*...
                          (cf1-m2*ones(1,size(cf1,2)))'));
        [EV1,E1] = eigs(S1);
        E1_max = max(diag(E1));
        [rE1,cE1,vE1] = find(E1==E1_max);
        EV1_PC = EV1(:,cE1);
        phi1 = asind(EV1_PC(2));
        figure(ob_cnt+2)
        LP1_r = imrotate(LP1,phi1,'bilinear');
        imshow(LP1_r,[]);
        figure(ob_cnt+3)
        LPB1_r = imrotate(LPB1,phi1,'bilinear');
        imshow(LPB1_r,[]);
        [M1_r(cnt),N1_r(cnt)] = size(LP1_r);
        f = 1;
    end

The slant correction yields the following image:

1vzm9.jpg

Offline

#37 July 3 2012

mesa177
Member

Re: License Plate Extraction, Processing, and Character Segmentation

For the sub-image cropping (i.e. modifying the LP size into a standard one for further processing):

(Note: Before commencing with the cropping, if the LP requires slant correction, the new LP aspect ratio is identified)

% 3 - Cropping Sub-images: 
%
% Using bicubic interpolation, the original/oriented sub-images are cropped 
% into one of two standard sizes: if LP actual aspect ratio is greater than
% or equal to 3, the standard size would be 202 x 902 pixels; otherwise,
% the size would be 522 x 1002 pixels. If an image has a dimension smaller
% than the crop limit, its size is magnified by appending zeros at the
% sides (equal distributions on both upper and lower edges for rows or left
% and right edges for columns).
%
if (f)                   % Finding actual LP aspect ratio for cropping     
        [r1,c1,v1] = find(LPB1_r~=0);
        label1 = vertcat(r1',c1');
        r1_max = max(label1(1,:));
        r1_min = min(label1(1,:));
        c1_max = max(label1(2,:));
        c1_min = min(label1(2,:));
        LPB1_r = LPB1_r(r1_min:r1_max,c1_min:c1_max);
        LP1_r = LP1_r(r1_min:r1_max,c1_min:c1_max);
        [M1_r(cnt),N1_r(cnt)] = size(LP1_r);
        a1_LPB(cnt) = (c1_max - c1_min + 1)/(r1_max - r1_min + 1);
        clear r1 c1 v1 label1 r1_max r1_min c1_max c1_min
    else
        a1_LPB(cnt) = ar1(cnt);
    end
    
    figure(ob_cnt+4)
    if (a1_LPB(cnt) >= 3)    % Cropping LP to standard size
        if (f)
            cr_r_a1 = fix((M1_r(cnt)-100)/2) + 2*mod(M1_r(cnt)-100,2);
            cr_r_b1 = fix((M1_r(cnt)-100)/2) - mod(M1_r(cnt)-100,2);
            cr_c_a1 = fix((N1_r(cnt)-450)/2) + 2*mod(N1_r(cnt)-450,2);
            cr_c_b1 = fix((N1_r(cnt)-450)/2) - mod(N1_r(cnt)-450,2);
            LP1_cr = LP1_r(cr_r_a1:M1_r(cnt)-cr_r_b1,...
                           cr_c_a1:N1_r(cnt)-cr_c_b1);
        else
            cr_r_a1 = fix((M1(cnt)-100)/2) + 2*mod(M1(cnt)-100,2);
            cr_r_b1 = fix((M1(cnt)-100)/2) - mod(M1(cnt)-100,2);
            cr_c_a1 = fix((N1(cnt)-450)/2) + 2*mod(N1(cnt)-450,2);
            cr_c_b1 = fix((N1(cnt)-450)/2) - mod(N1(cnt)-450,2);     
            LP1_cr = LP1_r(cr_r_a1:M1(cnt)-cr_r_b1,...
                           cr_c_a1:N1(cnt)-cr_c_b1);
        end               
    else
        if (f)
            cr_r_a1 = fix((M1_r(cnt)-260)/2) + 2*mod(M1_r(cnt)-260,2);
            cr_r_b1 = fix((M1_r(cnt)-260)/2) - mod(M1_r(cnt)-260,2);
            cr_c_a1 = fix((N1_r(cnt)-500)/2) + 2*mod(N1_r(cnt)-500,2);
            cr_c_b1 = fix((N1_r(cnt)-500)/2) - mod(N1_r(cnt)-500,2);
            LP1_cr = LP1_r(cr_r_a1:M1_r(cnt)-cr_r_b1,...
                           cr_c_a1:N1_r(cnt)-cr_c_b1);
        else
            cr_r_a1 = fix((M1(cnt)-260)/2) + 2*mod(M1(cnt)-260,2);
            cr_r_b1 = fix((M1(cnt)-260)/2) - mod(M1(cnt)-260,2);
            cr_c_a1 = fix((N1(cnt)-500)/2) + 2*mod(N1(cnt)-500,2);
            cr_c_b1 = fix((N1(cnt)-500)/2) - mod(N1(cnt)-500,2);
            LP1_cr = LP1_r(cr_r_a1:M1(cnt)-cr_r_b1,...
                           cr_c_a1:N1(cnt)-cr_c_b1);
        end 
    end     
    LP1_cr_bi = imresize(LP1_cr,2,'bicubic');
    imshow(LP1_cr_bi,[]);
    [M1_bi(cnt),N1_bi(cnt)] = size(LP1_cr_bi);
    
    figure(ob_cnt+5)          % Apply median filter to remove speckle noise 
    LP1_bi = medfilt2(LP1_cr_bi,[5,5]);
    imshow(LP1_bi,[]);

The cropped LP image is:

3a0ar.jpg

Last edited by mesa177 (July 3 2012)

Offline

#38 July 3 2012

mesa177
Member

Re: License Plate Extraction, Processing, and Character Segmentation

For the LP partitioning (regions E for English characters and A for Arabic characters):

% 4 - Dividing LP into 2 Partitions (English and Arabic):
%
% Unlike most countries, the Lebanese LPs are composed of English and
% Arabic segments. There are two formats for an LP: one with aspect ratio
% greater than or equal to 3 and one less than 3. The first format has the
% English segment of the LP followed by the Arabic segment (along the
% horizontal direction). The other format has the English segment above the
% Arabic segment (along vertical direction). So, to enhance operation speed
% and facilitate process of character recognition later on, the LP is
% divided into 2 segments according to its format. Stage 3 of the CS
% operation has already specified a standerdized size for each LP format.
% Thus, LPs with standard size 202 x 902 pixels are of Format 1 while those
% with size 522 x 1002 pixels are of Format 2. Format 1 LPs are divided
% along the vertical direction into two equal segments, while Format 2 LPs
% are divided along the horizontal direction into two equal segments. The
% English segment is noted by "E" while the Arabic segment by "A". Since
% each segment of the Lebanese license plate also contains the word
% "Lebanon" in its respective language, some of the rows in Format 1 LPs
% or some of the columns in Format 2 LPs are eliminated to remove those 
% regions. The standard size of each segment is 117 x 452 in Format 1 and
% 117 x 452 in Format 2 (segments E and A are of equal standard sizes).   
%
% LP Partitioning
    if (a1_LPB(cnt) >= 3)     % LP is of Format 1
        LP1_1 = LP1_bi(20:fix(M1_bi(cnt)*2/3)+2,1:N1_bi(cnt)/2+1); 
        LP1_2 = LP1_bi(fix(M1_bi(cnt)*1/3)+19:M1_bi(cnt),...
                       N1_bi(cnt)/2:N1_bi(cnt));
    else                      % LP is of Format 2
        LP1_1 = LP1_bi(1:fix(M1_bi(cnt)*2/3)+2,1:N1_bi(cnt)/2+1); 
        LP1_2 = LP1_bi(fix(M1_bi(cnt)*1/3):M1_bi(cnt),...
                       N1_bi(cnt)/2:N1_bi(cnt));
    end
    
    figure(ob_cnt+6) 
    subplot(2,1,1)
    imshow(LP1_1,[]);
    subplot(2,1,2)
    imshow(LP1_2,[]);
    [M1_ErA(cnt),N1_ErA(cnt)] = size(LP1_1);

Regions E and A are shown as subplots on the same image:

2ldtuom.jpg

Offline

#39 July 3 2012

mesa177
Member

Re: License Plate Extraction, Processing, and Character Segmentation

For the SCW of regions E and A:

% 5 - SCW Segmentation of Characters:
%
% Each of Format 1 E and Format 1 A or Format 2 E and Format 2 A partitions
% have their characters segmented, starting with statistical thresholding
% SCW segmentation.
%
% SCW segmentation of characters
    figure(ob_cnt+7)
    subplot(2,1,1)
    LP1_ext = horzcat(LP1_1(:,1:4),LP1_1,...
                      LP1_1(:,N1_ErA(cnt)-2:N1_ErA(cnt)));
    LP1_ext = vertcat(LP1_ext(1:8,:),LP1_ext,...
                      LP1_ext(M1_ErA(cnt)-6:M1_ErA(cnt),:));
    [M1_ext(cnt),N1_ext(cnt)] = size(LP1_ext);
    for i = 9:M1_ext-7
        for j = 5:N1_ext-3
            A_SCW = LP1_ext(i-4:i+3,j-2:j+1);
            B_SCW = LP1_ext(i-8:i+7,j-4:j+3);
            mA = mean(mean(A_SCW));
            mB = mean(mean(B_SCW));
            if (mA/mB < TS)
                LP1_SCW_ext(i,j) = 1;
            else
                LP1_SCW_ext(i,j) = 0;
            end
            clear A_SCW B_SCW mA mB
        end
    end
    LP1_SCW1 = LP1_SCW_ext(9:M1_ext-7,5:N1_ext-3);
    imshow(LP1_SCW1,[]);          % Show SCW segmentation for LP E
    clear LP1_ext LP1_SCW_ext M1_ext N1_ext
    subplot(2,1,2)
    LP1_ext = horzcat(LP1_2(:,1:4),LP1_2,...
                      LP1_2(:,N1_ErA(cnt)-2:N1_ErA(cnt)));
    LP1_ext = vertcat(LP1_ext(1:8,:),LP1_ext,...
                      LP1_ext(M1_ErA(cnt)-6:M1_ErA(cnt),:));
    [M1_ext(cnt),N1_ext(cnt)] = size(LP1_ext);
    for i = 9:M1_ext-7
        for j = 5:N1_ext-3
            A_SCW = LP1_ext(i-4:i+3,j-2:j+1);
            B_SCW = LP1_ext(i-8:i+7,j-4:j+3);
            mA = mean(mean(A_SCW));
            mB = mean(mean(B_SCW));
            if (mA/mB < TS)
                LP1_SCW_ext(i,j) = 1;
            else
                LP1_SCW_ext(i,j) = 0;
            end
            clear A_SCW B_SCW mA mB
        end
    end
    LP1_SCW2 = LP1_SCW_ext(9:M1_ext-7,5:N1_ext-3);
    imshow(LP1_SCW2,[]);          % Show SCW segmentation for LP A
    clear LP1_ext LP1_SCW_ext M1_ext N1_ext

The resulting image is:

kb6mgj.jpg

Offline

#40 July 3 2012

mesa177
Member

Re: License Plate Extraction, Processing, and Character Segmentation

For the image inversion of regions E and A:

% 6 - Image Inversion:
%
% Each partition subjected to SCW segmentation is inverted to allow the
% characters to be in black and the background in white.
%
% Image inversion
    figure(ob_cnt+8)
    subplot(2,1,1)
    LP1_in1 = ~LP1_SCW1; 
    imshow(LP1_in1,[]);
    subplot(2,1,2)
    LP1_in2 = ~LP1_SCW2; 
    imshow(LP1_in2,[]);

The resulting image is:

ejhg0n.jpg

Offline

#41 July 3 2012

mesa177
Member

Re: License Plate Extraction, Processing, and Character Segmentation

Before proceeding with the CCA for regions E and A, it is fundamental to find the parameter limits (just as in post # 30). The two parameters at hand are the orientation angle and the height of the character in each region.

The code for detecting the orientation angle limits is:

% Detecting Orientation Angles of Segmented Characters in LP

% This program detects the orientation angle of each of the segmented
% characters five studied license plates. First, the objects in each image
% is labelled with bwlabel (classical approach of connected component
% labeling with 8-connectivity), then the labeled matrix identifying the
% boarders of the license plates is used for calculating the orientation
% angle of the segmented characters,. This is calculated according to the
% equation:
% tan(phi_i) = 2[r_sum(c_sum(rcWi(r,c))]/[r_sum(c_sum(r^2Wi(r,c)) - 
%                                         r_sum(c_sum(c^2Wi(r,c))]  

clear all
clc

ob_cnt = 0;

% Generating Gaussian mask to be used for blurring thresholded picture 
% before performing object labeling

% sig = fix(randn*10);           % Generating gradient of Gaussian masks for filtering
%                                % along x-axis (fx) and y-axis (fy)
% while (sig == 0)||(mod(sig,2)==0)||(abs(sig)>5)               
%       sig = fix(randn*10);     % Ensure that masks formed are odd matrices
% end                            % each of whose size is no greater than 15x15
% sig = abs(sig);                % Sigma should be positive

% After generating several Gaussian masks, best result obtained for sig = 1
sig = 1; 
n = 3*sig;
for i=1:n
    for j=1:n
      g(i,j) = exp(-(i^2+j^2)/2*sig^2);
    end
end

figure(ob_cnt+1)
I1 = imread('image 1.jpg');  % Importing picture of license plate 1
I1 = rgb2gray(I1);
imshow(I1,[]);               % Show grayscale picture
[M1,N1] = size(I1);

figure(ob_cnt+2)
I_bin1 = edge(I1,'canny');   % Performing edge detection with Canny method
imshow(I_bin1,[]);           % Show edge detection

figure(ob_cnt+3)
f1 = conv2(double(I_bin1),double(g));
f1 = f1(1:M1,1:N1);
[W1,num1] = bwlabel(f1,8);   % Labeling with Matlab command bwlabel
imshow(W1,[]);

figure(ob_cnt+4)
% Extracting LP from middle section where expected to be
LP1 = W1(600:910,990:1500);
imshow(LP1,[]);
[M1,N1] = size(LP1);

for i = 1:M1
    for j = 1:N1
        rc_component1(i,j) = i*j*LP1(i,j);
    end
end
for i = 1:M1
    for j = 1:N1
        r2_component1(i,j) = i^2*LP1(i,j);
    end
end
for i = 1:M1
    for j = 1:N1
        c2_component1(i,j) = j^2*LP1(i,j);
    end
end    
phi1 = atand((2*sum(sum(rc_component1)))/...
             (sum(sum(r2_component1))-sum(sum(c2_component1))))

%--------------------------------------------------------------------------

ob_cnt = ob_cnt + 4;

figure(ob_cnt+1)
I2 = imread('image 2.jpg');  % Importing picture of license plate 2
I2 = rgb2gray(I2);
imshow(I2,[]);               % Show grayscale picture
[M2,N2] = size(I2);

figure(ob_cnt+2)
I_bin2 = edge(I2,'canny');   % Performing edge detection with Canny method
imshow(I_bin2,[]);           % Show edge detection

figure(ob_cnt+3)
f2 = conv2(double(I_bin2),double(g));
f2 = f2(1:M2,1:N2);
[W2,num2] = bwlabel(f2,8);   % Labeling with Matlab command bwlabel
imshow(W2,[]);

figure(ob_cnt+4)
% Extracting LP from middle section where expected to be
LP2 = W2(750:1100,900:1650);
imshow(LP2,[]);
[M2,N2] = size(LP2);

for i = 1:M2
    for j = 1:N2
        rc_component2(i,j) = i*j*LP2(i,j);
    end
end
for i = 1:M2
    for j = 1:N2
        r2_component2(i,j) = i^2*LP2(i,j);
    end
end
for i = 1:M2
    for j = 1:N2
        c2_component2(i,j) = j^2*LP2(i,j);
    end
end    
phi2 = atand((2*sum(sum(rc_component2)))/...
             (sum(sum(r2_component2))-sum(sum(c2_component2))))

%--------------------------------------------------------------------------

ob_cnt = ob_cnt + 4;

figure(ob_cnt+1)
I3 = imread('image 3.jpg');  % Importing picture of license plate 3
I3 = rgb2gray(I3);
imshow(I3,[]);               % Show grayscale picture
[M3,N3] = size(I3);

figure(ob_cnt+2)
I_bin3 = edge(I3,'canny');   % Performing edge detection with Canny method
imshow(I_bin3,[]);           % Show edge detection

figure(ob_cnt+3)
f3 = conv2(double(I_bin3),double(g));
f3 = f3(1:M3,1:N3);
[W3,num3] = bwlabel(f3,8);   % Labeling with Matlab command bwlabel
imshow(W3,[]);

figure(ob_cnt+4)
% Extracting LP from middle section where expected to be
LP3 = W3(700:1100,1100:1700);
imshow(LP3,[]);
[M3,N3] = size(LP3);

for i = 1:M3
    for j = 1:N3
        rc_component3(i,j) = i*j*LP3(i,j);
    end
end
for i = 1:M3
    for j = 1:N3
        r2_component3(i,j) = i^2*LP3(i,j);
    end
end
for i = 1:M3
    for j = 1:N3
        c2_component3(i,j) = j^2*LP3(i,j);
    end
end    
phi3 = atand((2*sum(sum(rc_component3)))/...
             (sum(sum(r2_component3))-sum(sum(c2_component3))))

%--------------------------------------------------------------------------

ob_cnt = ob_cnt + 4;

figure(ob_cnt+1)
I4 = imread('image 4.jpg');  % Importing picture of license plate 4
I4 = rgb2gray(I4);
imshow(I4,[]);               % Show grayscale picture
[M4,N4] = size(I4);

figure(ob_cnt+2)
I_bin4 = edge(I4,'canny');   % Performing edge detection with Canny method
imshow(I_bin4,[]);           % Show edge detection

figure(ob_cnt+3)
f4 = conv2(double(I_bin4),double(g));
f4 = f4(1:M4,1:N4);
[W4,num4] = bwlabel(f4,8);   % Labeling with Matlab command bwlabel
imshow(W4,[]);

figure(ob_cnt+4)
% Extracting LP from middle section where expected to be
LP4 = W4(620:1020,1000:1650);
imshow(LP4,[]);
[M4,N4] = size(LP4);

for i = 1:M4
    for j = 1:N4
        rc_component4(i,j) = i*j*LP4(i,j);
    end
end
for i = 1:M4
    for j = 1:N4
        r2_component4(i,j) = i^2*LP4(i,j);
    end
end
for i = 1:M4
    for j = 1:N4
        c2_component4(i,j) = j^2*LP4(i,j);
    end
end    
phi4 = atand((2*sum(sum(rc_component4)))/...
             (sum(sum(r2_component4))-sum(sum(c2_component4))))

%--------------------------------------------------------------------------

ob_cnt = ob_cnt + 4;

figure(ob_cnt+1)
I5 = imread('image 5.jpg');  % Importing picture of license plate 5
I5 = rgb2gray(I5);
imshow(I5,[]);               % Show grayscale picture
[M5,N5] = size(I5);

figure(ob_cnt+2)
I_bin5 = edge(I5,'canny');   % Performing edge detection with Canny method
imshow(I_bin5,[]);           % Show edge detection

figure(ob_cnt+3)
f5 = conv2(double(I_bin5),double(g));
f5 = f5(1:M5,1:N5);
[W5,num5] = bwlabel(f5,8);   % Labeling with Matlab command bwlabel
imshow(W5,[]);

figure(ob_cnt+4)
% Extracting LP from middle section where expected to be
LP5 = W5(600:1100,710:1850);
imshow(LP5,[]);
[M5,N5] = size(LP5);

for i = 1:M5
    for j = 1:N5
        rc_component5(i,j) = i*j*LP5(i,j);
    end
end
for i = 1:M5
    for j = 1:N5
        r2_component5(i,j) = i^2*LP5(i,j);
    end
end
for i = 1:M5
    for j = 1:N5
        c2_component5(i,j) = j^2*LP5(i,j);
    end
end    
phi5 = atand((2*sum(sum(rc_component5)))/...
             (sum(sum(r2_component5))-sum(sum(c2_component5))))
         
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

The code for detecting the height limits is:

% Detecting Aspect Ratios of LP

% This program detects the height of each of the five studied license
% plates. First, the objects in each image is labelled with bwlabel
% (classical approach of connected component labeling with 8-connectivity),
% then the label(s) identifying the boarders of the license plates are
% used to extract the position coordinates. The height is then 
% calculated according to the equation: rmax - rmin + 1. 

clear all
clc

ob_cnt = 0;

% Generating Gaussian mask to be used for blurring thresholded picture 
% before performing object labeling

% sig = fix(randn*10);           % Generating gradient of Gaussian masks for filtering
%                                % along x-axis (fx) and y-axis (fy)
% while (sig == 0)||(mod(sig,2)==0)||(abs(sig)>5)               
%       sig = fix(randn*10);     % Ensure that masks formed are odd matrices
% end                            % each of whose size is no greater than 15x15
% sig = abs(sig);                % Sigma should be positive

% After generating several Gaussian masks, best result obtained for sig = 1
sig = 1; 
n = 3*sig;
for i=1:n
    for j=1:n
      g(i,j) = exp(-(i^2+j^2)/2*sig^2);
    end
end

figure(ob_cnt+1)
I1 = imread('image 1.jpg');  % Importing picture of license plate 1
I1 = rgb2gray(I1);
imshow(I1,[]);               % Show grayscale picture
[M1,N1] = size(I1);

figure(ob_cnt+2)
I_bin1 = edge(I1,'canny');   % Performing edge detection with Canny method
imshow(I_bin1,[]);           % Show edge detection

figure(ob_cnt+3)
f1 = conv2(double(I_bin1),double(g));
f1 = f1(1:M1,1:N1);
[W1,num1] = bwlabel(f1,8);   % Labeling with Matlab command bwlabel
imshow(W1,[]);

figure(ob_cnt+4)
% Extracting LP from middle section where expected to be
imshow(W1(600:910,990:1500),[]);

figure(ob_cnt+5)
% Extracting character from LP
CS1 = W1(660:720,1080:1110);
imshow(CS1,[]);

r1_max = 720; 
r1_min = 660;
h1 = r1_max - r1_min + 1

%--------------------------------------------------------------------------

ob_cnt = ob_cnt + 5;

figure(ob_cnt+1)
I2 = imread('image 2.jpg');  % Importing picture of license plate 2
I2 = rgb2gray(I2);
imshow(I2,[]);               % Show grayscale picture
[M2,N2] = size(I2);

figure(ob_cnt+2)
I_bin2 = edge(I2,'canny');   % Performing edge detection with Canny method
imshow(I_bin2,[]);           % Show edge detection

figure(ob_cnt+3)
f2 = conv2(double(I_bin2),double(g));
f2 = f2(1:M2,1:N2);
[W2,num2] = bwlabel(f2,8);   % Labeling with Matlab command bwlabel
imshow(W2,[]);

figure(ob_cnt+4)
% Extracting LP from middle section where expected to be
imshow(W2(750:1100,900:1650),[]);

figure(ob_cnt+5)
% Extracting character from LP
CS2 = W2(780:880,1170:1210);
imshow(CS2,[]);

r2_max = 880; 
r2_min = 780;
h2 = r2_max - r2_min + 1

%--------------------------------------------------------------------------

ob_cnt = ob_cnt + 5;

figure(ob_cnt+1)
I3 = imread('image 3.jpg');  % Importing picture of license plate 3
I3 = rgb2gray(I3);
imshow(I3,[]);               % Show grayscale picture
[M3,N3] = size(I3);

figure(ob_cnt+2)
I_bin3 = edge(I3,'canny');   % Performing edge detection with Canny method
imshow(I_bin3,[]);           % Show edge detection

figure(ob_cnt+3)
f3 = conv2(double(I_bin3),double(g));
f3 = f3(1:M3,1:N3);
[W3,num3] = bwlabel(f3,8);   % Labeling with Matlab command bwlabel
imshow(W3,[]);

figure(ob_cnt+4)
% Extracting LP from middle section where expected to be
imshow(W3(700:1100,1100:1700),[]);

figure(ob_cnt+5)
% Extracting character from LP
CS3 = W3(785:870,1270:1340);
imshow(CS3,[]);

r3_max = 870; 
r3_min = 785;
h3 = r3_max - r3_min + 1

%--------------------------------------------------------------------------

ob_cnt = ob_cnt + 5;

figure(ob_cnt+1)
I4 = imread('image 4.jpg');  % Importing picture of license plate 4
I4 = rgb2gray(I4);
imshow(I4,[]);               % Show grayscale picture
[M4,N4] = size(I4);

figure(ob_cnt+2)
I_bin4 = edge(I4,'canny');   % Performing edge detection with Canny method
imshow(I_bin4,[]);           % Show edge detection

figure(ob_cnt+3)
f4 = conv2(double(I_bin4),double(g));
f4 = f4(1:M4,1:N4);
[W4,num4] = bwlabel(f4,8);   % Labeling with Matlab command bwlabel
imshow(W4,[]);

figure(ob_cnt+4)
% Extracting LP from middle section where expected to be
imshow(W4(620:1020,1000:1650),[]);

figure(ob_cnt+5)
% Extracting character from LP
CS4 = W4(675:770,1190:1260);
imshow(CS4,[]);

r4_max = 770; 
r4_min = 675;
h4 = r4_max - r4_min + 1

%--------------------------------------------------------------------------

ob_cnt = ob_cnt + 5;

figure(ob_cnt+1)
I5 = imread('image 5.jpg');  % Importing picture of license plate 5
I5 = rgb2gray(I5);
imshow(I5,[]);               % Show grayscale picture
[M5,N5] = size(I5);

figure(ob_cnt+2)
I_bin5 = edge(I5,'canny');   % Performing edge detection with Canny method
imshow(I_bin5,[]);           % Show edge detection

figure(ob_cnt+3)
f5 = conv2(double(I_bin5),double(g));
f5 = f5(1:M5,1:N5);
[W5,num5] = bwlabel(f5,8);   % Labeling with Matlab command bwlabel
imshow(W5,[]);

figure(ob_cnt+4)
% Extracting LP from middle section where expected to be
imshow(W5(600:1100,710:1850),[]);

figure(ob_cnt+5)
% Extracting character from LP
CS5 = W5(815:945,970:1025);
imshow(CS5,[]);

r5_max = 945; 
r5_min = 815;
h5 = r5_max - r5_min + 1

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

An example of a segmented character would be:

4totbm.jpg

Offline

#42 July 3 2012

mesa177
Member

Re: License Plate Extraction, Processing, and Character Segmentation

After determining the CCA parameter limits, it's time to conduct the CCA and character counting on each of the regions E and A:

% 7 - CCA with Object Count:
% 
% With labeling the image segments, the characters can be identified by
% restricting the orientation and height of the objects. 
%
figure(ob_cnt+9)
    % CCA on inverted form of LP SCW segmentation 
    subplot(2,1,1)
    f11 = conv2(double(LP1_in1),double(g));
    f11 = f11(1:M1_ErA(cnt),1:N1_ErA(cnt));
    [W11,num11] = bwlabel(LP1_in1,8);
    imshow(W11,[]);
    subplot(2,1,2)
    f12 = conv2(double(LP1_in2),double(g));
    f12 = f12(1:M1_ErA(cnt),1:N1_ErA(cnt));
    [W12,num12] = bwlabel(LP1_in2,8);
    imshow(W12,[]);
        
    figure(ob_cnt+10)
    subplot(2,1,1)
    cnt11 = 0;
    for k = 1:num11               % Calculate orientation angle
        L1 = zeros(M1_ErA(cnt),N1_ErA(cnt)); 
        [r1,c1,v1] = find(W11==k); 
        label1 = vertcat(r1',c1');
        for i = 1:size(label1,2)
            L1(label1(1,i),label1(2,i)) = W11(label1(1,i),label1(2,i));
            rc_component1(label1(1,i),label1(2,i)) = label1(1,i)*...
                                                     label1(2,i)*...
                                              L1(label1(1,i),label1(2,i));
            r2_component1(label1(1,i),label1(2,i)) = label1(1,i)^2*...
                                               L1(label1(1,i),label1(2,i));
            c2_component1(label1(1,i),label1(2,i)) = label1(2,i)^2*...
                                               L1(label1(1,i),label1(2,i));
        end 
        phi11(k) = atand((2*sum(sum(rc_component1)))/...
                       (sum(sum(r2_component1))-sum(sum(c2_component1))));
        clear L1 r1 c1 v1 label1 rc_component1 r2_component1 c2_component1
    end
    for k = 1:num11              % Calculate height
        L1 = zeros(M1_ErA(cnt),N1_ErA(cnt));
        [r1,c1,v1] = find(W11==k); 
        label1 = vertcat(r1',c1');
        r1_max = max(label1(1,:));
        r1_min = min(label1(1,:));
        h11(k) = r1_max - r1_min + 1;
        clear r1 c1 v1 label1 r1_max r1_min
    end
    LP1_ob1 = zeros(M1_ErA(cnt),N1_ErA(cnt));
    for k = 1:num11              % Retrieve objects with specific 
                                 % orientation angle and height
        if (((phi11(k)+180) > 110)&&((phi11(k)+180) < 165))&&...
           (h11(k) >= 50)
           L1 = zeros(M1_ErA(cnt),N1_ErA(cnt));       
           [r1,c1,v1] = find(W11==k); 
           label1 = vertcat(r1',c1');
           for i = 1:size(label1,2)
               L1(label1(1,i),label1(2,i)) = W11(label1(1,i),label1(2,i));
           end 
           for i = 1:length(label1)
               LP1_ob1(label1(1,i),label1(2,i)) = L1(label1(1,i),label1(2,i));
           end
           cnt11 = cnt11 + 1;
           clear L1 r1 c1 v1 label1
        end  
    end
    imshow(LP1_ob1,[]);
    subplot(2,1,2)
    cnt12 = 0;
    for k = 1:num12               % Calculate orientation angle
        L1 = zeros(M1_ErA(cnt),N1_ErA(cnt)); 
        [r1,c1,v1] = find(W12==k); 
        label1 = vertcat(r1',c1');
        for i = 1:size(label1,2)
            L1(label1(1,i),label1(2,i)) = W12(label1(1,i),label1(2,i));
            rc_component1(label1(1,i),label1(2,i)) = label1(1,i)*...
                                                     label1(2,i)*...
                                              L1(label1(1,i),label1(2,i));
            r2_component1(label1(1,i),label1(2,i)) = label1(1,i)^2*...
                                               L1(label1(1,i),label1(2,i));
            c2_component1(label1(1,i),label1(2,i)) = label1(2,i)^2*...
                                               L1(label1(1,i),label1(2,i));
        end 
        phi12(k) = atand((2*sum(sum(rc_component1)))/...
                       (sum(sum(r2_component1))-sum(sum(c2_component1))));
        clear L1 r1 c1 v1 label1 rc_component1 r2_component1 c2_component1
    end
    for k = 1:num12              % Calculate height
        L1 = zeros(M1_ErA(cnt),N1_ErA(cnt));
        [r1,c1,v1] = find(W12==k); 
        label1 = vertcat(r1',c1');
        r1_max = max(label1(1,:));
        r1_min = min(label1(1,:));
        h12(k) = r1_max - r1_min + 1;
        clear r1 c1 v1 label1 r1_max r1_min
    end
    LP1_ob2 = zeros(M1_ErA(cnt),N1_ErA(cnt));
    for k = 1:num12              % Retrieve objects with specific 
                                 % orientation angle and height
        if (((phi12(k)+180) > 110)&&((phi12(k)+180) < 165))&&...
           (h12(k) >= 50)
           L1 = zeros(M1_ErA(cnt),N1_ErA(cnt));       
           [r1,c1,v1] = find(W12==k); 
           label1 = vertcat(r1',c1');
           for i = 1:size(label1,2)
               L1(label1(1,i),label1(2,i)) = W12(label1(1,i),label1(2,i));
           end 
           for i = 1:length(label1)
               LP1_ob2(label1(1,i),label1(2,i)) = L1(label1(1,i),label1(2,i));
           end
           cnt12 = cnt12 + 1;
           clear L1 r1 c1 v1 label1
        end  
    end
    imshow(LP1_ob2,[]);
    
    figure(ob_cnt+11)
    subplot(2,1,1)
    LP1_C1 = ~LP1_ob1; 
    imshow(LP1_C1,[]);
    subplot(2,1,2)
    LP1_C2 = ~LP1_ob2; 
    imshow(LP1_C2,[]);

The result of the CCA on the inverted regions E and A is:

dhffoo.jpg

After performing the object count (i.e. character count for each region E and A) and re-inverting the image to obtain the original grayscale shades, the following image is obtained:

zwx7nq.jpg

Offline

#43 July 3 2012

mesa177
Member

Re: License Plate Extraction, Processing, and Character Segmentation

For the character box-fitting of the characters on each region E and A:

% 8 - Character Box-Fitting:
%
% The row and column standard deviations are used on each character
% (object) to fit it into a box (character isolation with determined
% boundaries). The number of boxes (characters) is tracked with counter c.
%
% Character box-fitting
    figure(ob_cnt+12)
    R_STD_LP1_1 = std(LP1_C1');
    C_STD_LP1_1 = std(LP1_C1);
    subplot(2,2,1)
    area(R_STD_LP1_1);
    title('Row Standard Deviation of E in LP');
    subplot(2,2,2)
    area(C_STD_LP1_1);
    title('Column Standard Deviation of E in LP');
    R_STD_LP1_2 = std(LP1_C2');
    C_STD_LP1_2 = std(LP1_C2);
    subplot(2,2,3)
    area(R_STD_LP1_2);
    title('Row Standard Deviation of A in LP');
    subplot(2,2,4)
    area(C_STD_LP1_2);
    title('Column Standard Deviation of A in LP');
    
    figure(ob_cnt+13)
    subplot(2,1,1)
    LP1_F1 = zeros(M1_ErA(cnt),N1_ErA(cnt));
    [r1, c1, v1] = find(C_STD_LP1_1>(sum(C_STD_LP1_1)/length(C_STD_LP1_1)));
    label1 = vertcat(r1,c1);
    for i = 1:size(label1,2)
        LP1_F1(:,label1(2,i)) = LP1_C1(:,label1(2,i));
    end 
    imshow(LP1_F1,[]);
    clear r1 c1 v1 label1
    subplot(2,1,2)
    LP1_F2 = zeros(M1_ErA(cnt),N1_ErA(cnt));
    [r1, c1, v1] = find(C_STD_LP1_2>(sum(C_STD_LP1_2)/length(C_STD_LP1_2)));
    label1 = vertcat(r1,c1);
    for i = 1:size(label1,2)
        LP1_F2(:,label1(2,i)) = LP1_C2(:,label1(2,i));
    end 
    imshow(LP1_F2,[]);
    clear r1 c1 v1 label1
    
    figure(ob_cnt+14)
    R_STD_LP1_1up = std(LP1_F1');
    C_STD_LP1_1up = std(LP1_F1);
    subplot(2,2,1)
    area(R_STD_LP1_1up);
    title('Updated Row Standard Deviation of E in LP');
    subplot(2,2,2)
    area(C_STD_LP1_1up);
    title('Updated Column Standard Deviation of E in LP');
    R_STD_LP1_2up = std(LP1_F2');
    C_STD_LP1_2up = std(LP1_F2);
    subplot(2,2,3)
    area(R_STD_LP1_2up);
    title('Updated Row Standard Deviation of A in LP');
    subplot(2,2,4)
    area(C_STD_LP1_2up);
    title('Updated Column Standard Deviation of A in LP');
    
    figure(ob_cnt+15)
    [r1, c1, v1] = find(C_STD_LP1_1up == 0);
    for i = 2:length(c1)
        horz_proj_LP1_1(i) = sum([C_STD_LP1_1up(i-1),C_STD_LP1_1up(i)]);
    end   
    [r2, c2, v2] = find(horz_proj_LP1_1 ~= 0);
    j = 1; % Dummy counter
    for i = c2(1):c2(end)
        CS_LP1_1(j) = c1(i);
        j = j+1;
    end
    [r3, c3, v3] = find(c1 == CS_LP1_1(1));
    CS_LP1_1 = horzcat(c1(c3-1),CS_LP1_1); % Inducing starting line of segmentation
    clear r1 c1 v1 r2 c2 v2 r3 c3 v3 j
    temp = CS_LP1_1;
    clear CS_LP1_1
    j = 2;
    CS_LP1_1(1) = temp(1); % Same starting line of segmentation
    for i = 2:length(temp)-1
        if ((temp(i+1)-temp(i))<15)
            CS_LP1_1(j) = temp(i+1);
        else
            CS_LP1_1(j) = temp(i);
            j = j+1;
        end
    end 
    for i = 2:length(CS_LP1_1)
        subplot(1,length(CS_LP1_1)-1,i-1)
        imshow(LP1_F1(:,CS_LP1_1(i-1):CS_LP1_1(i)),[]); 
    end  
    clear temp horz_proj_LP1_1 j
    
    figure(ob_cnt+16)
    [r1, c1, v1] = find(C_STD_LP1_2up == 0);
    for i = 2:length(c1)
        horz_proj_LP1_2(i) = sum([C_STD_LP1_2up(i-1),C_STD_LP1_2up(i)]);
    end   
    [r2, c2, v2] = find(horz_proj_LP1_2 ~= 0);
    j = 1; % Dummy counter
    for i = c2(1):c2(end)
        CS_LP1_2(j) = c1(i);
        j = j+1;
    end
    [r3, c3, v3] = find(c1 == CS_LP1_2(1));
    CS_LP1_2 = horzcat(c1(c3-1),CS_LP1_2); % Inducing starting line of segmentation
    clear r1 c1 v1 r2 c2 v2 r3 c3 v3 j
    temp = CS_LP1_2;
    clear CS_LP1_2
    j = 2;
    CS_LP1_2(1) = temp(1); % Same starting line of segmentation
    for i = 2:length(temp)-1
        if ((temp(i+1)-temp(i))<15)
            CS_LP1_2(j) = temp(i+1);
        else
            CS_LP1_2(j) = temp(i);
            j = j+1;
        end
    end 
    for i = 2:length(CS_LP1_2)
        subplot(1,length(CS_LP1_2)-1,i-1)
        imshow(LP1_F2(:,CS_LP1_2(i-1):CS_LP1_2(i)),[]); 
    end
    clear temp horz_proj_LP1_2 j

The result of the first row and column standard deviation analysis is:

1zmnypk.jpg

So the updated binary view of regions E and A would be:

zv90ut.jpg

The updated row and column standard deviation analysis is:

244schz.jpg

This would yield the following segmented characters for region E:

2cy35tz.jpg

and for region A:

29vbhhz.jpg

Seeing that the lovely hematology analyzer has finished its 4 hour cleaning cycle, this means I have to get back to work. Will continue this post later, stay tuned :)

Offline

#44 January 8 2014

cristof
Member

Re: License Plate Extraction, Processing, and Character Segmentation

Hi mesa!
Any news about this wonderful project?
:)

Offline

Board footer