我正在尝试开发一种可以用相机扫描护照页面的扫描仪。如何使用OpenCV检测Passport页面的界限?
我想裁掉的标记部分。
我已经编写了使用OpenCV进行边缘检测的代码,它可以找到轮廓,然后近似最大的四边形。最后,它进行4点透视转换以获得图像的顶视图。边缘检测代码如下所示:
public static List<MatOfPoint> findContours(Mat src){
Mat img = src.clone();
src.release();
//find contours
double ratio = getScaleRatio(img.size());
int width = (int) (img.size().width/ratio);
int height = (int) (img.size().height/ratio);
Size newSize = new Size(width, height);
Mat resizedImg = new Mat(newSize, CvType.CV_8UC4);
Imgproc.resize(img, resizedImg, newSize);
Imgproc.medianBlur(resizedImg, resizedImg, 5);
Mat cannedImg = new Mat(newSize, CvType.CV_8UC1);
Imgproc.Canny(resizedImg, cannedImg, 70, 200, 3, true);
resizedImg.release();
Imgproc.threshold(cannedImg, cannedImg, 200, 255, Imgproc.THRESH_OTSU);
Mat dilatedImg = new Mat(newSize, CvType.CV_8UC1);
Mat morph = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3));
Imgproc.dilate(cannedImg, dilatedImg, morph, new Point(-1, -1), 2, 1, new Scalar(1));
cannedImg.release();
morph.release();
ArrayList<MatOfPoint> contours = new ArrayList<>();
Mat hierarchy = new Mat();
Imgproc.findContours(dilatedImg, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
hierarchy.release();
Log.d(TAG, "contours found: " + contours.size());
Collections.sort(contours, new Comparator<MatOfPoint>() {
@Override
public int compare(MatOfPoint o1, MatOfPoint o2) {
return Double.valueOf(Imgproc.contourArea(o2)).compareTo(Imgproc.contourArea(o1));
}
});
return contours;
}
for(MatOfPoint contour:contours){
MatOfPoint2f mat = new MatOfPoint2f(contour.toArray());
double peri = Imgproc.arcLength(mat, true);
MatOfPoint2f approx = new MatOfPoint2f();
Imgproc.approxPolyDP(mat, approx, 0.02 * peri, true);
Point[] points = approx.toArray();
Log.d("SCANNER", "approx size " + points.length);
if (points.length == 4) {
Point[] spoints = CVProcessor.sortPoints(points);
if (CVProcessor.insideArea(spoints, newSize)) {
rectContour = contour;
foundPoints = spoints;
break;
}
}
}
此代码适用于单页文档,即ID卡,信用卡。哪里有4个可区分的边缘。
但不适用于护照,因为最高优势不如其独特。
输入将从Android上的相机拍摄。任何想法如何检测护照页面?我正在使用OpenCV 3.1。
您能否提供有关拍摄条件的任何信息:光线条件(特别是在光源方向变得更暗或消失的顶部边缘),拍摄角度(相机与护照是否垂直),那么各种其他国家的护照(美国的旗帜从一页传到另一页)呢,你将使用的背景是什么?捕获角度将很困难,因为您可能不会选择将护照平放在地面上(否则您的手会挡住护照)。请问这个问题的理由:您的图片不是测试图片,而是从谷歌中挑选出来的? – saurabheights
@saurabheights扫描仪应该在android/ios手机上使用。所以相机质量应该是标准智能手机相机至少500万像素的分辨率。假设照明条件足够好(不需要特别设置)。相机可能不完全垂直于护照,但应该靠近。背景应该与护照背景不同(较深)。它的作用是将护照尽可能平放在地面上。是的,图片是从谷歌采取的,但解决方案应该与这些作为基础测试案例。 – Mehedi
我的确有一些初步的想法,比如使用Canny&Hough,并配以护照尺寸。考虑Hough变换中的垂直/接近垂直线,并对水平线做同样的处理。水平边缘和垂直边缘的透视变换应该为你提供一个矩形图像。这个维度将有助于从护照顶端的问题。最后的聚合应该做最后的任务。背景和护照之间的颜色分割(浅色和通常居中)也可能有所帮助,但由于各个国家的护照之间存在差异,因此可能会出现错误。 – saurabheights