先前的博客之中提到要解決車牌字符識別的問題,由於博主在這倆月沒有對車牌識別系統進行進一步的研究。也由於自身的C++語言能力不足。但經過兩個月的語言能力提升,現在返過來解決這個問題。不多少說題外話了。
先提思路,首先字符識別,第一步分爲垂直投影和水平投影如圖一所示。水平投影作用是將鉚釘和邊框的噪聲去掉。同時也是限制其車牌字符的位置(這裏沒有用到垂直投影)。然後使用FindContours尋找外圍輪廓,再採用凸包將其包圍,然後在使用minAreaRect返回最小外接矩形,同時保存在RotatedRect類Vector數組中。Rotated詳細見——非箴勿語的博客:http://blog.csdn.net/a553654745/article/details/45743063。但最小外接矩形的四個頂點並未排序。
川字是車牌之中最容易出現分割錯誤的,同時也很容易將其川字分割成多塊的。首先將每個RotatedRect類的返回的四個頂點值存儲在Point2f的二維數組中。同時將每個RotatedRect類的Center屬性成員存儲在一維數組中,然後根據每個外接矩形的中心點對其排序,再將根據相鄰的每一個外接矩形中心點位置的距離判斷是否爲一個整體。同時也要將每個RotatedRect類的四個頂點進行排序。如圖所示,只需要得到四個頂點的Xmin、Xmax、Ymin、Ymax並將按照如圖二所示排序,則圖像必定會在框定的矩形內。然後根據每個RotatedRect的中心點(center)距離設定一個閾值,根據這個閾值判斷相鄰的兩個或者三個RotatedRect類是否爲一個整體。(本程序是閾值設置爲8個像素值)。如果是一個整體則將按照下圖圖三紅筆所示進行處理,然後將兩個矩形或者多個矩形並在一起成爲一個整體。
圖一 水平投影和垂直投影
其效果圖如下圖四所示,已經能較好的解決這個川字分割的問題。
其程序如下圖所示:
char_sort(char_rects,char_number); //對字符排序 ********************************************原始程序從這裏開始修改
vector < float > x_distance; //用來儲存各個最小外界矩形的中心點
for (int i = 0; i < char_number;i++)
{
x_distance.push_back(char_rects[i].center.x);
}
/*
vector <Mat> char_mat;
for (int i = 0; i<char_rects.size() ;i++ )
{
//char_mat.push_back(Mat(inputImg,char_rects[i].boundingRect())) ;
char_mat.push_back(Mat(img_threshold,char_rects[i].boundingRect())) ;
}
*/
//vector <Mat> char_mat;
vector <Point2f> rect_points; // 這個儲存 最小矩形的 四個頂點。
for (int z = 0; z < char_rects.size(); z++)
{
Point2f vertex[4];
char_rects[z].points(vertex);
for (int i = 0; i < 4; i++)
{
rect_points.push_back(vertex[i]);
}
}
int rect_p_number = rect_points.size();
float x_min[20];
float x_max[20];
float y_min[20];
float y_max[20]; //用來存儲座標點的最大值和最小值;
for (int z = 0; z < char_rects.size();z++)
{
float min_x = rect_points[z * 4 ].x;
float min_y = rect_points[z * 4 ].y;
float max_x = 0;
float max_y = 0;
for (int w =0; w < 4;w++)
{
min_x = min_x < rect_points[z * 4 + w].x ? min_x : rect_points[z * 4 + w].x;
max_x = max_x > rect_points[z * 4 + w].x ? max_x : rect_points[z * 4 + w].x;
min_y = min_y < rect_points[z * 4 + w].y ? min_y : rect_points[z * 4 + w].y;
max_y = max_y > rect_points[z * 4 + w].y ? max_y : rect_points[z * 4 + w].y;
}
x_min[z] = min_x;
x_max[z] = max_x;
y_min[z] = min_y;
y_max[z] = max_y;
}// 得出 最大值和最小值 //這的最大最小值數組個數 必須是一個變量
vector <Point2f> real_points; //對反饋四個頂點的值進行排序
for (int z = 0; z < char_rects.size(); z++)
{
Point2f a, b, c, d;
a.x = x_min[z];
a.y = y_max[z];
b.x = x_min[z];
b.y = y_min[z];
c.x = x_max[z];
c.y = y_min[z];
d.x = x_max[z];
d.y = y_max[z];
real_points.push_back(a);
real_points.push_back(b);
real_points.push_back(c);
real_points.push_back(d);
}
vector <Point2f> conbine;
int flag1 = 0; //這是合併的標誌,每一次進行合併的時候,進行加1;
int center_number = 0;
for (int center_number = 0; center_number < 5; center_number++) // 這裏爲什麼是要是char_rects.size()-1呢?是因爲這裏因爲這個要第二個與第一個比較,所以最後一個不能再加上1與之比較; //這裏確定的一點是 我們只考慮前面三個輪廓
{
int distanst = x_distance[center_number + 1] - x_distance[center_number];
int distanst2 = x_distance[center_number + 2] - x_distance[center_number + 1];
if (distanst <= 8 && distanst2 >= 8 )
{
conbine.push_back(real_points[center_number * 4]);
conbine.push_back(real_points[center_number * 4 + 1]);
conbine.push_back(real_points[center_number * 4 + 6]);
conbine.push_back(real_points[center_number * 4 + 7]);
center_number +=1;
flag1 += 1;
}
if (distanst2 <= 8 && distanst2 <= 8)
{
conbine.push_back(real_points[center_number * 4]);
conbine.push_back(real_points[center_number * 4 + 1]);
conbine.push_back(real_points[center_number * 4 + 10]);
conbine.push_back(real_points[center_number * 4 + 11]);
center_number += 2;
flag1 += 2;
}
else
{
conbine.push_back(real_points[center_number * 4]);
conbine.push_back(real_points[center_number * 4 + 1]);
conbine.push_back(real_points[center_number * 4 + 2]);
conbine.push_back(real_points[center_number * 4 + 3]);
}
}
int s = (conbine.size())/4 +flag1 ;
int s1 = (real_points.size())/ 4;
for (; s < s1 ; s++)
{
conbine.push_back(real_points[s * 4]);
conbine.push_back(real_points[s * 4 + 1]);
conbine.push_back(real_points[s * 4 + 2]);
conbine.push_back(real_points[s * 4 + 3]);
}
/* int do_number = 0;
do
{
int i = do_number;
int distanst;
if (i < char_rects.size()-1)
{
distanst = x_distance[i + 1] - x_distance[i];
if (x_distance[i+1])
{
conbine.push_back(real_points[i * 4]);
conbine.push_back(real_points[i * 4 + 1]);
conbine.push_back(real_points[i * 4 + 6]);
conbine.push_back(real_points[i * 4 + 7]);
flag1++;
}
else
{
conbine.push_back(real_points[i * 4]);
conbine.push_back(real_points[i * 4 + 1]);
conbine.push_back(real_points[i * 4 + 2]);
conbine.push_back(real_points[i * 4 + 3]);
}
}
else if (i >= char_rects.size()-1)
{
conbine.push_back(real_points[i * 4]);
conbine.push_back(real_points[i * 4 + 1]);
conbine.push_back(real_points[i * 4 + 2]);
conbine.push_back(real_points[i * 4 + 3]);
}
do_number++;
} while (do_number < char_rects.size());
*/
Mat char_img;
vector <Mat> char_mat;
int char_rects_conbin_number = char_rects.size() - flag1;
for (int i = 0; i <char_rects_conbin_number; i++)
//for (int i = 0; i < 7; i++)
{
// char_img = inputImg(Range(conbine[i * 4+1].x, conbine[i * 4+2].x), Range(conbine[i *4+1].y, conbine[i * 4].y));
char_img = inputImg(Range(conbine[i * 4 + 1].y, conbine[i * 4].y), Range(conbine[i * 4 + 1].x, conbine[i * 4 + 2].x));//首先這個
char_mat.push_back(char_img);
}