java - OpenCV 消除扫描伪影并旋转内容

标签 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

正如您所看到的 - 除了有用的内容之外,仍然存在一些带有红色轮廓的扫描伪影。

是否可以通过某种常见的方式(不仅适用于这张图片)删除这些扫描伪影而不损坏内容?

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

最佳答案

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

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

  • 转换为灰度
  • 应用模糊/平滑
  • 阈值图像
  • 应用形态扩张
  • 查找连接的组件
  • 过滤掉小面积的成分

--

高斯模糊

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 方法的第三个参数。查看代码,这意味着任何颜色值高于 150 的像素都将被替换为 255(白色)。因此,增加这个数字将导致黑色/文本像素减少。 减少数量将导致更多黑色区域,例如文物。

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

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

关于java - OpenCV 消除扫描伪影并旋转内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48660278/

相关文章:

java - Weblogic 12c Web 服务在部署时生成空指针异常

java - 将 java.time.LocalDateTime SE 8 转换为时间戳

java - 如何将 UTC 转换为日期时间?

c++ - 在 cv::Mat 和 Eigen::Matrix 之间转换矩阵

c++ - libcURL POST 分段上传(带缓冲图像)返回 HTTP 400

c++ - OpenCV (c++) 多 channel 元素访问

java - 哪个 Collection 会这样做?

java - 如何在java中对齐换行符?

android - 在后台运行 native 代码

python - opencv.groupRectangles() c++ 和 python 层之间的差异