Android 如何使用摄像头对文档识别图像执行自动裁剪?
我想做一个像cam扫描仪一样的应用程序来裁剪文档 但我需要像我的两个图像一样的功能 第一幅图像显示的是摄像机拍摄的图像 第二个图像识别这样的捕获图像部分 我的研究越来越多,但没有得到任何结果,所以,我在这里问,如果有人这样做,告诉我Android 如何使用摄像头对文档识别图像执行自动裁剪?,android,opencv,ocr,crop,Android,Opencv,Ocr,Crop,我想做一个像cam扫描仪一样的应用程序来裁剪文档 但我需要像我的两个图像一样的功能 第一幅图像显示的是摄像机拍摄的图像 第二个图像识别这样的捕获图像部分 我的研究越来越多,但没有得到任何结果,所以,我在这里问,如果有人这样做,告诉我 谢谢我想你的问题是检测要扫描的对象 像模式匹配或特征检测这样的对象检测机制不会给你带来你想要的结果,因为你不知道你正在扫描的对象到底是什么 基本上,你在图片中搜索一个矩形物体 解决这一问题的基本方法如下: 在图像上运行一个命令。在进行此操作之前,可以将图像模糊
谢谢我想你的问题是检测要扫描的对象 像模式匹配或特征检测这样的对象检测机制不会给你带来你想要的结果,因为你不知道你正在扫描的对象到底是什么 基本上,你在图片中搜索一个矩形物体 解决这一问题的基本方法如下:
- 在图像上运行一个命令。在进行此操作之前,可以将图像模糊一点。物体的边缘应清晰可见
- 现在,您需要执行一个步骤来查找图片中的线条
- 搜索彼此成90度角的线。问题是要找到合适的。也许使用最接近画面框架的线条就足够了,这些线条与它们相当平行
- 找到相交点以定义对象的边
需要记住的一点是,Java包装器的几乎每个函数都调用一个本机方法。那要花很多时间。因此,在将结果返回到Java部分之前,您希望尽可能多地使用本机代码。我知道现在回答这个问题已经太迟了,但这可能会对某些人有所帮助 请尝试以下代码
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
path = new Path();
path.moveTo(x1, y1); // this should set the start point right
//path.lineTo(x1, y1); <-- this line should be drawn at the end of course,sorry
path.lineTo(x2, y2);
path.lineTo(x3, y3);
path.lineTo(x4, y4);
path.lineTo(x1, y1);
canvas.drawPath(path, currentPaint);
}
@覆盖
受保护的void onDraw(画布){
super.onDraw(帆布);
路径=新路径();
path.moveTo(x1,y1);//这应该设置正确的起点
//path.lineTo(x1,y1);使用以下方法传递图像垫:
void findSquares(Mat image, List<MatOfPoint> squares) {
int N = 10;
squares.clear();
Mat smallerImg = new Mat(new Size(image.width() / 2, image.height() / 2), image.type());
Mat gray = new Mat(image.size(), image.type());
Mat gray0 = new Mat(image.size(), CvType.CV_8U);
// down-scale and upscale the image to filter out the noise
Imgproc.pyrDown(image, smallerImg, smallerImg.size());
Imgproc.pyrUp(smallerImg, image, image.size());
// find squares in every color plane of the image
Outer:
for (int c = 0; c < 3; c++) {
extractChannel(image, gray, c);
// try several threshold levels
Inner:
for (int l = 1; l < N; l++) {
Imgproc.threshold(gray, gray0, (l + 1) * 255 / N, 255, Imgproc.THRESH_BINARY);
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
// find contours and store them all as a list
Imgproc.findContours(gray0, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
MatOfPoint approx = new MatOfPoint();
// test each contour
for (int i = 0; i < contours.size(); i++) {
approx = approxPolyDP(contours.get(i), Imgproc.arcLength(new MatOfPoint2f(contours.get(i).toArray()), true) * 0.02, true);
// square contours should have 4 vertices after approximation
// relatively large area (to filter out noisy contours)
// and be convex.
// Note: absolute value of an area is used because
// area may be positive or negative - in accordance with the
// contour orientation
double area = Imgproc.contourArea(approx);
if (area > 5000) {
if (approx.toArray().length == 4 &&
Math.abs(Imgproc.contourArea(approx)) > 1000 &&
Imgproc.isContourConvex(approx)) {
double maxCosine = 0;
Rect bitmap_rect = null;
for (int j = 2; j < 5; j++) {
// find the maximum cosine of the angle between joint edges
double cosine = Math.abs(angle(approx.toArray()[j % 4], approx.toArray()[j - 2], approx.toArray()[j - 1]));
maxCosine = Math.max(maxCosine, cosine);
bitmap_rect = new Rect(approx.toArray()[j % 4], approx.toArray()[j - 2]);
}
// if cosines of all angles are small
// (all angles are ~90 degree) then write quandrange
// vertices to resultant sequence
if (maxCosine < 0.3)
squares.add(approx);
}
}
}
}
}
}
void findSquares(Mat图像、列表方块){
int N=10;
正方形。清除();
Mat smallerImg=new Mat(新尺寸(image.width()/2,image.height()/2,image.type());
Mat gray=新Mat(image.size(),image.type());
Mat gray0=新Mat(image.size(),CvType.CV_8U);
//缩小和放大图像以滤除噪声
pirdown(image,smallerImg,smallerImg.size());
pirup(smallerImg,image,image.size());
//在图像的每个颜色平面中查找正方形
外部:
对于(int c=0;c<3;c++){
提取通道(图像,灰色,c);
//尝试几个阈值级别
内部:
对于(int l=1;l5000){
如果(约toArray()。长度==4&&
数学绝对值(Imgproc轮廓面积(约))>1000&&
Imgproc.isContourConvex(近似值)){
双最大余弦=0;
矩形位图_Rect=null;
对于(int j=2;j<5;j++){
//求关节边之间角度的最大余弦
双余弦=数学绝对值(角度(约toArray()[j%4],约toArray()[j-2],约toArray()[j-1]);
maxCosine=Math.max(maxCosine,cosine);
位图_rect=new rect(约toArray()[j%4],约toArray()[j-2]);
}
//如果所有角度的余弦都很小
//(所有角度约为90度)然后写入量子线
//结果序列的顶点
如果(最大余弦<0.3)
正方形。添加(大约);
}
}
}
}
}
}
在此方法中,您可以获得四点文档,然后可以使用以下方法剪切此图像:
public Bitmap warpDisplayImage(Mat inputMat) {
List<Point> newClockVisePoints = new ArrayList<>();
int resultWidth = inputMat.width();
int resultHeight = inputMat.height();
Mat startM = Converters.vector_Point2f_to_Mat(orderRectCorners(Previes method four poit list(like : List<Point> points)));
Point ocvPOut4 = new Point(0, 0);
Point ocvPOut1 = new Point(0, resultHeight);
Point ocvPOut2 = new Point(resultWidth, resultHeight);
Point ocvPOut3 = new Point(resultWidth, 0);
ocvPOut3 = new Point(0, 0);
ocvPOut4 = new Point(0, resultHeight);
ocvPOut1 = new Point(resultWidth, resultHeight);
ocvPOut2 = new Point(resultWidth, 0);
}
Mat outputMat = new Mat(resultWidth, resultHeight, CvType.CV_8UC4);
List<Point> dest = new ArrayList<Point>();
dest.add(ocvPOut3);
dest.add(ocvPOut2);
dest.add(ocvPOut1);
dest.add(ocvPOut4);
Mat endM = Converters.vector_Point2f_to_Mat(dest);
Mat perspectiveTransform = Imgproc.getPerspectiveTransform(startM, endM);
Imgproc.warpPerspective(inputMat, outputMat, perspectiveTransform, new Size(resultWidth, resultHeight), Imgproc.INTER_CUBIC);
Bitmap descBitmap = Bitmap.createBitmap(outputMat.cols(), outputMat.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(outputMat, descBitmap);
return descBitmap;
}
公共位图显示图像(Mat inputMat){
List newClockVisePoints=new ArrayList();
int resultWidth=inputMat.width();
int resultHeight=inputMat.height();
Mat startM=Converters.vector_Point2f_to_Mat(orderRectCorners(预览方法四点列表(如:列表点));
点ocvPOut4=新点(0,0);
点ocvPOut1=新点(0,结果右侧);
点ocvPOut2=新点(结果宽度,结果宽度);
点ocvPOut3=新点(结果宽度,0);
ocvPOut3=新点(0,0);
ocvPOut4=新点(0,结果)