Professional Documents
Culture Documents
Nhan Dang Bien So Xe
Nhan Dang Bien So Xe
i
MỤC LỤC
ii
TÀI LIỆU THAM KHẢO.......................................................................................15
PHỤ LỤC................................................................................................................. 16
iii
DANH MỤC CÁC HÌNH VẼ
HÌNH 1-1 QUẢN LÝ BÃI GIỮ XE BẰNG NHẬN DẠNG BIỂN SỐ..................2
HÌNH 1-2 GIAO DIỆN CỦA VISUAL STUDIO 2015.........................................4
HÌNH 2-1 ẢNH MÀU, ẢNH MỨC XÁM VÀ ẢNH NHỊ PHÂN.........................7
HÌNH 2-2 CÁC BƯỚC XỬ LÝ ẢNH CƠ BẢN....................................................7
HÌNH 2-3 MỘT SỐ LOẠI BIỂN SỐ XE THÔNG DỤNG....................................9
HÌNH 2-4 CÁC BƯỚC PHÁT HIỆN VÙNG CHỨA BIỂN SỐ XE ...................10
HÌNH 3-1 GIAO DIỆN CHƯƠNG TRÌNH CHÍNH............................................12
HÌNH 3-2 CÔNG CỤ DEBUG................................................................................12
HÌNH 3-3 KẾT QUẢ NHẬN DẠNG BIỂN SỐ.....................................................13
HÌNH 3-4 CÁC LOẠI BIỂN KHÔNG NHẬN DẠNG ĐỦ KÍ TỰ......................13
iv
DANH MỤC CÁC TỪ VIẾT TẮT
v
ĐỒ ÁN 3
Trang 1/33
Ứng dụng nhận dạng biển số xe là ứng dụng có khả năng phân tích hình ảnh và xác
định biển số xe từ các hình ảnh chụp được từ các thiết bị thu hình. Nguồn hình ảnh
cho ứng dụng có rất nhiều. Và phát triển, hình ảnh được trực tiếp thu nhận từ
camera. Trong đề tài chỉ dừng lại ở mức xác định được biển số xe (xác định các
chữ) từ các bức ảnh.
Có nhiều cách thức khác nhau để phân loại các ứng dụng nhận dạng biển số
xe. Một trong những cách đơn giản là phân loại ứng dụng nhận dạng biển số xe
thông qua mục đích sử dụng. Có thể chia ứng dụng nhận dạng biển số xe thành hai
loại sau:
*Loạ i 1: Giớ i hạ n vù ng nhìn:
-Đầu vào: Ảnh thu trực tiếp từ các thiết bị ghi nhận ảnh kỹ thuật số. Ảnh được ghi
nhận thường chỉ giới hạn trong vùng có biển số xe.
-Nguyên lý hoạt động: Các phương tiện giao thông phải chạy với một tốc độ đủ
chậm để máy ghi nhận hình ảnh co thể thu được ảnh vùng biển số xe.
*Loại 2: Không giới hạn vùng nhìn:
-Đầu vào: Ảnh đầu vào thu được từ các thiết bị ghi hình tự động, không phụ thuộc
vào góc độ, các đối tượng xung quanh, ảnh không cần bắt buộc chỉ chụp vùng chứa
biển số xe, mà có thể ảnh tổng hợp như chứa them các đối tượng như người, cây,
đường phố.., miễn là vùng biển số xe phải đủ rõ để có thể thực hiện nhận dạng được
các ký tự trong vùng đó.
-Nguyên lý hoạt động: Do đặc tính không giới hạn vùng nhìn mà ảnh đầu vào có thể
thu được từ một thiết bị ghi hình (camara, máy ảnh…). Và do đó, công việc đầu tiên
là dò tìm trong ảnh, để xác định đúng vùng nào là biển số xe. Sau đó, thực hiện tách
vùng và nhận dạng. Vì không phụ thuộc vào hình ảnh thu được nên có thể dùng ứng
dụng tại nhiều nơi.
Ảnh là mảng số thực hai chiều ( I m ,n) , có kích thước (MxN), trong đó mỗi giá trị
( I m , n) (tại một điểm ảnh), biểu thị mức xám của ảnh tại vị trí ( m ,n ) tương
ứng.Một ảnh là ảnh nhị phân nếu giá trị ( I m ,n) bằng 0 hoặc 1.
Điểm ả nh (Pixel) là mộ t phầ n tử củ a ả nh số tạ i toạ độ (x, y) vớ i độ xá m hoặ c
mà u nhấ t định. Kích thướ c và khoả ng cá ch giữ a cá c điểm ả nh đó đượ c chọ n
thích hợ p sao cho mắ t ngườ i cả m nhậ n sự liên tụ c về khô ng gian và mứ c xá m
(hoặ c mà u) củ a ả nh số gầ n như ả nh thậ t. Mỗ i phầ n tử trong ma trậ n đượ c gọ i là
mộ t phầ n tử ả nh.
Mứ c xá m: Là kết quả củ a sự biến đổ i tương ứ ng 1 giá trị độ sá ng củ a 1 điểm
ả nh vớ i 1 giá trị nguyên dương. Thô ng thườ ng nó xá c định trong [0, 255] tuỳ
thuộ c và o giá trị mà mỗ i điểm ả nh đượ c biểu diễn. Cá c thang giá trị mứ c xá m
thô ng thườ ng: 16, 32, 64, 128, 256 (Mứ c 256 là mứ c phổ dụ ng. Lý do: từ kỹ
thuậ t má y tính dù ng 1 byte (8 bit) để biểu diễn mứ c xá m. Mứ c xá m dù ng 1 byte
biểu diễn: 28 =256 mứ c, tứ c là từ 0 đến 255).
2.1.2 Các cách phân loại ảnh
Ả nh nhị phâ n: Giá trị xá m củ a tấ t cả cá c điểm ả nh chỉ nhậ n giá trị 1 hoặ c 0 như
vậ y mỗ i điểm ả nh trong ả nh nhị phâ n đượ c biểu diễn bở i 1 bit. Ả nh xá m: Giá trị
xá m nằ m trong [0, 255] như vậ y mỗ i điểm ả nh trong ả nh nhị phâ n đượ c biểu
diễn bở i 1 byte.
Ảnh màu:
-Hệ màu RGB:
Mộ t pixel đượ c biểu diễn bằ ng 3 giá trị (R, G, B) trong đó R, G, B là mộ t giá trị
xá m và đượ c biểu biểu diễn bằ ng 1 byte. Khi đó ta có mộ t ả nh 24 bits.
P(x, y) = (R, G, B)
-Hệ mà u CMY: là phầ n bù củ a hệ mà u RGB, thườ ng đượ c dù ng trong má y in.
(C, M, Y) = (1, 1, 1) – (R, G, B)
Hay C+R=M+G=Y+B=1
-Hệ mà u CMYK: trong đó K là độ đậ m nhạ t củ a mà u
K= min(C, M, Y)
P(x, y) = (C-K, M-K, V-K, K).
Hình 2-1 Ảnh màu, ảnh mức xám và ảnh nhị phân
thỏa mãn tích chất đó là ký tự. Chú ý số ký tự trên biển số xe là từ 6 đến 10 ký tự. ở
nước ta chỉ có số ký tự trên mỗi biền số xe nằm trong khoảng 6 đến 9 ký tự.
-Khi ta tiến hành phân ngưỡng sẽ làm hiện rõ vùng biển số, trong giai đoạn này
ta có thể sử dụng các phương pháp phát hiện biên.
Bước 4: Tìm đường bao đối đượng
-Khi có ảnh thu được ở bước 3 chúng ta tiến hành tìm các vùng biên là đối tượng
riêng để trích các vùng và lấy thông số của các vùng như là tọa độ điểm của các
cạnh, diện tích của vùng.
Bước 5: Tách vùng biển số
-Tìm đường bao đối tượng với tiêu chí tỉ lệ 3.5 W H 4.5 hoặ c 0.8 W H 1.4 để
tìm ra nhữ ng vù ng có thể là biển số nhấ t.
-Tiến hà nh cắ t cá c vù ng có thể là biển số nhấ t trên ả nh để là m nguồ n cho giai
đoạ n cắ t ký tự để là m mẫ u cho cá c quá trình nhậ n dạ ng ký tự .
2.2.4 Nhận dạng các kí tự
Nhậ n dạ ng ký tự quang họ c (OCR) là loạ i phầ n mềm má y tính đượ c tạ o ra để
chuyển cá c hình ả nh củ a chữ viết tay hoặ c chữ đá nh má y (thườ ng đượ c quét
bằ ng má y scanner) thà nh cá c vă n bả n tà i liệu.
Trong đề tà i nà y chú ng ta sử dụ ng Tesseract OCR để nhậ n dạ ng cá ckí tự chữ và
số trong biển số xe.
Kết quả nhận dạng chúng ta có thể thấy được là khá chính xác. Tuy nhiên vẫn có
một số biển số không nhận dạng được hoặc bị mất kí tự do các nguyên nhân sau:
-Ký tự không rõ và ký tự bị mờ từng phần cũng làm cho quá trình tìm đối tượng sẽ
phát hiện ra nhiều đối tượng mà không phát hiện ra vùng các chữ số.
-Chữ bị bóng sáng do kính lắp hoặc bị đèn chiếu làm nhòe.
-Ảnh bị che mất một phần nhỏ làm mất đi một phần ký tự hoặc ký tự dính liền với
đường viền của biển làm quá trình tìm đối tượng nhầm chữ số và viền của biển là
một đối tượng.
-Ảnh có nhiều nhiễu không rõ, nhiều nhiễu sẽ làm các ký tự gần nhau sẽ được tính
gần như là một đối tượng.
Ngoài ra, chương trình cũng không nhận dạng dược các loại biển nền đỏ (xanh) chữ
trắng.
[2] https://www.visualstudio.com/
[3] http://www.emgu.com/wiki/index.php/Documentation
PHỤ LỤC
*Code FindContours:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using Emgu.CV;
using Emgu.CV.Structure;
namespace Auto_parking
{
class FindContours
{
public int count = 0;
/// <summary>
/// Method used to process the image and set the output result images.
/// </summary>
/// <param name="colorImage">Source color image.</param>
/// <param name="thresholdValue">Value used for thresholding.</param>
/// <param name="processedGray">Resulting gray image.</param>
/// <param name="processedColor">Resulting color image.</param>
public int IdentifyContours(Bitmap colorImage, int thresholdValue, bool
invert, out Bitmap processedGray, out Bitmap processedColor, out List<Rectangle>
list)
{
List<Rectangle> listR = new List<Rectangle>();
#region Conversion To grayscale
Image<Gray, byte> grayImage = new Image<Gray, byte>(colorImage);
//grayImage = grayImage.Resize(400, 400,
Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);
#endregion
////grayImage = grayImage.ThresholdBinary(new
Gray(grayImage.GetAverage().Intensity / 2.5), new Gray(255));
// Contour<Point> contours =
grayImage.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_C
HAIN_APPROX_SIMPLE, Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_LIST,
storage);
// while (contours != null)
// {
// }
// contours = contours.HNext;
// }
// for (int i = 0; i < count; i++)
// {
// for (int j = i + 1; j < count; j++)
// {
// if( (listR[j].X < (listR[i].X + listR[i].Width) && listR[j].X >
listR[i].X)
// && (listR[j].Y < (listR[i].Y + listR[i].Width) && listR[j].Y >
listR[i].Y) )
// {
// listR.RemoveAt(j);
// count--;
// j --;
// }
// else if( (listR[i].X < (listR[j].X + listR[j].Width) && listR[i].X >
listR[j].X)
// && (listR[i].Y < (listR[j].Y + listR[j].Width) && listR[i].Y >
listR[j].Y))
// {
// listR.RemoveAt(i);
// count--;
// i--;
// break;
// }
// }
// }
//}
#endregion
//}
//List<Rectangle> list_best = null;
Rectangle[] li = new Rectangle[9];
Image<Bgr, byte> color_b = new Image<Bgr, byte>(colorImage); ;
Image<Gray, byte> src_b = grayImage.Clone();
Image<Gray, byte> bi_b = bi.Clone();
Image<Bgr, byte> color2;
Image<Gray, byte> src;
Image<Gray, byte> bi2;
int c = 0, c_best = 0;
//IntPtr a = color_b.Ptr;
//CvInvoke.cvReleaseImage(ref a);
for (double value = 0; value <= 127; value += 3)
{
for (int s = -1; s <= 1 && s + value != 1; s += 2)
{
color2 = new Image<Bgr, byte>(colorImage);
//src = grayImage.Clone();
bi2 = bi.Clone();
listR.Clear();
//list_best.Clear();
c = 0;
double t = 127 + value * s;
src = grayImage.ThresholdBinary(new Gray(t), new Gray(255));
Contour<Point> contours =
src.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_
APPROX_SIMPLE, Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_LIST, storage);
while (contours != null)
{
contours = contours.HNext;
}
}
//IntPtr a = color_b.Ptr;
//CvInvoke.cvReleaseImage(ref a);
double avg_h = 0;
double dis = 0;
for (int i = 0; i < c; i++)
{
avg_h += listR[i].Height;
for (int j = i + 1; j < c; j++)
{
if ((listR[j].X < (listR[i].X + listR[i].Width) && listR[j].X >
listR[i].X)
&& (listR[j].Y < (listR[i].Y + listR[i].Width) && listR[j].Y >
listR[i].Y))
{
//avg_h -= listR[j].Height;
listR.RemoveAt(j);
c--;
j--;
}
else if ((listR[i].X < (listR[j].X + listR[j].Width) && listR[i].X >
listR[j].X)
&& (listR[i].Y < (listR[j].Y + listR[j].Width) && listR[i].Y >
listR[j].Y))
{
avg_h -= listR[i].Height;
listR.RemoveAt(i);
c--;
i--;
break;
}
}
}
avg_h = avg_h / c;
for (int i = 0; i < c; i++)
{
dis += Math.Abs(avg_h - listR[i].Height);
}
count = c_best;
grayImage = src_b;
color = color_b;
bi = bi_b;
listR.Clear();
for (int i = 0; i < li.Length; i++)
{
if (li[i].Height != 0) listR.Add(li[i]);
}
#endregion
Emgu.CV.CvEnum.ADAPTIVE_THRESHOLD_TYPE.CV_ADAPTIVE_THRES
H_MEAN_C, Emgu.CV.CvEnum.THRESH.CV_THRESH_BINARY, 21, 2);
grayImage = grayImage.Dilate(3);
grayImage = grayImage.Erode(3);
return d;
}
private double cout_avg_new(Image<Gray, byte> src)
{
double d = 0;
List<Rectangle> lsR = new List<Rectangle>();
Image<Gray, byte> grayImage = new Image<Gray, byte>(src.Width,
src.Height);
Emgu.CV.CvEnum.ADAPTIVE_THRESHOLD_TYPE.CV_ADAPTIVE_THRES
H_MEAN_C, Emgu.CV.CvEnum.THRESH.CV_THRESH_BINARY, 21, 2);
grayImage = grayImage.Dilate(3);
grayImage = grayImage.Erode(3);
{
m++;
min += value;
}
else
{
M++;
max += value;
}
}
T0 = (min / m + max / M) / 2;
} while (T - T0 > 1 || T0 - T > 1);
d += (double)T0 / (double)lsR.Count;
}
return d;
}
int c = 0, c_best = 0;
for (double value = min; value <= max; value += 0.1)
{
Contour<Point> contours =
src.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_
APPROX_SIMPLE, Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_LIST, storage);
while (contours != null)
{
contours = contours.HNext;
}
for (int i = 0; i < c; i++)
{
for (int j = i + 1; j < c; j++)
{
if ((listR[j].X < (listR[i].X + listR[i].Width) && listR[j].X >
listR[i].X)
&& (listR[j].Y < (listR[i].Y + listR[i].Width) && listR[j].Y >
listR[i].Y))
{
listR.RemoveAt(j);
c--;
j--;
}
else if ((listR[i].X < (listR[j].X + listR[j].Width) && listR[i].X >
listR[j].X)
&& (listR[i].Y < (listR[j].Y + listR[j].Width) && listR[i].Y >
listR[j].Y))
{
listR.RemoveAt(i);
c--;
i--;
break;
}
}
}
}
if (c <= 8 && c > c_best)
{
list_best = listR;
c_best = c;
if (c == 8)
{
color_out = color2;
bi_out = bi2;
list_out = list_best;
count = c_best;
return src;
}
}
}
color_out = color2;
bi_out = bi2;
list_out = list_best;
count = c_best;
return src;
}
}
}