자동차 번호판 문자 절단 (1)

18029 단어
요약: 우리 나라 의 표준 번호판 은 너비 45cm, 높이 15cm 로 통 일 된 크기 로 알려 져 있다.자동차 번호판 의 단일 문자 폭 은 45mm 이 고 그 중에서 첫 번 째 문자 의 공간 은 좌우 로 비 어 있 는 공간 을 포함 하 며 두 번 째 문자 와 세 번 째 문자 사이 의 간격 은 34mm 이 고 다른 문자 의 간격 은 12mm 이다.문자 의 총 수 는 7 개 이 고 한 글자 의 너 비 는 자동차 번호판 의 10% 를 차지한다.이런 정보 가 있 으 면 자동차 번호판 문자 의 절단 알고리즘 공식 을 얻 을 수 있다.
 
 
  

#include #include #include #include using namespace std; #define T 27                            //判断一行是不是车牌有效信息的阈值 #define T1                             //判断一列是不是车牌有效信息的阈值 #define S(image,x,y) ((uchar*)(image->imageData + image->widthStep*(y)))[(x)] //S(image,x,y)指该图像(x,y)像素点的像素值,[(x)]是数组,类似于a[i] IplImage *pImgSrc;                       //源图像 IplImage *pImgSrc1 = NULL;        //灰度图 IplImage *pImgSrc2 = NULL;        //高斯滤波后的图 IplImage *pImgSrc3 = NULL;        //边缘检测后的图  IplImage *pImgSrc4 = NULL;        //感兴趣的图片 IplImage *pImgSrc5 = NULL;        //归一化的灰度图 int i, j; int r_start, r_end;               //用来记录车牌开始,结束行 int c_start, c_end;              //用来记录车牌开始,结束列 int row[120];                     //row[]存放含有有效车牌信息的第j行,把所有有效行放一个数组里面 int col[340];                      //存放每个字符双边界(列)的位置 int k = 0;                           //含有有效车牌信息的行数 int CWidth = 45;               //每个字符的宽度(我国的标准车牌有统一的大小,即宽度为45cm,高度为15cm。车牌上单个字符宽45mm) int Space = 12;                  //字符之间的间隙(第2字符与第3字符之间的间隙为34mm,其他字符间隙为12mm。) int reWidth = 410;  //410是感兴趣图像的宽度 int reHeight = 85; //85是感兴趣的高度
 
  void UpAndDown(IplImage *src_son_row);//定义一个子函数,找到图片中含有车牌有效信息的上下边界 
  
 
  void LeftAndRight(IplImage *src_son_col);  //有效信息的左边界和右边界 
  

void find_ROI(IplImage *before_ROI, IplImage *after_ROI);//               

void cut_and_drawLine(IplImage *befour_cut_image);//                ,      ;
 
  void showChar(IplImage *showChar);//显示所分割出来的字符

void main()
{
pImgSrc = cvLoadImage("004.bmp", -1);
pImgSrc2 = cvCreateImage(cvGetSize(pImgSrc), IPL_DEPTH_8U, 1);//创建一副8位无符型单通道的图片,大小和pImgSrc相同
pImgSrc1 = cvCreateImage(cvGetSize(pImgSrc), IPL_DEPTH_8U, 1);//同上
pImgSrc3 = cvCreateImage(cvGetSize(pImgSrc), IPL_DEPTH_8U, 1);//同上
cvCvtColor(pImgSrc, pImgSrc1, CV_RGB2GRAY);                             // 将彩图转化为灰度图,储存在pImgSrc1中;
cvSmooth(pImgSrc1, pImgSrc2, CV_GAUSSIAN, 3, 0, 0);                 //高斯滤波
cvCanny(pImgSrc2, pImgSrc3, 100, 200, 3);                                     //二值化
cvDilate(pImgSrc3, pImgSrc3, 0, 1);
cvErode(pImgSrc3, pImgSrc3, 0, 1);
cvNamedWindow("cvcanny", 1);
cvShowImage("cvcanny", pImgSrc3);

r_start = 0;
r_end = 0;
c_start = 0;
c_end = 0;
cout << "像素的行数为:" << pImgSrc3->height << endl;
cout << "像素的列数为:" << pImgSrc3->width << endl;

UpAndDown(pImgSrc3);                     //找到图片中含有车牌有效信息的上边界和下边界
LeftAndRight(pImgSrc3);                    //找到图片中含有车牌有效信息的最左边界和右边界

find_ROI(pImgSrc2, pImgSrc4);        //找到图片中只含有目标区域的部分

pImgSrc5 = cvCreateImage(cvSize(reWidth, reHeight), IPL_DEPTH_8U, 1);
cvResize(pImgSrc4, pImgSrc5, CV_INTER_LINEAR);               //线性插值
cvNamedWindow("感兴趣图像的宽度与高度", 1);
cvShowImage("感兴趣图像的宽度与高度", pImgSrc5);

cut_and_drawLine(pImgSrc5);                 //对含有车牌有效信息的图片分割出字符,并画出分割线
showChar(pImgSrc5);                            //显示出所有分割出来的字符
cvReleaseImage(&pImgSrc5);
}
void UpAndDown(IplImage *src_son_row) {

//判断每行是不是含有车牌信息的行是通过查看黑点白点变化的次数来确定的

for (j = 0; j < src_son_row->height; j++)
//遍历整幅图的行和列,寻找包含车牌信息的行数
{
int count = 0;                                       //  count/2  记录每行白点(水平的白线看做一个点)的个数
for (i = 0; i < src_son_row->width; i++)
{
if (S(src_son_row, i, j) != S(src_son_row, i + 1, j))  //统计行跳数
count++;
if (count > T)                              //把含有车牌有效信息的行j存放到row[k]
{
row[k] = j;
k++;                                  //记录含有有效车牌信息的行数
break;
}
}
}
cout << "有效行k值为:" << k << endl;
for (i = 0; i //从上边开始,3行连续时认为是起始行
{
if ((row[i] == row[i + 1] - 1) && (row[i + 1] == row[i + 2] - 1)) {
r_start = row[i];
// cout<break;
}
}
cout << "the start row:" << r_start << endl;
cvLine(pImgSrc1, cvPoint(0, r_start), cvPoint(pImgSrc->width, r_start), cvScalar(255, 0, 0), 1, 8, 0);
cvNamedWindow("上画线", 1);

cvShowImage("上画线", pImgSrc1);


for (i = k - 1; i > r_start; i--)     //从下边开始,3行连续时认为是起始行
{
if ((row[i] == row[i - 1] + 1) && (row[i - 1] == row[i - 2] + 1)) {
r_end = row[i];
break;
}
}
cout << "the end row:" << r_end << endl;
cvLine(pImgSrc1, cvPoint(0, r_end), cvPoint(pImgSrc->width, r_end), cvScalar(255, 0, 0), 1, 8, 0);
cvNamedWindow("上下画线", 1);
cvShowImage("上下画线", pImgSrc1);
}

void LeftAndRight(IplImage *src_son_col) {
//判断每列是不是含有车牌有效信息是查看每列中含有白点像素的个数
bool flag = false;
for (i = 5; iwidth; i++)         //找到左列开始,i的大小可以根据运行效果来更改
{
int count = 0;
for (j = r_start; j{
if (S(src_son_col, i, j) == 255)
count++;
if (count>T1)
{
c_start = i;
flag = true;
break;
}
}
if (flag) break;
}
cout << "the start col:" << c_start << endl;
cvLine(pImgSrc1, cvPoint(c_start, r_start), cvPoint(c_start, r_end), cvScalar(255, 0, 0), 1, 8, 0);
cvNamedWindow("左画线", 1);
cvShowImage("左画线", pImgSrc1);

flag = false;
for (i = src_son_col->width - 10; i>c_start; i--)          
//找到右列开始
{
int count = 0;
for (j = r_start; j{
if (S(src_son_col, i, j) == 255)
count++;
if (count>T1)
{
c_end = i;
flag = true;
break;
}
}
if (flag) break;
}
cout << "the end col:" << c_end << endl;
cvLine(pImgSrc1, cvPoint(c_end, r_start), cvPoint(c_end, r_end), cvScalar(255, 0, 0), 1, 8, 0);
cvNamedWindow("左右画线", 1);
cvShowImage("左右画线", pImgSrc1);
}

void find_ROI(IplImage *before_ROI, IplImage *after_ROI) {
CvRect ROI_rect;                
//获得图片感兴趣区域
ROI_rect.x = c_start;//用来记录车牌开始的列
ROI_rect.y = r_start;//用来记录车牌开始的行
ROI_rect.width = c_end - c_start;
ROI_rect.height = r_end - r_start;
//设置ROI区域
cvSetImageROI(pImgSrc1, ROI_rect);
pImgSrc4 = cvCreateImage(cvSize(ROI_rect.width, ROI_rect.height), IPL_DEPTH_8U, 1);
cvCopy(pImgSrc1, pImgSrc4);//ROI区域拷贝
cvResetImageROI(pImgSrc1);//释放ROI区域
}

void cut_and_drawLine(IplImage *befour_cut_image) {
//得到每个字符的双边界
//只看水平方向
for (i = 0; i<7; i++)
{
switch (i) {
case 0:                                          //第一个字符名占45个像素
case 1:                                          
col[i * 2] = i*CWidth + i*Space;
cout << col[i * 2] << endl;
col[i * 2 + 1] = (i + 1)*CWidth + i*Space;
cout << col[i * 2 + 1] << endl;
break;                                       //第二个与第三个字符
之间有个点宽度是34个像素
 
  
		case 2:
			//2~6            45   
		case 3:
		case 4:
		case 5:
		case 6:
			col[i * 2] = i*CWidth + i*Space + 27;
			cout << col[i * 2] << endl;
			col[i * 2 + 1] = (i + 1)*CWidth + i*Space + 27;
			cout << col[i * 2 + 1] << endl;
			break;
		}
	}
	for (i = 0; i<15; i++)        //         
	{
		cvLine(befour_cut_image, cvPoint(col[i], 0), cvPoint(col[i], reHeight), cvScalar(255, 0, 0), 1, 8, 0);
	}
}
void showChar(IplImage *showChar) {
	cvNamedWindow("      ", 1);//    “      ”  ,      
	cvShowImage("      ", showChar);// “      ”       
	cvWaitKey(0);
}

 
  
             ,             (0,45)(57,102) (141,186)  (198,243)  (255,300)  (312,357) (369,414)
         
                    ,         ,    ,                        。
 
            ,                     ,                   ,       ,       ( )。

좋은 웹페이지 즐겨찾기