前言

1.关于边缘检测,我这里用了HED这个边缘检测网络,HED创作于2015年,骨干网络是state-of-the-art的VGG-16,并且使用迁移学习初始化了网络权重。关于HED的算法原理与训练模型代码可以转到github。
2.OpenCV也有好几边缘检测算法可用,就拿最常用的Canny算法来说,对背景复杂一点的图像,手动调参往往是这个场景下边缘很完美的提取出来,当换个有差异的场景,干扰源不一样,要得到好一些的效果,参数阈值又得重新调一遍,如果要做一个能商用的项目,Canny算法是不能完美解决边缘提取的问题。

项目流程

1.先用HED提取身份证边缘。
2.用霍夫变换直线检测对边缘图像做直线检测。
3.对检测到的直线做排序与筛选,得到最终的边缘。
4.找到边缘线的相交点。
5.以四条线的四个相交点来矫正得到的最终身份证目标。

代码实现

1.使用用OpenCV的DNN来做模型推理,得到最终于的边缘图像。

int hedEdge(cv::dnn::Net& edge_net, cv::Mat& cv_book, cv::Mat& cv_hed)
{if (cv_book.empty()){return -2;}cv::Mat cv_gamma;cv::Size reso(512, 512);cv::Mat blob = cv::dnn::blobFromImage(cv_book, 1.0 / 255.0, reso, cv::Scalar(0, 0, 0), true, false);edge_net.setInput(blob);cv_hed = edge_net.forward();cv::resize(cv_hed.reshape(1, reso.height), cv_hed, cv_book.size(), cv::INTER_LINEAR);cv_hed.convertTo(cv_hed, CV_8UC1, 255);return 0;
}

得到边缘图像:

2.对得到的边缘图像进行直线检测并分出垂直与水平线。

struct Line
{cv::Point LP1;cv::Point LP2;cv::Point LC;Line(cv::Point p1, cv::Point p2){LP1 = p1;LP2 = p2;LC = cv::Point((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);}
};
void lineDetection(cv::Mat cv_edge,std::vector<Line> &h_lines, std::vector<Line>& v_lines)
{cv::Mat cv_dilate, cv_erode;cv::Mat element_e = getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5), cv::Point(-1, -1));cv::Mat element_d = getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3), cv::Point(-1, -1));cv::erode(cv_edge, cv_erode, element_e);cv::dilate(cv_erode, cv_dilate, element_d);std::vector<cv::Vec4i> lines;HoughLinesP(cv_dilate, lines, 1, CV_PI / 180, 100,80, 8);for (size_t i = 0; i < lines.size(); i++) {cv::Vec4i v = lines[i];double delta_x = v[0] - v[2], delta_y = v[1] - v[3];Line l(cv::Point(v[0], v[1]), cv::Point(v[2], v[3]));if (fabs(delta_x) > fabs(delta_y)){h_lines.push_back(l);}else{v_lines.push_back(l);}}
}

运行结果:

3.提取最终边缘线并得到四个矫正的点。

bool cmpLineY(const Line& p1, const Line& p2)
{return p1.LC.y < p2.LC.y;
}bool cmpLineX(const Line& p1, const Line& p2)
{return p1.LC.x < p2.LC.x;
}cv::Point2f computeIntersect(Line l1, Line l2)
{int x1 = l1.LP1.x, x2 = l1.LP2.x, y1 = l1.LP1.y, y2 = l1.LP2.y;int x3 = l2.LP1.x, x4 = l2.LP2.x, y3 = l2.LP1.y, y4 = l2.LP2.y;if (float d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)){cv::Point2f pt;pt.x = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;pt.y = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;return pt;}return cv::Point2f(-1, -1);
}void screeningLine(cv::Mat cv_src, std::vector<Line> &h_lines, std::vector<Line> &v_lines, std::vector<cv::Point> &out_points)
{if (h_lines.size() >= 2 && v_lines.size() >= 2){std::sort(h_lines.begin(), h_lines.end(), cmpLineY);std::sort(v_lines.begin(), v_lines.end(), cmpLineX);out_points.push_back(computeIntersect(h_lines[0], v_lines[0]));out_points.push_back(computeIntersect(h_lines[0], v_lines[v_lines.size() - 1]));out_points.push_back(computeIntersect(h_lines[h_lines.size() - 1], v_lines[0]));out_points.push_back(computeIntersect(h_lines[h_lines.size() - 1], v_lines[v_lines.size() - 1]));}else{out_points.push_back(cv::Point2f(2, 2));out_points.push_back(cv::Point2f(2, cv_src.rows - 2));out_points.push_back(cv::Point2f(cv_src.cols - 2, 2));out_points.push_back(cv::Point2f(cv_src.cols - 2, cv_src.rows - 2));}
}

运行结果:

4.按四个点矫正图像。

int reviseImage(cv::Mat& cv_src, cv::Mat& cv_dst, std::vector<cv::Point>& in_points)
{cv::Point point_f, point_b;point_f.x = (in_points.at(0).x < in_points.at(2).x) ? in_points.at(0).x : in_points.at(2).x;point_f.y = (in_points.at(0).y < in_points.at(1).y) ? in_points.at(0).y : in_points.at(1).y;point_b.x = (in_points.at(3).x > in_points.at(1).x) ? in_points.at(3).x : in_points.at(1).x;point_b.y = (in_points.at(3).y > in_points.at(2).y) ? in_points.at(3).y : in_points.at(2).y;//代码取目标的最小外接矩形,但倾斜45度时会出现比例变形的现象cv::Rect rect(point_f, point_b);cv_dst = cv::Mat::zeros(rect.height, rect.width, CV_8UC3);std::vector<cv::Point2f> dst_pts;dst_pts.push_back(cv::Point2f(0, 0));dst_pts.push_back(cv::Point2f(rect.width - 1, 0));dst_pts.push_back(cv::Point2f(0, rect.height - 1));dst_pts.push_back(cv::Point2f(rect.width - 1, rect.height - 1));std::vector<cv::Point2f> tr_points;tr_points.push_back(in_points.at(0));tr_points.push_back(in_points.at(1));tr_points.push_back(in_points.at(2));tr_points.push_back(in_points.at(3));cv::Mat transmtx = getPerspectiveTransform(tr_points, dst_pts);warpPerspective(cv_src, cv_dst, transmtx, cv_dst.size());return 0;
}

运行结果:

身体证检测与识别(二)——HED边缘检测与矫正相关推荐

  1. 中文OCR光学字符检测与识别二:用最先进的DBNet训练自己的数据集检测中文文本

    中文OCR光学字符检测与识别二:用最先进的DBNet训练自己的数据集检测中文文本 本文介绍 中文OCR光学字符检测与识别二:用最先进的DBNet训练自己的数据集检测中文文本 中文OCR光学字符检测与识 ...

  2. 目标检测与识别算法综述:从传统算法到深度学习(二)

    作   者:XJTU_Ironboy 时   间:2018年11月 联系方式:tzj19970116@163.com 本文结构: 摘要 介绍 2.1 大致框架 2.2 测试评价指标 2.3 相关比赛介 ...

  3. OpenCV4学习笔记(58)——二维码检测与识别

    本次要整理的笔记内容是在OpenCV中对二维码进行检测与识别.二维码对我们来说可以说是非常熟悉的,乃至于每次出门都会和"扫码"挂钩,可以说二维码已经渗入到我们生活的方方面面.那么二 ...

  4. 智能驾驶 车牌检测和识别(二)《YOLOv5实现车牌检测(含车牌检测数据集和训练代码)》

    智能驾驶 车牌检测和识别(二)<YOLOv5实现车牌检测(含车牌检测数据集和训练代码)> 目录 智能驾驶 车牌检测和识别(二)<YOLOv5实现车牌检测(含车牌检测数据集和训练代码) ...

  5. OpenCV检测与识别条码、二维码

    原文链接:http://www.juzicode.com/opencv-note-barcodedetector-qrcodedetector ​在 zbar:给我来10G打码图片 一文中桔子菌介绍了 ...

  6. 基于深度学习的二维码检测和识别(含完整代码和数据)

    最近尝试着将深度学习技术引入到二维码检测和识别中,期望能够提升传统二维码的识读性能,能够适用更多复杂背景,并且最终应用到工业生产中,方便生产线上对产品的ID管理. 项目最终实现效果如下所示: 相对来说 ...

  7. OpenCV二维码检测定位识别

    VS2019下OpenCV环境配置 VC++目录的包含目录和库目录 链接器-输入-附加依赖项: 文件在lib下,带d结尾的是debug模式用的 #include<Windows.h> #i ...

  8. 目标识别:如何从人脸图片中扣出眼图,实时人脸人眼检测和识别

    一.了解opencv级联多级分类器: 我们使用opencv级联多级分类器进行解读: 1.基本概念  opencv中的人脸检测使用基于Harr的级联分类和基于LBP的级联分类.  Harr是在2001年 ...

  9. python用法查询软件_如何使用Python应用软件实现车牌检测和识别

    1.车牌检测和识别项目介绍 车牌的检测和识别的应用非常广泛,比如交通违章车牌追踪,小区或地下车库门禁.在对车牌识别和检测的过程中,因为车牌往往是规整的矩形,长宽比相对固定,色调纹理相对固定,常用的方法 ...

最新文章

  1. HDU7059-Counting Stars 线段树 (区间加最低位置,区间减最高位)
  2. java拼接字符串 判断内容_java--字符串拼接比较
  3. 软件工程 工具之二—— PowerDesigner v12(四)
  4. Linq distinct去重方法之一
  5. protobuf 语法浅析
  6. SAP NetWeaver 平台介绍
  7. ROS中记录数据与回放
  8. Linux扫描工具rootkit部署
  9. 国稻种芯百团计划行动 胡培松:早稻可以向用途多元化发展
  10. minimax算法_使用Minimax算法玩策略游戏
  11. php中html插入图片,html插入图片的示例代码详解(图)
  12. java求导数_java实现队列链表,求一元多项式的导数
  13. GEF原理及实现系列(四、控制器)
  14. oracle ko16mswin949,PRM DUL Oracle数据库恢复的最后一步
  15. 如何网页访问摄像机?海康威视官方文档
  16. 8960综测仪测试小区广播(2G)
  17. android壁纸保存目录,如何获取安卓手机当前壁纸的路径
  18. 高斯白噪声及Matlab常用实现方法
  19. 罗宾斯管理学第13版课后答案
  20. 电销行业竞争与日俱增,西安外呼系统如何改善?

热门文章

  1. 【编程语言】诚迈试题一
  2. openwrt网络唤醒计算机,OpenWrt实现WOL(Wake-on-LAN)网络唤醒
  3. 从白百合看明星都出轨,该如何维护守护自己的爱情
  4. Linux结合ls和rm命令删除文件
  5. ApacheKafka在滴滴出行商业化探索与实践
  6. python随机生成小数_python如何生成随机小数
  7. 巧用Photoshop滤镜打造星光灿烂特效背景(转)
  8. 介绍一下 WMS WCS PLC 之间的关系 并附加代码
  9. Labview2017安装及破解步骤
  10. Oracle 行转列 pivot函数基本用法