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