【C#】身份证识别(二):提取目标区域图像
2017-09-26 17:20
309 查看
目录
引言
一获取身份证号区域矩形
二获取地址出生年月性别名族姓名区域矩形
获取号码区域位置
获取各个区域的包围矩形
三剪切目标区域
四提取效果
完整项目地址:https://gitee.com/xgpxg/ICRS
身份证识别(一):身份证号定位
Angle:矩形旋转角度(相对水平方向),顺时针旋转值为正,逆时针旋转值为负。
Center:矩形的中心
Size:矩形的尺寸
GetVertices():PointF[]类型,包含矩形的四个顶点坐标。
有了这些信息之后就可以以该矩形(以下称为标准矩形)为基准计算其它区域的相对位置。
以住址区域为例:
偏移量的计算:
标准矩形的中心为rr.Center
若旋转角度为0
若旋转角度不为0
对于旋转角度为0的矩形,只要以左上角顶点为中心依次将矩形区域复制到新图像即可。
对于倾斜的矩形,则需要先选取旋转中心,然后将矩形旋转至水平方向,然后在对像素点进行遍历复制。
对于上一步得到的矩形,虽然GetVertices()可以获取四个顶点的坐标,但是无法确定顶点顺序,则无法确定旋转中心点,所以首先要对矩形顶点编号。我们按逆时针方向进行顶点编号。
这样当Angle<0编号为①的顶点就是旋转中心,当Angle<0编号为①的顶点就是旋转中心。
顶点编号主要代码:
然后新建一幅与矩形区域相同大小的图像:
因为要复制原始图像区域内的像素,所以并不是对原始图像旋转,而是对
如上图所示,绿色矩形为
设
具体代码如下:
如此一来便提取出了各个区域的图像,下一步进行字符识别。
附一: 获取各个区域的包围矩形的主要代码:
附二: 点旋转代码:
附三: 判断点是否在多边形内
引言
一获取身份证号区域矩形
二获取地址出生年月性别名族姓名区域矩形
获取号码区域位置
获取各个区域的包围矩形
三剪切目标区域
四提取效果
完整项目地址:https://gitee.com/xgpxg/ICRS
引言:
为获得更好的识别效果,现对身份证含有个人信息区域进行提取,缩小识别范围,以此来提高识别精度和效率一、获取身份证号区域矩形
身份证号区域矩形的获取,见上一篇文章:身份证识别(一):身份证号定位
二、获取地址、出生年月、性别、名族、姓名区域矩形
1. 获取号码区域位置
在第一步得到的结果是一个旋转矩形RotatedRect,该矩形的属性如下:Angle:矩形旋转角度(相对水平方向),顺时针旋转值为正,逆时针旋转值为负。
Center:矩形的中心
Size:矩形的尺寸
GetVertices():PointF[]类型,包含矩形的四个顶点坐标。
有了这些信息之后就可以以该矩形(以下称为标准矩形)为基准计算其它区域的相对位置。
2. 获取各个区域的包围矩形
由于标准矩形的顶点顺序不确定,所以选用标准矩形的中心作为参考点,然后计算地址区域中心的偏移量。以住址区域为例:
偏移量的计算:
标准矩形的中心为rr.Center
若旋转角度为0
float w = (float)(rr.Size.Width * 0.8); //住址区宽度 float h = (float)(rr.Size.Height * 1.7);//住址区高度 float px = (float)(rr.Center.X - rr.Size.Height * 3.1);//住址区x坐标 float py = (float)(rr.Center.Y - rr.Size.Height * 2.4);//住址区y坐标 PointF center = new PointF(px,py); RotatedRect rect = new RotatedRect(center,new SizeF(w,h),rr.Angle);
若旋转角度不为0
float w = (float)(rr.Size.Width * 0.8 * Math.Cos(rr.Angle); //住址区宽度 float h = (float)(rr.Size.Height * 1.7* Math.Cos(rr.Angle));//住址区高度
三、剪切目标区域
裁剪目标区域,即将目标矩形内的像素点复制到一幅与矩形相同大小,并保持水平的图像中,以方便进一步的识别。对于旋转角度为0的矩形,只要以左上角顶点为中心依次将矩形区域复制到新图像即可。
对于倾斜的矩形,则需要先选取旋转中心,然后将矩形旋转至水平方向,然后在对像素点进行遍历复制。
对于上一步得到的矩形,虽然GetVertices()可以获取四个顶点的坐标,但是无法确定顶点顺序,则无法确定旋转中心点,所以首先要对矩形顶点编号。我们按逆时针方向进行顶点编号。
这样当Angle<0编号为①的顶点就是旋转中心,当Angle<0编号为①的顶点就是旋转中心。
顶点编号主要代码:
/// <summary> /// 矩形顶点编号 /// </summary> /// <param name="pointfs"></param> /// <param name="angle"></param> /// <returns></returns> public static PointF[] RectCode(RotatedRect rect) { PointF[] p = rect.GetVertices(); PointF[] pointfs = new PointF[4]; pointfs[0] = p[0]; pointfs[1] = p[0]; pointfs[2] = p[0]; pointfs[3] = p[0]; //逆时针编号 for (int i = 1; i < 4; i++) { if (p[i].X < p[i - 1].X) pointfs[0] = p[i]; if (p[i].Y > p[i - 1].Y) pointfs[1] = p[i]; if (p[i].X > p[i - 1].X) pointfs[2] = p[ 4000 i]; if (p[i].Y < p[i - 1].Y) pointfs[3] = p[i]; } return pointfs; }
然后新建一幅与矩形区域相同大小的图像:
Image<Bgr, byte> newImg = new Image<Bgr, byte>(new Size((int)rect.Size.Width, (int)rect.Size.Height));
因为要复制原始图像区域内的像素,所以并不是对原始图像旋转,而是对
newImg内的点与原始图像内的点对应起来,进行一个映射。
如上图所示,绿色矩形为
newImg,蓝色矩形为身份证号区域,首先将将绿色矩形的坐标平移到红色虚线矩形处,然后再旋转虚线矩形的坐标,即完成了坐标映射。
设
newImg的坐标为(x0,y0),
img(原始图像)的坐标为(x,y)平移的偏移量为(Δx,Δy),旋转角度为angle,则(x0,y0)处的像素值可以表示为:
(x0,y0).Color = rote(angle)[(x0+Δx,y0+Δy)].Color
具体代码如下:
public static Image<Bgr,byte> Rote(Image<Bgr,byte>img, RotatedRect rect) { PointF center = new PointF(); PointF[] pointfs = RectCode(rect); if(rect.Angle < 0) { center = pointfs[0]; } if(rect.Angle >= 0) { center = pointfs[3]; } Image<Bgr, byte> output = new Image<Bgr, byte>(new Size((int)rect.Size.Width, (int)rect.Size.Height)); int w = (int)rect.Size.Width; int h = (int)rect.Size.Height; for (int i = (int)center.X,m=0; i < w + (int)center.X; i++,m++) { for (int j = (int)center.Y, n = 0; j < h + (int)center.Y; j++,n++) { { Point p = PointRotate(center, new PointF(i, j), -rect.Angle); if (p.X >= img.Size.Width) p.X = img.Size.Width - 1; if (p.Y >= img.Size.Height ) p.Y = img.Size.Height - 1; output[n, m] = img[p.Y, p.X]; } } } if (Math.Abs(rect.Angle) > 45) { output = output.Rotate(180, new Bgr(Color.White)); } return output; }
如此一来便提取出了各个区域的图像,下一步进行字符识别。
四、提取效果
附一: 获取各个区域的包围矩形的主要代码:
/// <summary> /// 身份证号区域 /// </summary> /// <param name="img"></param> /// <returns></returns> public static RotatedRect IdRotatedRect(Image<Bgr, byte> img) { Image<Bgr, byte> a = new Image<Bgr, byte>(img.Size); VectorOfVectorOfPoint con = GetContours(BinImg(img)); Point[][] con1 = con.ToArrayOfArray(); PointF[][] con2 = Array.ConvertAll<Point[], PointF[]>(con1, new Converter<Point[], PointF[]>(PointToPointF)); for (int i = 0; i < con.Size; i++) { RotatedRect rrec = CvInvoke.MinAreaRect(con2[i]); float w = rrec.Size.Width; float h = rrec.Size.Height; if (w / h > 6 && w / h < 10 && h > 20) { PointF[] pointfs = rrec.GetVertices(); for (int j = 0; j < pointfs.Length; j++) { CvInvoke.Line(a, new Point((int)pointfs[j].X, (int)pointfs[j].Y), new Point((int)pointfs[(j + 1) % 4].X, (int)pointfs[(j + 1) % 4].Y), new MCvScalar(0, 0, 255, 255), 4); } return rrec; } } return new RotatedRect(); } /// <summary> /// 地址区域 /// </summary> /// <param name="rr"></param> /// <returns></returns> public static RotatedRect AddressRotatedRect(RotatedRect rr) { float w = (float)((rr.Size.Width * 0.8)); float h = (float)(rr.Size.Height * 1.7); float px = (float)(rr.Center.X - rr.Size.Height * 3.1); float py = (float)(rr.Center.Y - rr.Size.Height * 2.4); PointF center = new PointF(px,py); RotatedRect rect = new RotatedRect(center,new SizeF(w,h),rr.Angle); return rect; } /// <summary> /// 年份区域 /// </summary> /// <param name="rr"></param> /// <returns></returns> public static RotatedRect DateRotatedRect(RotatedRect rr) { float w = (float)(rr.Size.Width * 0.7); float h = (float)(rr.Size.Height * 1); float px = (float)(rr.Center.X - rr.Size.Height * 3.7); float py = (float)(rr.Center.Y - rr.Size.Height * 4); PointF center = new PointF(px, py); RotatedRect rect = new RotatedRect(center, new SizeF(w, h), rr.Angle); return rect; } /// <summary> /// 性别区域 /// </summary> /// <param name="rr"></param> /// <returns></returns> public static RotatedRect SexRotatedRect(RotatedRect rr) { float w = (float)(rr.Size.Width * 0.7); float h = (float)(rr.Size.Height * 1); float px = (float)(rr.Center.X - rr.Size.Height * 3.7); float py = (float)(rr.Center.Y - rr.Size.Height * 5); PointF center = new PointF(px, py); RotatedRect rect = new RotatedRect(center, new SizeF(w, h), rr.Angle); return rect; } /// <summary> /// 姓名区域 /// </summary> /// <param name="rr"></param> /// <returns></returns> public static RotatedRect NameRotatedRect(RotatedRect rr) { float w = (float)(rr.Size.Width * 0.3 ); float h = (float)(rr.Size.Height * 1 ); float px = (float)(rr.Center.X - rr.Size.Height * 5.1); float py = (float)(rr.Center.Y - rr.Size.Height * 6.3); PointF center = new PointF(px, py); RotatedRect rect = new RotatedRect(center, new SizeF(w, h), rr.Angle); return rect; }
附二: 点旋转代码:
public static Point PointRotate(PointF center, PointF p1, double angle) { Point tmp = new Point(); double angleHude = angle * Math.PI / 180;/*角度变成弧度*/ double x1 = (p1.X - center.X) * Math.Cos(angleHude) + (p1.Y - center.Y) * Math.Sin(angleHude) + center.X; double y1 = -(p1.X - center.X) * Math.Sin(angleHude) + (p1.Y - center.Y) * Math.Cos(angleHude) + center.Y; tmp.X = (int)x1; tmp.Y = (int)y1; return tmp; }
附三: 判断点是否在多边形内
public static bool IsInside(Point inputponint,PointF[] pointfs) { GraphicsPath myGraphicsPath = new GraphicsPath(); Region myRegion = new Region(); myGraphicsPath.Reset(); myGraphicsPath.AddPolygon(pointfs); myRegion.MakeEmpty(); myRegion.Union(myGraphicsPath); return myRegion.IsVisible(inputponint); }
相关文章推荐
- 一个图像目标区域提取的问题
- C# 截取图像中的特定区域
- opencv提取截获图像,任意区域
- 目标检测的图像特征提取之(二)LBP特征
- 目标检测的图像特征提取之(二)LBP特征
- 目标检测的图像特征提取之(三)Haar特征_http://blog.csdn.net/zouxy09/article/details/7929570
- 目标检测的图像特征提取之(二)LBP特征
- 目标检测的图像特征提取之(一)HOG特征
- 目标检测的图像特征提取之(一)HOG特征
- 目标检测的图像特征提取之——Haar特征
- 目标检测的图像特征提取之Haar特征
- 四种比较简单的图像显著性区域特征提取方法原理及实现
- 目标检测的图像特征提取(一)HOG特点
- 目标检测的图像特征提取之(二)LBP特征
- 目标检测的图像特征提取之(二)LBP特征
- 目标检测的图像特征提取之(二)LBP特征
- 目标检测的图像特征提取之(二)LBP特征
- 目标检測的图像特征提取之(一)HOG特征
- 目标图像特征提取算子(HOG)
- ROI提取图像中部分区域