车牌识别算法实践(二):基础算法

本篇将涉及到的一些基础算法集中介绍一下。由于以贴代码为主,有些算法可能只提个名字,有些算法的原理可能会一两句话带过。

原来的VLPR工程中车牌识别的一些组件是分成好几个类的,现将它们全部塞到一个类CPlate中。这样虽有违C++ OOP的精神,但 “咣当”一下子将Plate.h复制过来感觉是很爽滴:

#pragma once

const int W = 512;				// 预定义的归一化图像宽度
const int M = 16;				// 预定义最小图像块单元的宽度
const int N = 64;				// 预定义最小图像块单元的高度
const int I	= 12;				// 车牌定位扫描线之间的间隔
const int WW = 64;				// 最大字符宽度
const int HH = 116;				// 最大字符高度
const int WP = 384;				// 透视变换的车牌宽度
const int HP = 116;				// 透视变换的车牌高度
const int NN = 30;				// 行扫描时可能的闭合区域的最大值
const int SEG_LIMIT = 50;		// 行扫描时的长线段像素数最大值
const int NUM_SYMBOL = 12;		// 车牌中字符个数的最大值
const int NUM_CHARSET = 4;		// 车牌中字符集个数的最大值
const int NUM_OUTLINE = 800;	// 字符外周轮廓所包含点数的最大值
const int NUM_PLATE = 2;		// 同时悬挂的车牌块数的最大值

typedef char				int8;
typedef unsigned char		uint8;
typedef short				int16;
typedef unsigned short		uint16;
typedef int					int32;
typedef unsigned int		uint32;
typedef __int64				int64;
typedef unsigned __int64	uint64;

// 车牌背景色
enum
{
	BLACK,		// 黑色
	WHITE,		// 白色
	RED,		// 红色
	GREEN,		// 绿色
	BLUE,		// 蓝色
	YELLOW,		// 黄色
};

// 车牌类型
enum   
{
	PLATE_NONE,					// 无车牌
	PLATE_BLUE_WHITE,			// 蓝底白字
	PLATE_YELLOW_BLACK,			// 黄底黑字
	PLATE_YELLOW_BLACK2,		// 黄底黑字两行
	PLATE_MUCK,					// 渣土车
	PLATE_GREEN_BLACK,			// 绿底黑字
	PLATE_GREEN_YELLOW_BLACK,	// 绿/黄底黑字
	PLATE_WHITE_BLACK,			// 白底黑字
};

// 汉字类型
enum   
{
	HANZI_OLD,		// 汉字字体
};

// 英数类型
enum   
{
	ALPHA_OLD,		// 英数字体1, 蓝底白字、黄底黑字等车牌的英数字体
	ALPHA_NEW,		// 英数字体2,新能源车牌的英数字体
};

// 分隔符类型
enum   
{
	SEPTOR_NONE,	// 空白分隔符
	SEPTOR_DOT,		// 圆点分隔符
	SEPTOR_DASH,	// 横杠分隔符
	SEPTOR_PLUG,	// 插头分隔符
};

// 像素点
typedef struct VECT
{
	int16 x;		// x坐标
	int16 y;		// y坐标
	int16 z;		// 用于存储二维坐标点的其他属性
} VECT;

// 矩形框
typedef struct BOX
{
	int16 left;		// 左边界
	int16 right;	// 右边界
	int16 top;		// 上边界
	int16 bottom;	// 下边界
} BOX;

// 范围
typedef struct BOUND
{
	int16 flags;	// 标志字
	int16 width;	// 方框宽度
	int16 height;	// 方框高度
	int16 xl;		// 最左边点的x坐标,等于方框左边界
	int16 yl;		// 最左边点的y坐标
	int16 xr;		// 最右边点的x坐标,等于方框右边界
	int16 yr;		// 最右边点的y坐标
	int16 xt;		// 最上边点的x坐标
	int16 yt;		// 最上边点的y坐标,等于方框上边界
	int16 xb;		// 最下边点的x坐标
	int16 yb;		// 最下边点的y坐标,等于方框下边界
	int16 xlc;		// 过中央横线最左边点的x坐标
	int16 ylc;		// 过中央横线最左边点的y坐标
	int16 xrc;		// 过中央横线最右边点的x坐标
	int16 yrc;		// 过中央横线最右边点的y坐标
	int16 xtc;		// 过中央竖线最上边点的x坐标
	int16 ytc;		// 过中央竖线最上边点的y坐标
	int16 xbc;		// 过中央竖线最下边点的x坐标
	int16 ybc;		// 过中央竖线最下边点的y坐标
	int16 xc;		// 中心点的x坐标
	int16 yc;		// 中心点的y坐标
	int16 nl;		// 轮廓左边段的点数
	int16 nr;		// 轮廓右边段的点数
	int16 nt;		// 轮廓上边段的点数
	int16 nb;		// 轮廓下边段的点数
	VECT* vl;		// 轮廓左边段的点数据
	VECT* vr;		// 轮廓右边段的点数据
	VECT* vt;		// 轮廓上边段的点数据
	VECT* vb;		// 轮廓下边段的点数据
} BOUND;

// 单字符识别结果
typedef struct RESULT 
{
	uint8 symbol;	// 字符
	uint8 score;	// 分值,满分为100
	int16 weight;	// 重量,越重越好
} RESULT;

// 字符模板
typedef struct RASTER
{
	uint8 symbol;		// 字符
	uint8 reserved1;
	uint8 reserved2;
	uint8 reserved3;
	uint32 font[48];	// 宽32,高48
} RASTER;

// 车牌参数
typedef struct PARAMS
{
	int num_row;				// 字符行数
	int num_charset;			// 字符集个数
	int alpha_style;			// 字母、数字样式
	int hanzi_style;			// 汉字样式
	int ratio0;					// 正常字符间距之间的比例的下限
	int ratio1;					// 正常字符间距之间的比例的上限,分隔点前、后两字符间距与正常字符间距的比例的下限
	int ratio2;					// 分隔点前、后两字符间距与正常字符间距的比例的上限,正常字符2倍间距与1倍间距的比例的下限
	int ratio3;					// 正常字符2倍间距与1倍间距的比例上限,分隔点前、后两字符加1字符间距与正常字符间距的比例的的下限
	int ratio4;					// 分隔点前、后两字符加1字符间距与正常字符间距的比例的的上限,正常字符3倍间距与1倍间距的比例的下限
	int ratio5;					// 正常字符3倍间距与1倍间距的比例的上限
	struct 
	{
		int num_sym;				// 字符个数(不含分隔符)
		int septor_pos;				// 分隔符的位置
		int septor_style;			// 分隔符样式
		int back_color0;			// 分隔符前的背景颜色
		int back_color;				// 分隔符后的背景颜色
		int fore_color;				// 主要的字符颜色
		int fore_color1;			// 最末位字符颜色
		int width;					// 字符宽度 
		int height;					// 字符高度
		int x_space;				// 正常字符间距
		int x_dot_space;			// 分隔点前、后两字符间距
		int y_center;				// 中央y坐标
		int x_center[NUM_SYMBOL];	// 各字符中央x坐标
		int charset[NUM_SYMBOL];	// 各字符所属字符集
		int sequence[NUM_SYMBOL];	// 易识别字符的序号
	} row[2];						// 每行的参数			
	char chars[NUM_CHARSET][64];	// 字符集的定义
} PARAMS;

// 扫描线
typedef struct LINES
{
	int row;	// 哪一行
	int num;	// xx中存储的点数
	int ct;		// 黑白线段数
	int x1;		// 有效起始点的序号
	int x2;		// 有效结束点的序号
	int *xx;	// 每个点的x坐标
} LINES;

// 车牌识别结果的信息
typedef struct PLATE_INFO
{
	int num;							// 车牌块数
	int type[NUM_PLATE];				// 车牌类型
	uint8 avg_score[NUM_PLATE];			// 每个车牌识别结果的总评分(可信度)
	uint8 text[NUM_PLATE][12];			// 每个车牌的识别结果(以'\0'结束)
	uint8 score[NUM_PLATE][12];			// 每个车牌每个字符识别结果的评分(可信度)
} PLATE_INFO;


class CPlate
{
public:
	CPlate(void);
	~CPlate(void);

	unsigned char *m_pOrg;			// 原始图像
	unsigned char *m_pRGB;			// RGB图像
	unsigned char *m_pHSV;			// HSV图像
	unsigned char *m_pGreen;		// 绿底,反相
	unsigned char *m_pBlue;			// 蓝底
	unsigned char *m_pYellow;		// 黄底,反相
	unsigned char *m_pWhite;		// 白底,反相
	unsigned char *m_pBlack;		// 黑底,也用作灰度图像
	unsigned char *m_pSharpen;		// 灰度图像锐化后

	unsigned char *m_pPlateRGB[NUM_PLATE];	// 车牌局部的彩色图像
	unsigned char *m_pPlateGray;	// 识别时用到的车牌图像之一
	unsigned char *m_pPlateColor;	// 识别时用到的车牌图像之二 
	unsigned char *m_pPlateMono[8]; // 识别时用到的单色车牌图像

	int m_nWidth;		// 归一化图像宽度
	int m_nHeight;		// 归一化图像高度
	int m_nOrgWidth;	// 原始图像宽度
	int m_nOrgHeight;	// 原始图像高度

	int *m_pCoord;		// 存储扫描线坐标点的缓冲区
	LINES *m_pLines;	// 存储扫描线内容的缓冲区

public:
	static int GaussElimination(double *a, double *b, double *x, int n);

	static int FitHorizLine(VECT *pt, int n, int &k, int &b);
	static int FitVertLine(VECT *pt, int n, int &k, int &b);
	static int FindCrossPoint(int kh, int bh, int kv, int bv, VECT *pt);

	static int SetBound(int xc, int yc, int width, int height, BOUND *bound);
	static bool BoundEqual(BOUND *a, BOUND *b);
	static bool BoundIncluded(BOUND *a, BOUND *b);
	static BOUND* BoundCombine(BOUND *a, BOUND *b);
	static void BoundFindLeftSide(BOUND *bound, VECT* pt, int num);
	static void BoundFindRightSide(BOUND *bound, VECT* pt, int num);
	static int FindBound(BOUND *bound, BOX *box, VECT *pt, int num);

	static void RGB2Gray(void *src, void *dst, int width, int height);
	static void RGB2Blue(void *src, void *dst, int width, int height);
	static void RGB2Green(void *src, void *dst, int width, int height);
	static void RGB2Yellow(void *src, void *dst, int width, int height);
	static void RGB2Black(void *src, void *dst, int width, int height);
	static void RGB2White(void *src, void *dst, int width, int height);
	static void Invert(void *src, int width, int height);
	static void Copy(void *src, void *dst, int width, int height);
	static void MiddleFilter(void *src, int width, int height, int mono);
	static void Sharpen(void *src, void *dst, int width, int height);
	static void Binarize(void *src, void *dst, int width, int height, int threshold);
	static void Frame(void *src, int color, int width, int height);
	static void HorizLine(void *src, int color, int width, int y);
	static void VertLine(void *src, int color, int width, int height, int x);
	static void PerspectiveTransform(void *src, void *dst, int *factor, int src_x0, int src_y0, int src_width, int src_height, int dst_width, int dst_height);

	static int OTSU_Threshold(int *count, int &threshold, int &back, int &fore);

	static void StatsHistogram(void *src, int width, int height, int *count);
	static void StatsHistogram(void *src, int x, int y, int w, int h, int *count);

	static int FindOutline(void *src, int width, int height, int threshold, int xx, int *yy, int &yynum, VECT pt0, VECT *pt, BOX *box, bool box_init);

	static int FindOutlineLeftward(void *src, int width, int height, int threshold, VECT pt0, VECT *pt, BOX *box, BOUND *bound, bool box_init);
	static int FindOutlineRightward(void *src, int width, int height, int threshold, VECT pt0, VECT *pt, BOX *box, BOUND *bound, bool box_init);
	static int FindOutlineUpward(void *src, int width, int height, int threshold, VECT pt0, VECT *pt, BOX *box, BOUND *bound, bool box_init);
	static int FindOutlineDownward(void *src, int width, int height, int threshold, VECT pt0, VECT *pt, BOX *box, BOUND *bound, bool box_init);

	static int FindEdgeUpward(void *src, int threshold, BOUND *bound, VECT *pt);
	static int FindEdgeDownward(void *src, int threshold, BOUND *bound, VECT *pt);
	static int FindEdgeLeftward(void *src, int threshold, int kc, BOUND *bound, VECT *pt);
	static int FindEdgeRightward(void *src, int threshold, int kc, BOUND *bound, VECT *pt);

	static int EstimateHorizAngle(VECT *pt, int n, int &k, int &b);
	static int EstimateVertAngle(VECT *pt, int n, int &k, int &b);
	
	static int StatsLine(void *src, int width, int threshold, int *xx, bool sharpen);
	static int StatsVertLine(void *src, int width, int threshold, int *xx, BOX *box);
	static int DetermineLine(int row, int col, LINES *pline, bool sharpen);

	static int FindRasterSet(int plate, int charset, RASTER **ppRaster);
	static RESULT RecognizeSymbol(void *src, int threshold, int plate, int index, int &num, int &yt, int &yb, VECT *pt, BOUND *bound, int numRaster, RASTER **ppRaster);
	static RESULT MatchRaster(void *src, int width, int height, int x, int y, int w, int h, int numRaster, RASTER **ppRaster, bool narrow1);

	static int CompareColors(const void *a, const void *b);
	static int CompareBound_height(const void *a, const void *b);
	static
  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值