OpenCV删除扫描工件并旋转内容

时间:2018-02-07 09:33:53

标签: java opencv

我能够本地化以下图片的内容:

enter image description here

这是当前的Java代码:

    Mat image = Imgcodecs.imread("test.png");

    Mat gray = new Mat();
    Imgproc.cvtColor(image, gray, Imgproc.COLOR_BGR2GRAY);
    Core.absdiff(gray, new Scalar(255), gray);

    Imgproc.threshold(gray, gray, 5, 255, Imgproc.THRESH_TOZERO);

    Mat kernel1 = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(11, 11));
    Mat kernel2 = Mat.ones(3, 3, CvType.CV_8U);

    Mat erosion = new Mat();
    Imgproc.erode(gray, erosion, kernel2, new Point(-1, -1), 1);
    Mat dilation = new Mat();
    Imgproc.dilate(erosion, dilation, kernel1, new Point(-1, -1), 7);

    final List<MatOfPoint> contours = new ArrayList<>();
    final Mat hierarchy = new Mat();
    Imgproc.findContours(dilation, contours, hierarchy,
                         Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE);

    for (MatOfPoint contour : contours) {
        RotatedRect rect = Imgproc.minAreaRect(new MatOfPoint2f(contour.toArray()));
        Mat box = new Mat();
        Imgproc.boxPoints(rect, box);

        Imgproc.drawContours(image, contours, -1, new Scalar(0,0,255));
    }

这是结果图像:

enter image description here

正如您所看到的 - 连同有用的内容,仍然有一些扫描工件与红色轮廓一起。

是否可以以一些常见的方式删除这些扫描工件(这不仅适用于此图片)而不会损坏内容?

另外,如何根据轮廓正确旋转此图像内的内容(而不是图像本身)?

1 个答案:

答案 0 :(得分:2)

此问题可视为文本检测情况。

我们可以使用一些静态图像分析:

  • 转换为灰度
  • 应用模糊/平滑
  • 阈值图片
  • 应用形态消化
  • 查找已连接的组件
  • 过滤掉小区域的组件

-

高斯模糊

Gaussian Blurred

<强> 阈值

Thresholding

倒置颜色

Inverted

<强> 扩张

Dilated

检测到的区域(过滤后)更新

Painted

-

    System.load("opencv_java320.dll");

    Mat dst = new Mat();
    Mat src = Imgcodecs.imread("path/to/your/image.png");

    // Converting to Grey Scale
    Imgproc.cvtColor(src, dst, Imgproc.COLOR_RGB2GRAY, 0);

    // Blurring/Smoothing
    Imgproc.GaussianBlur(dst, src, new Size(15.0,15.0),0.0,0.0);

    // Thresholding / Binarization
    Imgproc.threshold(src, dst, 150,255,Imgproc.THRESH_BINARY);
    Mat painted = new Mat(); // UPDATED
    src.copyTo(painted); // UPDATED

    // Invert colors (helps with dilation)
    Core.bitwise_not(dst,src);

    // Image Dilation
    Mat structuringElement = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(55.0,55.0));
    Imgproc.dilate(src, dst, structuringElement);

    // Detect Text Areas
    List<Rect> textBlocks = findTextBlocks(dst);

    // Paint detected text areas
    paintTextBlocks(textBlocks, painted);
static List<Rect> findTextBlocks(Mat dilated)
{
    Mat labels = new Mat();
    Mat stats = new Mat();
    Mat centroids = new Mat();
    // Find connected components
    int numberOfLabels = Imgproc.connectedComponentsWithStats(dilated,labels,stats,centroids,8, CvType.CV_16U);
    List<Rect> textBlocks = new ArrayList<>();
    // adjust this threshold as your desire
    double sizeThreshold = 0.01;
    // Label 0 is considered to be the background label, so we skip it
    for (int i = 1; i < numberOfLabels; i++)
    {
        // stats columns; [0-4] : [left top width height area}
        Rect textBlock = new Rect(new Point(stats.get(i,0)[0],stats.get(i,1)[0]),new Size(stats.get(i,2)[0],
                stats.get(i,3)[0]));
        // stats.get(i,4)[0] is the area of the connected component / Filtering out small areas
        if (Double.compare(stats.get(i,4)[0],dilated.height() * dilated.width() * sizeThreshold) > 0){
            textBlocks.add(textBlock);
        }
    }
    return textBlocks;
}

static void paintTextBlocks(List<Rect> textBlocks, Mat original)
{
    for (Rect r : textBlocks)
    {
        Imgproc.rectangle(original, new Point(r.x,r.y), new Point(r.x+r.width,r.y+r.height),
                new Scalar(100.0),2);
    }
}

您可以调整/调整以下内容:

1)Imgproc.threshold方法的第3个参数。查看代码意味着任何颜色值高于150的像素都将替换为255(白色)。因此,增加此数字将导致更少的黑/文本像素。 减少数量将导致更多黑色区域,例如文物。

2) 扩张结构元素的大小(矩形)。宽度和高度应该相同并且都是奇数。结构元素的较小尺寸意味着较弱的膨胀;较小的连接组件。尺寸越大意味着扩张越宽,连接部件越大。

3)findTextBlocks()方法中的sizeThreshold。此变量根据其大小/面积控制连接组件的过滤强度。非常小的阈值将导致获得小区域,例如工件和大阈值将导致仅检测到非常大的区域。