java项目实战:处理图片水印,提取图片信息,生成excel表

  在这次应用软件设计课程中,要求从今年的软件杯大赛上的项目选择一个实现。我选的是"网店工商信息提取",具体要求就是:从给出的带水印的图片中提取出企业名称和企业注册号,并根据这些信息生成excel表格。

  刚刚开始以为这个要求挺难实现的,图片识别好像是很高深的技术啊。但是认真做起来从开工到完成也没花多少时间,并不是我完成了图片识别的代码,而是我用到了谷歌一个图片识别的源码包(TESS4J)。其实不止是图片识别这部分,生成excel表也是用的第三方源码包(感觉好方便)。早知道这么容易,后悔没有报名软件杯。。。

  这样,项目四个模块的功能(水印处理、图片识别、信息提取、生成excel表)我自己实现的其实只有信息提取和水印处理。虽然如此,还是有必要记录一下。

  下面上代码:

  首先是主函数RP.java:

import java.awt.Rectangle;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import net.sourceforge.tess4j.*;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.xssf.usermodel.*;



public class RP {
	private String a0="无法识别",c0="无法识别";
	
		public void PickUp(String s)             //提取文字中的公司名和注册号
		{
			int c1=-1,c2=-1;
			c1=s.lastIndexOf("号 :");
			c2=s.indexOf("\n");
			if(c1!=-1&&c2!=-1)
			{
				c0=s.substring(c1+4, c2);
				
			}
			int a1=-1,a2=-1;
			a1=s.indexOf("称 :");
			a2=s.lastIndexOf("\n");
			if(a1!=-1&&a2!=-1)
			{
				a0=s.substring(a1+4, a2);
				
			}
		/*	else{
				int b1=s.indexOf("名称:");
			    int b2=s.lastIndexOf("有限公司");
			    if(b1!=-1)
			    {
				  b0=s.substring(b1+3, b2+2);
				}
			}*/
		}
		public void toExcel(int i,XSSFWorkbook wb,XSSFSheet sheet)           //将文字信息做成表格
		{
			if(i==0)                                                    //第一行的话,就设置列名等属性
			{
				XSSFRow row=sheet.createRow(0);
				XSSFCellStyle style=(XSSFCellStyle)wb.createCellStyle();
				style.setAlignment(HorizontalAlignment.CENTER);
				XSSFCell cell=row.createCell(0);
				cell.setCellValue("企业名称");
		        cell.setCellStyle(style);          
		        cell = row.createCell(1); 
		        cell.setCellValue("企业注册号");  
		        cell.setCellStyle(style);
			}
			else                                   //不是第一行就将识别到的信息输入表格
			{
				XSSFRow row = sheet.createRow(i); 
				row.createCell(0).setCellValue(this.a0);  					
				row.createCell(1).setCellValue(this.c0); 
			}
		}
	public static void main(String[] args) throws IOException {
		RP rp=new RP();
		int num=1;
		Rectangle ret=new Rectangle(0,0,550,80);           //设置一个矩形区域,作为识别部分,减少运行时间提高识别率
		File root = new File(System.getProperty("user.dir") + "/imgs");//存放处理后的图片,imgs文件夹
		File res=new File(System.getProperty("user.dir") + "/res");//源图片位置,res文件夹下
		
		ITesseract instance = new Tesseract();
		instance.setLanguage("songti");              //使用训练好中文字库识别
		
		XSSFWorkbook wb=new XSSFWorkbook();
		XSSFSheet sheet=wb.createSheet("信息汇总");
		rp.toExcel(0,wb,sheet);        //设置列名
		
		try {
			File[] ress = res.listFiles();
			int i=0;
			for(File file : ress){
				i++;
				WaterMark.Clean(file.getAbsolutePath(),"F:\\eclipse-workspace\\ReadPicture\\imgs\\"+i+".png");
			}        //去除源图片水印,处理后的图片放到img文件夹
			
			
			File[] files = root.listFiles();
			for (File file : files) {                        //对去除水印后的图片逐个处理
				String result = instance.doOCR(file,ret);          //开始采用doOCR(file)效率很低,因为图片内容太多
				System.out.print(result);
				rp.a0="无法识别";
				rp.c0="无法识别";
				rp.PickUp(result);             //调用信息提取的函数,提取出企业名和企业注册号
				rp.toExcel(num,wb,sheet);      //调用toExcel函数,将提取到的信息写入
				num++;
			}
		} catch (TesseractException e) {
			System.err.println(e.getMessage());
		}
		
		
		 try {  
	            FileOutputStream fout = new FileOutputStream("F:\\company imformation\\company.xlsx");  
	            wb.write(fout);  
	            fout.close();  
	        } catch (IOException e) {  
	            e.printStackTrace();  
	        }                 //把写好信息的表输出
	}
	
}

然后是水印处理的:WaterMark.java:

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.awt.Color;


public class WaterMark   {
    public static void Clean( String frompath,String topath) throws IOException {
        File file1 = new File(frompath);
        BufferedImage image = ImageIO.read(file1);
        
        for(int i=0;i<550;i++)                    //这里只取x轴550,y轴80区域的像素点,因为需要识别的信息只在这个区域,这样可以节约程序运行时间
        {
            for(int j=0;j<80;j++)
            {
                int pixel = image.getRGB(i, j);        //获得坐标(i,j)的像素
                int red = (pixel & 0xff0000) >> 16;      
                int green = (pixel & 0xff00) >> 8;
                int blue = (pixel & 0xff);              //通过坐标(i,j)的像素值获得r,g,b的值
              
                if(red>=10&&red<=20&&green>=10&&green<=20&&blue>=10&&blue<=20)    //组成字符的像素点置为黑色
                {
                	int cover=new Color(0,0,0).getRGB();
                    image.setRGB(i,j,cover);
                }
                else 
                {
                    int white=new Color(255,255,255).getRGB();                   //其他全改为白色
                    image.setRGB(i,j,white);
                }
            }
        }
      /*for(int i=1;i<550;i++)  //获取一个像素点的四周像素点的rgb,如果这个点的上下都是黑或左右都是黑,则把这个点置为黑。减少失真程度
        {
            for(int j=1;j<80;j++)
            {
            	int t=0,d=0,r=0,l=0;
                
                int pixeltop = image.getRGB(i, j-1);
                int redtop = (pixeltop & 0xff0000) >> 16;
                int greentop = (pixeltop & 0xff00) >> 8;
                int bluetop = (pixeltop & 0xff);
                
                int pixelleft = image.getRGB(i-1, j);
                int redleft = (pixelleft & 0xff0000) >> 16;
                int greenleft = (pixelleft & 0xff00) >> 8;
                int blueleft = (pixelleft & 0xff);
                
                int pixelright = image.getRGB(i+1, j);
                int redright = (pixelright & 0xff0000) >> 16;
                int greenright= (pixelright& 0xff00) >> 8;
                int blueright = (pixelright & 0xff);
                
                int pixeldown = image.getRGB(i, j+1);
                int reddown = (pixeldown & 0xff0000) >> 16;
                int greendown= (pixeldown& 0xff00) >> 8;
                int bluedown = (pixeldown & 0xff);
                if(redtop==0&&greentop==0&&bluetop==0)
                {
                	t=1;
                }
                if(redleft==0&&greenleft==0&&blueleft==0)
                {
                	l=1;
                }
                if(redright==0&&greenright==0&&blueright==0)
                {
                	r=1;
                }
                if(reddown==0&&greendown==0&&bluedown==0)
                {
                	d=1;
                }
                if(r==1&&l==1)          //上下同时为黑,就把这个点置为黑
                {
                	int cover=new Color(0,0,0).getRGB();
                    image.setRGB(i,j,cover);
                }
                if(d==1&&t==1)       //左右同时为黑,就把这个点置为黑
                {
                	int cover=new Color(0,0,0).getRGB();
                    image.setRGB(i,j,cover);
                }
            }
        }*/   //其实这个处理步骤没有影响好像也不大,识别率也相当高了(训练了字库的前提下)

        File file2=new File(topath);
        ImageIO.write(image,"png",file2);       //图片更改后重新写入另一个文件夹
    }
}

  这里解释下获取RGB的代码:

int pixel = image.getRGB(i, j);      
int red = (pixel & 0xff0000) >> 16;      
int green = (pixel & 0xff00) >> 8;
int blue = (pixel & 0xff);

  对一个像素点getRGB后得到32位的值,r,g,b的值各占8位,如图:

  


  从右到左即从0到31。加入要获取g,就将像素值和0xff00按位相与,得到一个16位的值,其中低8位全为0,这样再将这个16位的值右移8位就得到了g的值。

  关于训练字库,这是我的同组同学完成的,可以参考这篇博客:

  https://blog.csdn.net/why200981317/article/details/48265621

  在导入所有的需要用到的jar包,并biuld path后,运行程序。源图片是这样的:

  java项目实战:处理图片水印,提取图片信息,生成excel表_第1张图片

  经过处理后是这样的:

java项目实战:处理图片水印,提取图片信息,生成excel表_第2张图片

有一些失真,但是经过训练字库影响不大。  

提取信息生成的excel表格:

java项目实战:处理图片水印,提取图片信息,生成excel表_第3张图片

简述一下程序的流程:

1.对图片进行去水印处理,这里只处理图片的一部分以节约程序运行时间。

2.用训练好的字库识别图片信息,这里指定只识别部分区域以节约程序运行时间,识别图片信息源码包是TESS4J包.

3.提取图片信息,提取出企业名称和企业注册号信息。

4.用提取到的信息生成excel表格,用到的源码包是poi包。

不知道导入哪些jar包的可以去直接下载:https://download.csdn.net/download/xlantian/10495923。文件有点大是因为字库文件占用空间较大。

最后致谢:训练字库的同学。







你可能感兴趣的:(项目实战)