Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
基于Java的图像处理边缘检测_Java_Image Processing - Fatal编程技术网

基于Java的图像处理边缘检测

基于Java的图像处理边缘检测,java,image-processing,Java,Image Processing,这就是我的处境。它涉及到对齐扫描图像,这将导致不正确的扫描。我必须将扫描的图像与我的Java程序对齐 详情如下: 有一张打印在一张纸上的表格,它将被扫描到一个图像文件中 我将用Java打开图片,我将有一个文本框覆盖 文本框应该与扫描的图像正确对齐 为了正确对齐,我的Java程序必须分析扫描的图像并检测扫描图像上表格边缘的坐标,从而定位图像和文本框,以便文本框和图像都正确对齐(如果扫描不正确) 你看,扫描图像的人可能不一定把图像放在完全正确的位置,所以我需要我的程序在加载图像时自动对齐扫描图像

这就是我的处境。它涉及到对齐扫描图像,这将导致不正确的扫描。我必须将扫描的图像与我的Java程序对齐

详情如下:

  • 有一张打印在一张纸上的表格,它将被扫描到一个图像文件中
  • 我将用Java打开图片,我将有一个文本框覆盖
  • 文本框应该与扫描的图像正确对齐
  • 为了正确对齐,我的Java程序必须分析扫描的图像并检测扫描图像上表格边缘的坐标,从而定位图像和文本框,以便文本框和图像都正确对齐(如果扫描不正确)
你看,扫描图像的人可能不一定把图像放在完全正确的位置,所以我需要我的程序在加载图像时自动对齐扫描图像。这个程序将在许多这样的扫描图像上重复使用,所以我需要这个程序以这种方式灵活

我的问题如下:

  • 如何使用Java检测表格上边缘的y坐标和表格最左边边缘的x坐标。表格是一个有许多单元格的常规表格,带有黑色薄边框,打印在一张白纸上(水平打印输出)

  • 如果存在一种更简单的方法自动对齐扫描图像,使所有扫描图像的图形表都对齐到相同的x、y坐标,则共享此方法:)

  • 如果你不知道以上问题的答案,请告诉我应该从哪里开始。我对图形java编程了解不多,我有大约一个月的时间来完成这个程序。假设我的日程安排很紧,我必须让图形部分对我来说尽可能简单


  • 干杯,谢谢。

    边缘检测通常是通过增强相邻像素之间的对比度来完成的,这样可以得到易于检测的线条,适合进一步处理

    为此,“内核”根据像素的初始值和该像素的邻域值对像素进行变换。一个好的边缘检测内核将增强相邻像素之间的差异,并降低具有相似邻域的像素的强度

    我先看一下索贝尔算符。这可能不会返回对您立即有用的结果;然而,这将使你比你在对该领域知之甚少的情况下解决问题更接近实际情况

    在获得一些清晰的边缘后,可以使用较大的核来检测两条线中出现90%弯曲的点,这可能会为您提供外部矩形的像素坐标,这对于您的目的来说已经足够了

    有了这些外部坐标,使新像素与旋转并移动到“匹配”位置的旧像素之间的平均值混合仍然是一个数学问题。结果(特别是如果您不知道抗锯齿数学)可能非常糟糕,会给图像增加模糊


    锐化滤镜可能是一个解决方案,但它们也有自己的问题,主要是通过增加颗粒度使图片更清晰。太多了,很明显,原始图像不是高质量的扫描。

    我过去做过类似的问题,基本上解决了表单的方向,重新对齐,重新缩放,我都准备好了。可以使用Hough变换来检测图像的角度偏移(即:旋转了多少),但仍然需要检测形状的边界。它还必须适应纸张本身的边界

    对我来说,这是一个幸运的突破,因为它基本上显示了一个黑色和白色的图像在一个大的黑色边界。
  • 应用积极的5x5中值滤波器以去除一些噪声
  • 从灰度转换为黑白(将强度值从[0255]重缩放为[0,1])
  • 计算主成分分析(即:根据计算出的特征值计算图像协方差矩阵的特征向量)() 4) 这会给你一个基向量。您只需使用它将图像重新定向到标准基矩阵(即:[1,0],[0,1])
  • 您的图像现在已完美对齐。我这样做是为了使整个人类大脑的MRI扫描方向正常化


    你也知道在真实的图像周围有一个巨大的黑色边框。您只需继续删除图像顶部和底部以及两侧的行,直到它们全部消失。目前为止,您可以暂时将7x7中值或模式过滤器应用于图像副本。它有助于从指纹、污垢等中排除最终图像中残留的过多边界。

    尝试从简单场景开始,然后改进方法

  • 检测拐角
  • 在窗体的边界中查找角
  • 使用表单角点坐标,计算旋转角度
  • 旋转/缩放图像
  • 映射表单中每个字段相对于表单原点坐标的位置
  • 匹配文本框
  • 本文末尾介绍的程序执行步骤1至3。它是使用。下图显示了检测到角点的输出图像

    程序还输出:旋转角度:1.6365770416167182

    源代码:

    import java.awt.Color;
    import java.awt.Point;
    import marvin.image.MarvinImage;
    import marvin.io.MarvinImageIO;
    import marvin.plugin.MarvinImagePlugin;
    import marvin.util.MarvinAttributes;
    import marvin.util.MarvinPluginLoader;
    
    public class FormCorners {
    
    public FormCorners(){
        // Load plug-in
        MarvinImagePlugin moravec = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.corner.moravec");
        MarvinAttributes attr = new MarvinAttributes();
    
        // Load image
        MarvinImage image = MarvinImageIO.loadImage("./res/printedForm.jpg");
    
        // Process and save output image
        moravec.setAttribute("threshold", 2000);
        moravec.process(image, null, attr);
        Point[] boundaries = boundaries(attr);
        image = showCorners(image, boundaries, 12);
        MarvinImageIO.saveImage(image, "./res/printedForm_output.jpg");
    
        // Print rotation angle
        double angle =  (Math.atan2((boundaries[1].y*-1)-(boundaries[0].y*-1),boundaries[1].x-boundaries[0].x) * 180 / Math.PI);
        angle =  angle >= 0 ? angle : angle + 360;
        System.out.println("Rotation angle:"+angle);
    }
    
    private Point[] boundaries(MarvinAttributes attr){
        Point upLeft = new Point(-1,-1);
        Point upRight = new Point(-1,-1);
        Point bottomLeft = new Point(-1,-1);
        Point bottomRight = new Point(-1,-1);
        double ulDistance=9999,blDistance=9999,urDistance=9999,brDistance=9999;
        double tempDistance=-1;
        int[][] cornernessMap = (int[][]) attr.get("cornernessMap");
    
        for(int x=0; x<cornernessMap.length; x++){
            for(int y=0; y<cornernessMap[0].length; y++){
                if(cornernessMap[x][y] > 0){
                    if((tempDistance = Point.distance(x, y, 0, 0)) < ulDistance){
                        upLeft.x = x; upLeft.y = y;
                        ulDistance = tempDistance;
                    } 
                    if((tempDistance = Point.distance(x, y, cornernessMap.length, 0)) < urDistance){
                        upRight.x = x; upRight.y = y;
                        urDistance = tempDistance;
                    }
                    if((tempDistance = Point.distance(x, y, 0, cornernessMap[0].length)) < blDistance){
                        bottomLeft.x = x; bottomLeft.y = y;
                        blDistance = tempDistance;
                    }
                    if((tempDistance = Point.distance(x, y, cornernessMap.length, cornernessMap[0].length)) < brDistance){
                        bottomRight.x = x; bottomRight.y = y;
                        brDistance = tempDistance;
                    }
                }
            }
        }
        return new Point[]{upLeft, upRight, bottomRight, bottomLeft};
    }
    
    private MarvinImage showCorners(MarvinImage image, Point[] points, int rectSize){
        MarvinImage ret = image.clone();
        for(Point p:points){
            ret.fillRect(p.x-(rectSize/2), p.y-(rectSize/2), rectSize, rectSize, Color.red);
        }
        return ret;
    }
    
    public static void main(String[] args) {
        new FormCorners();
    }
    }
    
    导入java.awt.Color;
    导入java.awt.Point;
    导入marvin.image.MarvinImage;
    导入marvin.io.MarvinImageIO;
    导入marvin.plugin.MarvinImagePlugin;
    导入marvin.util.MarvinAttributes;
    导入marvin.util.MarvinPluginLoader;
    公共类表格角{
    公共表格({
    //加载插件
    MarvinImagePlugin-moravec=MarvinPluginLoader.loadImage
    
    import java.awt.image.BufferedImage;
    import java.awt.Color;
    import java.util.ArrayList;
    import java.lang.Math;
    import java.awt.Point;
    public class EdgeDetection {
    
        public App ap;
            public int[] horizontalCuts = {120, 220, 320, 420};
            public int[] verticalCuts = {300, 350, 375, 400};
    
    
    
        public void printEdgesTest(BufferedImage image, boolean reversex, boolean reversey, int rangex, int rangey){
            int[] mx = horizontalCuts;
            int[] my = verticalCuts;
    
                //you are getting edge points here
                //the "true" parameter indicates that it performs a cut starting at 0. (left edge)
            int[] xEdges = getEdges(image, mx, reversex, true);
            int edgex = getEdge(xEdges, rangex);
            for(int x = 0; x < xEdges.length; x++){
                System.out.println("EDGE = " + xEdges[x]);
            }
            System.out.println("THE EDGE = " + edgex);
                //the "false" parameter indicates you are doing your cut starting at the end (image.getHeight)
                //and ending at 0
                //if the parameter was true, it would mean it would start the cuts at y = 0
            int[] yEdges = getEdges(image, my, reversey, false);
            int edgey = getEdge(yEdges, rangey);
            for(int y = 0; y < yEdges.length; y++){
                System.out.println("EDGE = " + yEdges[y]);
            }
            System.out.println("THE EDGE = " + edgey);
        }
    
        //This function takes an array of coordinates...detects outliers, 
        //and computes the average of non-outlier points.
    
        public int getEdge(int[] edges, int range){
            ArrayList<Integer> result = new ArrayList<Integer>();
            boolean[] passes = new boolean[edges.length];
            int[][] differences = new int[edges.length][edges.length-1];
            //THIS CODE SEGMENT SAVES THE DIFFERENCES BETWEEN THE POINTS INTO AN ARRAY
            for(int n = 0; n<edges.length; n++){
                for(int m = 0; m<edges.length; m++){
                    if(m < n){
                        differences[n][m] = edges[n] - edges[m];
                    }else if(m > n){
                        differences[n][m-1] = edges[n] - edges[m];
                    }
                }
            }
             //This array determines which points are outliers or nots (fall within range of other points)
            for(int n = 0; n<edges.length; n++){
                passes[n] = false;
                for(int m = 0; m<edges.length-1; m++){
                    if(Math.abs(differences[n][m]) < range){
                        passes[n] = true;
                        System.out.println("EDGECHECK = TRUE" + n);
                        break;
                    }
                }
            }
             //Create a new array only using valid points
            for(int i = 0; i<edges.length; i++){
                if(passes[i]){
                    result.add(edges[i]);
                }
            }
    
            //Calculate the rounded mean... This will be the x/y coordinate of the edge
            //Whether they are x or y values depends on the "reverse" variable used to calculate the edges array
            int divisor = result.size();
            int addend = 0;
            double mean = 0;
            for(Integer i : result){
                addend += i;
            }
            mean = (double)addend/(double)divisor;
    
            //returns the mean of the valid points: this is the x or y coordinate of your calculated edge.
            if(mean - (int)mean >= .5){
                System.out.println("MEAN " + mean);
                return (int)mean+1;
            }else{
                System.out.println("MEAN " + mean);
                return (int)mean;
            }       
        }
    
    
         //this function computes "dark" points, which include light gray, to detect edges.
         //reverse - when true, starts counting from x = 0 or y = 0, and ends at image.getWidth or image.getHeight()
         //verticalEdge - determines whether you want to detect a vertical edge, or a horizontal edge
         //arr[] - determines the coordinates of the vertical or horizontal cuts you will do
         //set the arr[] array according to the graphical layout of your scanned image
         //image - this is the image you want to detect black/white edges of
        public int[] getEdges(BufferedImage image, int[] arr, boolean reverse, boolean verticalEdge){
            int red = 255;
            int green = 255;
            int blue = 255;
            int[] result = new int[arr.length];
            for(int n = 0; n<arr.length; n++){
                for(int m = reverse ? (verticalEdge ? image.getWidth():image.getHeight())-1:0; reverse ? m>=0:m<(verticalEdge ? image.getWidth():image.getHeight());){
                    Color c = new Color(image.getRGB(verticalEdge ? m:arr[n], verticalEdge ? arr[n]:m));
                    red = c.getRed();
                    green = c.getGreen();
                    blue = c.getBlue();
                            //determine if the point is considered "dark" or not.
                            //modify the range if you want to only include really dark spots.
                            //occasionally, though, the edge might be blurred out, and light gray helps
                    if(red<239 && green<239 && blue<239){
                        result[n] = m;
                        break;
                    }
                            //count forwards or backwards depending on reverse variable
                    if(reverse){
                        m--;
                    }else{
                        m++;
                    }
                }
            }
        return result;
        }
    
    }