Android 在不同情况下检测文档的四个角
我尝试了以下两种方法:-Android 在不同情况下检测文档的四个角,android,opencv,image-processing,edge-detection,Android,Opencv,Image Processing,Edge Detection,我尝试了以下两种方法:- 图像到Mat的转换 应用高斯模糊 然后进行canny边缘检测 寻找轮廓 这种方法的问题是: 检测到的轮廓太多 大部分是开放轮廓 没有检测到我想要检测的东西 然后我改变了我的方法,尝试了高斯模糊/中值模糊后的自适应阈值,效果更好,我能够在50%的情况下检测到角点 我目前面临的问题是,页面检测需要对比鲜明、平淡的背景,没有任何反射。我认为它太理想化了,无法在现实世界中使用 这是我需要帮助的地方。即使是解决方案的方向也受到高度赞赏,尤其是在java中。期待中的感谢 在这样对比
PS在理想情况下对图像进行变形会导致检测到假轮廓边界。在变形图像之前可以检查的任何条件也是一种奖励。谢谢您可以使用以下一种或两种方法拾取单个轮廓:
- 使用
和BoundingRect
来评估ContourArea
返回正交矩形,要处理任意旋转,最好使用boundingRect()
返回最佳旋转矩形minarealect()
- 反复使用
将形状缩小为四边形Cv.ApproxPoly
var approxIter = 1; while (true) { var approxCurve = Cv.ApproxPoly(largestContour, 0, null, ApproxPolyMethod.DP, approxIter, true); var approxCurvePointsTmp = new[] { approxCurve.Select(p => new CvPoint2D32f((int)p.Value.X, (int)p.Value.Y)).ToArray() }.ToArray(); if (approxCurvePointsTmp[0].Length == 4) { corners = approxCurvePointsTmp[0]; break; } else if (approxCurvePointsTmp[0].Length < 4) throw new InvalidOperationException("Failed to decimate corner points"); approxIter++; }
var近似值=1; while(true) { var approxCurve=Cv.ApproxPoly(最大轮廓,0,null,ApproxPolyMethod.DP,approxIter,true); var approxCurvePointsTmp=new[]{approxCurve.Select(p=>newcvpoint2d32f((int)p.Value.X,(int)p.Value.Y)).ToArray()}.ToArray(); 如果(approxCurvePointsTmp[0]。长度==4) { 角点=approxCurvePointsTmp[0]; 打破 } else if(ApproxCurvePointsMP[0]。长度<4)抛出新的InvalidOperationException(“无法抽取角点”); approxIter++; }
如果是这样,可以对所有连接轮廓的组合重复搜索,以查看是否找到更大/更矩形的匹配。停止依赖边缘检测,这是世界上最糟糕的方法,并切换到某种形式的图像分割
纸是白色的,背景是对比色的,这是您应该使用的信息。如果您使用这样的方法:
public static RotatedRect getBestRectByArea(List<RotatedRect> boundingRects) {
RotatedRect bestRect = null;
if (boundingRects.size() >= 1) {
RotatedRect boundingRect;
Point[] vertices = new Point[4];
Rect rect;
double maxArea;
int ixMaxArea = 0;
// find best rect by area
boundingRect = boundingRects.get(ixMaxArea);
boundingRect.points(vertices);
rect = Imgproc.boundingRect(new MatOfPoint(vertices));
maxArea = rect.area();
for (int ix = 1; ix < boundingRects.size(); ix++) {
boundingRect = boundingRects.get(ix);
boundingRect.points(vertices);
rect = Imgproc.boundingRect(new MatOfPoint(vertices));
if (rect.area() > maxArea) {
maxArea = rect.area();
ixMaxArea = ix;
}
}
bestRect = boundingRects.get(ixMaxArea);
}
return bestRect;
}
private static Bitmap findROI(Bitmap sourceBitmap) {
Bitmap roiBitmap = Bitmap.createBitmap(sourceBitmap.getWidth(), sourceBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Mat sourceMat = new Mat(sourceBitmap.getWidth(), sourceBitmap.getHeight(), CV_8UC3);
Utils.bitmapToMat(sourceBitmap, sourceMat);
final Mat mat = new Mat();
sourceMat.copyTo(mat);
Imgproc.cvtColor(mat, mat, Imgproc.COLOR_RGB2GRAY);
Imgproc.threshold(mat, mat, 146, 250, Imgproc.THRESH_BINARY);
// find contours
List<MatOfPoint> contours = new ArrayList<>();
List<RotatedRect> boundingRects = new ArrayList<>();
Imgproc.findContours(mat, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
// find appropriate bounding rectangles
for (MatOfPoint contour : contours) {
MatOfPoint2f areaPoints = new MatOfPoint2f(contour.toArray());
RotatedRect boundingRect = Imgproc.minAreaRect(areaPoints);
boundingRects.add(boundingRect);
}
RotatedRect documentRect = getBestRectByArea(boundingRects);
if (documentRect != null) {
Point rect_points[] = new Point[4];
documentRect.points(rect_points);
for (int i = 0; i < 4; ++i) {
Imgproc.line(sourceMat, rect_points[i], rect_points[(i + 1) % 4], ROI_COLOR, ROI_WIDTH);
}
}
Utils.matToBitmap(sourceMat, roiBitmap);
return roiBitmap;
}
public static RotatedRect getbestrectbyrea(列表boundingRects){
RotatedRect bestRect=null;
如果(boundingRects.size()>=1){
RotatedRect boundingRect;
点[]顶点=新点[4];
Rect-Rect;
双最大面积;
int ixMaxArea=0;
//按面积查找最佳矩形
boundingRect=boundingRects.get(ixMaxArea);
边界直点(顶点);
rect=Imgproc.boundingRect(新的MatOfPoint(顶点));
maxArea=rect.area();
对于(int ix=1;ixmaxArea){
maxArea=rect.area();
ixMaxArea=ix;
}
}
bestRect=boundingRects.get(ixMaxArea);
}
返回bestRect;
}
专用静态位图findROI(位图源位图){
位图ROIBAMIT=Bitmap.createBitmap(sourceBitmap.getWidth()、sourceBitmap.getHeight()、Bitmap.Config.ARGB_8888);
Mat sourceMat=new Mat(sourceBitmap.getWidth()、sourceBitmap.getHeight()、CV_8UC3);
bitmapToMat(sourceBitmap,sourceMat);
最终材料=新材料();
sourceMat.copyTo(mat);
Imgproc.CVT颜色(mat、mat、Imgproc.COLOR_RGB2GRAY);
Imgproc.threshold(mat,mat,146250,Imgproc.THRESH_二进制);
//寻找轮廓
列表等高线=新的ArrayList();
List boundingRects=新建ArrayList();
Imgproc.findContours(mat、等高线、新mat()、Imgproc.RETR\u列表、Imgproc.CHAIN\u近似值\u简单值);
//找到合适的边界矩形
用于(点轮廓:轮廓){
MatOfPoint2f areaPoints=新的MatOfPoint2f(contour.toArray());
RotatedRect boundingRect=Imgproc.minareRect(面积点);
添加(boundingRect);
}
RotatedRect documentRect=getBestRectByArea(boundingRects);
if(documentRect!=null){
点矩形点[]=新点[4];
文件直点(直点);
对于(int i=0;i<4;++i){
Imgproc.line(源矩阵、矩形点[i]、矩形点[(i+1)%4]、ROI\u颜色、ROI\u宽度);
}
}
Utils.matToBitmap(sourceMat、roiBitmap);
返回位图;
}
您可以为源图像实现如下结果:
或