java - 使用 OpenCV 扫描文档
问题描述
我正在开发与此类似的 Android 文档扫描仪。
我对此进行了搜索,发现这可以通过 OpenCV 实现,因此从 OpenCV 开始。
我尝试了很多示例来从图像中检测文档,但无法检测图像是否具有浅色背景。检查示例图像以进行测试。
我正在使用 OpenCV Android SDK 并使用 java 代码进行图像处理。这是代码:
public void scanDocument(Bitmap mBitmap)
{
Mat mOriginalMat = convertToMat(mBitmap);
int mRatio = getRadio(mOriginalMat);
Size mSize = getImageFitSize(mOriginalMat, mRatio);
Mat resizedMat = resizeMat(mOriginalMat, mSize);
Mat colorMat = grayMat(resizedMat, mSize);
Mat blurMat = medianBlurMat(colorMat, mSize);
Mat thresholdMat = cannyEdgeMat(blurMat, mSize);
ArrayList<MatOfPoint> contourList = findContours(thresholdMat, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
double maxArea = 0.0;
int maxAreaIdx = -1;
Collections.sort(contourList, new Comparator<MatOfPoint>() {
@Override
public int compare(MatOfPoint lhs, MatOfPoint rhs)
{
return Double.valueOf(Imgproc.contourArea(rhs)).compareTo(Imgproc.contourArea(lhs));
}
});
ArrayList<MatOfPoint> contourListMax = new ArrayList<>();
for (int idx = 0; idx < contourList.size(); idx++)
{
MatOfPoint contour = contourList.get(idx);
MatOfPoint2f c2f = new MatOfPoint2f(contour.toArray());
MatOfPoint2f approx = new MatOfPoint2f();
double epsilon = Imgproc.arcLength(c2f, true);
Imgproc.approxPolyDP(c2f, approx, epsilon * 0.02, true);
Point[] points = approx.toArray();
MatOfPoint approxTemp = new MatOfPoint(approx.toArray());
if (points.length == 4 && Imgproc.isContourConvex(approxTemp) && maxArea < Imgproc.contourArea(approxTemp))
{
maxArea = Imgproc.contourArea(approxTemp);
maxAreaIdx = idx;
Point[] foundPoints = sortPoints(points);
contourListMax.add(approxTemp);
mPointFMap = new HashMap<>();
mPointFMap.put(0, new PointF((float) foundPoints[0].x + xGap, (float) foundPoints[0].y + yGap));
mPointFMap.put(1, new PointF((float) foundPoints[1].x + xGap, (float) foundPoints[1].y + yGap));
mPointFMap.put(2, new PointF((float) foundPoints[3].x + xGap, (float) foundPoints[3].y + yGap));
mPointFMap.put(3, new PointF((float) foundPoints[2].x + xGap, (float) foundPoints[2].y + yGap));
break;
}
}
Imgproc.drawContours(resizedMat, contourListMax, -1, new Scalar(255, 165, 0), 2);
showMatToImageView(resizedMat);
}
private Mat convertToMat(Bitmap bitmap)
{
Mat mat = Imgcodecs.imread(mFilePath);// new Mat(bitmap.getWidth(), bitmap.getHeight(), CvType.CV_8UC1);
Imgproc.cvtColor(mat, mat, Imgproc.COLOR_BGR2RGB);
return mat;
}
private double getRadio(Mat mat)
{
double ratio;
if (mat.size().width > mat.size().height)
ratio = mat.size().height / mMainLayout.getHeight();
else
ratio = mat.size().width / mMainLayout.getWidth();
return ratio;
}
private Size getImageFitSize(Mat mat, double ratio)
{
int height = Double.valueOf(mat.size().height / ratio).intValue();
int width = Double.valueOf(mat.size().width / ratio).intValue();
return new Size(width, height);
}
private void showMatToImageView(Mat mat)
{
final Bitmap bitmap = Bitmap.createBitmap(mat.width(), mat.height(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mat, bitmap);
runOnUiThread(new Runnable()
{
@Override
public void run()
{
mSourceImageView.setImageBitmap(bitmap);
mProgressBar.setVisibility(View.GONE);
}
});
}
private Mat resizeMat(Mat mat, Size size)
{
Mat resizedMat = new Mat(size, CvType.CV_8UC4);
Imgproc.resize(mat, resizedMat, size);
return resizedMat;
}
private Mat grayMat(Mat mat, Size size)
{
Mat grayMat = new Mat(size, CvType.CV_8UC4);
Imgproc.cvtColor(mat, grayMat, Imgproc.COLOR_RGB2GRAY, 4);
return grayMat;
}
private Mat medianBlurMat(Mat mat, Size size)
{
Mat blurMat = new Mat(size, CvType.CV_8UC4);
Imgproc.medianBlur(mat, blurMat, 3);
return blurMat;
}
private Mat cannyEdgeMat(Mat mat, Size size)
{
if (thresholdVal <= 0)
thresholdVal = 200;
Mat cannyEdgeMat = new Mat(size, CvType.CV_8UC1);
Imgproc.Canny(mat, cannyEdgeMat, thresholdVal * 0.5, thresholdVal, 3, true);
return cannyEdgeMat;
}
private ArrayList<MatOfPoint> findContours(Mat mat, int retrievalMode, int approximationMode)
{
ArrayList<MatOfPoint> contourList = new ArrayList<>();
Mat hierarchy = new Mat();
Imgproc.findContours(mat, contourList, hierarchy, retrievalMode, approximationMode);
hierarchy.release();
return contourList;
}
我想在透视变换的帮助下检测文档点,我会将文档转换为直线并进行其他图像过滤。
获取此结果图像。
请帮我解决这个问题。
解决方案
您的问题是在资源非常有限的领域。事实上,我已经从字面上复制粘贴了上面的代码,因为我什至不知道从哪里开始。但是,您也没有包括该行中使用的sortPoints()函数Point[] foundPoints = sortPoints(points);
,thresholdVal,xGap和yGap整数。它们是如何初始化的?通过分享其余的代码,你会帮我一个大忙。谢谢你。
推荐阅读
- ibm-doors - 门计算所有链接
- tensorflow - 内存泄漏 tf.data + Keras
- php - 输入 type="date" 如何格式化?
- mysql - 如何从逗号分隔字符串中获取 find_in_set 的记录。[MySql]
- azure - 我的 cosmosdb 连接存在身份验证问题
- nginx - nginx中if的invalid_referer语法
- reactjs - 如何在 React 应用程序之间共享 redux 代码
- java - 即使提供运行时读写权限,也无法在 sd 卡(外部存储)上创建文本文件
- java - Outlook 和 Office 365 无法识别 ICS 文件
- postgresql - Docker 容器:数据库中不存在关系 X