Java中的图像处理边缘检测 [英] Image Processing Edge Detection in Java

查看:164
本文介绍了Java中的图像处理边缘检测的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



这些是更多细节:




  • 在一张纸上印有一张类似于桌子的表格,将其扫描成图像文件。

  • 我将用Java打开图片,我将有一个OVERLAY文本框。

  • 文本框应该与扫描图像正确对齐。

  • 为了正确对齐,我的Java程序必须分析扫描图像并检测扫描图像上表格边缘的坐标,从而定位图像和文本框,使文本框和图像都正确对齐(如果扫描不正确)



你看,扫描图像的人可能不一定将图像放在一个完全正确的位置,所以我需要我的程序自动对齐扫描的图像,因为它加载它。这个程序可以在许多这样的扫描图像上重复使用,所以我需要这个程序灵活。



我的问题是以下之一:


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


  2. 如果存在更简单的方法自动对齐扫描图像,使所有扫描图像的图形表格对齐相同的x,y坐标,然后分享此方法:)。


  3. <如果您不知道上述问题的答案,请告诉我应该从哪里开始。我不太了解图形java编程,我有大约1个月的时间来完成这个程序。假设我的日程安排很紧,我必须让图形部件尽可能简单。


干杯谢谢。

解决方案

我研究了这些库,但最后我发现编写自己的边缘检测更方便方法。



下面的类将检测包含此类边缘的扫描纸张的黑色/灰色边缘,并将返回边缘的x和y坐标。纸张,从最右端(反向=真)或从下端(反向=真)或从上边缘(反向=假)或从左边缘(反向=假)开始。此外...程序将采用沿像素测量的垂直边缘(rangex)范围和以像素为单位测量的水平范围(范围)。范围确定接收点中的异常值。



程序使用指定的数组进行4次垂直切割,并进行4次水平切割。它检索暗点的值。它使用范围来消除异常值。有时,纸上的小点可能会导致异常点。范围越小,异常值越少。但是,有时边缘略微倾斜,所以你不想让范围太小。



玩得开心。它非常适合我。

  import java.awt.image.BufferedImage; 
import java.awt.Color;
import java.util.ArrayList;
import java.lang.Math;
import java.awt.Point;
公共类EdgeDetection {

public App ap;
public int [] horizo​​ntalCuts = {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 = horizo​​ntalCuts;
int [] my = verticalCuts;

//你在这里获得边缘点
//true参数表示它从0开始执行切割。(左边缘)
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);
//false参数表示你从最后开始剪切(image.getHeight)
//结束于0
//如果参数为真,它会意味着它会在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);
}

//此函数采用一系列坐标...检测异常值,
//并计算非离群点的平均值。

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];
//这个代码段保存了点之间的差异
为(int n = 0; n< edges.length; n ++){
for(int m = 0; m< ; edges.length; m ++){
if(m< n){
difference [n] [m] = edges [n] - edges [m];
}否则if(m> n){
difference [n] [m-1] = edges [n] - edges [m];
}
}
}
//这个数组确定哪些点是异常值或不是(在其他点的范围内)
for(int n = 0; n< ; edges.length; n ++){
传递[n] = false;
for(int m = 0; m< edges.length-1; m ++){
if(Math.abs(differences [n] [m])< range){
pass [n] =真;
System.out.println(EDGECHECK = TRUE+ n);
休息;
}
}
}
//仅使用有效点创建一个新数组
for(int i = 0; i< edges.length; i ++){
if(pass [i]){
result.add(edges [i]);
}
}

//计算舍入均值...这将是边缘的x / y坐标
//它们是x还是y值取决于用于计算边数组的反向变量
int divisor = result.size();
int addend = 0;
双均值= 0;
for(整数i:结果){
addend + = i;
}
mean =(double)addend /(double)divisor;

//返回有效点的平均值:这是计算边缘的x或y坐标。
if(mean - (int)mean> = .5){
System.out.println(MEAN+ mean);
return(int)mean + 1;
} else {
System.out.println(MEAN+ mean);
return(int)mean;
}
}


//此函数计算暗点,包括浅灰色,以检测边缘。
// reverse - 当为true时,从x = 0或y = 0开始计数,结束于image.getWidth或image.getHeight()
// verticalEdge - 确定是否要检测垂直边缘或水平边缘
// arr [] - 确定你要做的垂直或水平切割的坐标
//根据扫描图像的图形布局设置arr []数组
// image - 这是你要检测
public int [] getEdges的黑/白边缘的图像(BufferedImage image,int [] arr,boolean reverse,boolean verticalEdge){
int红色= 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());){
颜色c =新颜色(image.getRGB(verticalEdge?m:arr [n] ,verticalEdge?arr [n]:m));
red = c.getRed();
green = c.getGreen();
blue = c.getBlue();
//确定该点是否被视为黑暗。
//如果你想只包含真正的黑点,修改范围。
//偶尔,边缘可能会模糊,浅灰色有助于
if(红色< 239&& green< 239&& blue< 239){
结果[n] = m;
休息;
}
//向前或向后计数取决于反向变量
if(reverse){
m--;
} else {
m ++;
}
}
}
返回结果;
}

}


This is my situation. It involves aligning a scanned image which will account for incorrect scanning. I must align the scanned image with my Java program.

These are more details:

  • There is a table-like form printed on a sheet of paper, which will be scanned into an image file.
  • I will open the picture with Java, and I will have an OVERLAY of text boxes.
  • The text boxes are supposed to align correctly with the scanned image.
  • In order to align correctly, my Java program must analyze the scanned image and detect the coordinates of the edges of the table on the scanned image, and thus position the image and the textboxes so that the textboxes and the image both align properly (in case of incorrect scanning)

You see, the guy scanning the image might not necessarily place the image in a perfectly correct position, so I need my program to automatically align the scanned image as it loads it. This program will be reusable on many of such scanned images, so I need the program to be flexible in this way.

My question is one of the following:

  1. How can I use Java to detect the y coordinate of the upper edge of the table and the x-coordinate of the leftmost edge of the table. The table is a a regular table with many cells, with black thin border, printed on a white sheet of paper (horizontal printout)

  2. If an easier method exists to automatically align the scanned image in such a way that all scanned images will have the graphical table align to the same x, y coordinates, then share this method :).

  3. If you don't know the answer to the above to questions, do tell me where I should start. I don't know much about graphics java programming and I have about 1 month to finish this program. Just assume that I have a tight schedule and I have to make the graphics part as simple as possible for me.

Cheers and thank you.

解决方案

I researched the libraries but in the end I found it more convenient to code up my own edge detection methods.

The class below will detect black/grayed out edges of a scanned sheet of paper that contains such edges, and will return the x and y coordinate of the edges of the sheet of paper, starting from the rightmost end (reverse = true) or from lower end (reverse = true) or from the top edge (reverse = false) or from left edge (reverse = false). Also...the program will take ranges along vertical edges (rangex) measured in pixels, and horizontal ranges (rangey) measured in pixels. The ranges determine outliers in the points received.

The program does 4 vertical cuts using the specified arrays, and 4 horizontal cuts. It retrieves the values of the dark dots. It uses the ranges to eliminate outliers. Sometimes, a little spot on the paper may cause an outlier point. The smaller the range, the fewer the outliers. However, sometimes the edge is slightly tilted, so you don't want to make the range too small.

Have fun. It works perfectly for me.

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;
    }

}

这篇关于Java中的图像处理边缘检测的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆