package com.timeschedule.timeschedule.utils;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.imageio.ImageIO;
public class OCR {
public static void main(String[] args) throws Exception {
for(int i=0;i<10;i++){
String fileName = "verifyCode"+(i+1)+".jpg";
//File testDataDir = new File("J:\\check\\old\\"+fileName);
//(testDataDir, "J:\\check\\cleanImage",440,160);
String result = recognizeText(new File("J:\\check\\cleanImage\\"+fileName));
System.out.println("识别结果为: "+result);
}
}
public static String recognizeText(File imageFile) throws IOException, InterruptedException {
// 将识别出的内容保存在txt临时文本中,目录与图片在同一级,读取万临时文件内容后会删除该文件
File tempFile = new File("J:\\check\\cleanImage", "temp");
StringBuffer result = new StringBuffer(); // 接收识别结果
// cmd 输出格式[C:\Program Files (x86)\Tesseract-OCR\tesseract, 1.png,
// output,-l, chi_sim]
List<String> cmd = new ArrayList<String>();
// 注意: D:\Tesseract\是你的tesseract-OCR的安装目录
// 我这里是默认安装目录
cmd.add("D:\\Tesseract\\tesseract");
cmd.add("");
cmd.add(tempFile.getName()); // 指定识别出内容保存位置
cmd.add("-l"); // 语言参数标志 注意 :这里是字母l 不是数字1
cmd.add("");
//cmd.add("verifyCode");
//cmd.add("eng");
cmd.add("chi_sim");
cmd.add("");
/* if (flag) { // 设置语言库 中文 chi_sim 英文 eng
cmd.add("chi_sim");
} else {
cmd.add("eng");
}*/
ProcessBuilder pb = new ProcessBuilder();
pb.directory(imageFile.getParentFile()); // 设置进程工作目录
cmd.set(1, imageFile.getName());
pb.command(cmd);
pb.redirectErrorStream(true);
Process process = pb.start();
int w = process.waitFor(); // 进程等待
if (w == 0)// 0代表正常退出
{
BufferedReader in = new BufferedReader(
new InputStreamReader(new FileInputStream(tempFile.getAbsolutePath() + ".txt"), "UTF-8"));
String str;
while ((str = in.readLine()) != null) { // 读取识别结果
result.append(str);
}
in.close();
} else {
String msg;
switch (w) {
case 1:
msg = "Errors accessing files. There may be spaces in your image's filename.";
break;
case 29:
msg = "Cannot recognize the image or its selected region.";
break;
case 31:
msg = "Unsupported image format.";
break;
default:
msg = "Errors occurred.";
}
throw new RuntimeException(msg);
}
new File(tempFile.getAbsolutePath() + ".txt").delete(); // 删除临时生成的txt文件
return result.toString();
}
/**
*
* @param sfile
* 需要去噪的图像
* @param destDir
* 去噪后的图像保存地址
* @throws IOException
*/
public static void cleanImage(File sfile, String destDir,int width,int height)
throws Exception
{
File destF = new File(destDir);
if (!destF.exists())
{
destF.mkdirs();
}
BufferedImage bufferedImage = null;
try{
bufferedImage = ImageIO.read(sfile);
bufferedImage = resizeBufferedImage(bufferedImage,width,height,true);
}catch (Exception ex){
System.out.println(sfile.getName());
}
int h = bufferedImage.getHeight();
int w = bufferedImage.getWidth();
// 灰度化
int[][] gray = new int[w][h];
for (int x = 0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
int argb = bufferedImage.getRGB(x, y);
// 图像加亮(调整亮度识别率非常高)
int r = (int) (((argb >> 16) & 0xFF) * 1.1 + 30);
int g = (int) (((argb >> 8) & 0xFF) * 1.1 + 30);
int b = (int) (((argb >> 0) & 0xFF) * 1.1 + 30);
if (r >= 255)
{
r = 255;
}
if (g >= 255)
{
g = 255;
}
if (b >= 255)
{
b = 255;
}
gray[x][y] = (int) Math
.pow((Math.pow(r, 2.2) * 0.2973 + Math.pow(g, 2.2)
* 0.6274 + Math.pow(b, 2.2) * 0.0753), 1 / 2.2);
}
}
// 二值化
int threshold = ostu(gray, w, h);
BufferedImage binaryBufferedImage = new BufferedImage(w, h,
BufferedImage.TYPE_BYTE_BINARY);
for (int x = 0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
if (gray[x][y] > threshold)
{
gray[x][y] |= 0x00FFFF;
} else
{
gray[x][y] &= 0xFF0000;
}
binaryBufferedImage.setRGB(x, y, gray[x][y]);
}
}
// 矩阵打印
/*for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
if (isBlack(binaryBufferedImage.getRGB(x, y)))
{
System.out.print("*");
} else
{
System.out.print(" ");
}
}
System.out.println();
}*/
//saveImageAsJpg(binaryBufferedImage,new File(destDir, sfile.getName()).getPath(),160,440,true);
ImageIO.write(binaryBufferedImage, "jpg", new File(destDir, sfile
.getName()));
}
/**
* 调整bufferedimage大小
* @param source BufferedImage 原始image
* @param targetW int 目标宽
* @param targetH int 目标高
* @param flag boolean 是否同比例调整
* @return BufferedImage 返回新image
*/
private static BufferedImage resizeBufferedImage(BufferedImage source, int targetW, int targetH, boolean flag) {
int type = source.getType();
BufferedImage target = null;
double sx = (double) targetW / source.getWidth();
double sy = (double) targetH / source.getHeight();
/*if (flag && sx > sy) {
sx = sy;
targetW = (int) (sx * source.getWidth());
} else if(flag && sx <= sy){
sy = sx;
targetH = (int) (sy * source.getHeight());
}*/
if (type == BufferedImage.TYPE_CUSTOM) { // handmade
ColorModel cm = source.getColorModel();
WritableRaster raster = cm.createCompatibleWritableRaster(targetW, targetH);
boolean alphaPremultiplied = cm.isAlphaPremultiplied();
target = new BufferedImage(cm, raster, alphaPremultiplied, null);
} else {
target = new BufferedImage(targetW, targetH, type);
}
Graphics2D g = target.createGraphics();
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.drawRenderedImage(source, AffineTransform.getScaleInstance(sx, sy));
g.dispose();
return target;
}
/**
* @describe 等比缩小
* @param srcImage
* @param outFilePath
* @param width
* @param hight
* @param proportion
* @throws Exception
*/
public static void saveImageAsJpg(BufferedImage srcImage, String outFilePath,
int width, int hight, boolean proportion)throws Exception {
File saveFile = new File(outFilePath);
if (width > 0 || hight > 0) {
// 原图的大小
int sw = srcImage.getWidth();
int sh = srcImage.getHeight();
// 如果原图像的大小小于要缩放的图像大小,直接将要缩放的图像复制过去
if (sw > width && sh > hight) {
srcImage = resize(srcImage, width, hight);
} else {
String fileName = saveFile.getName();
String formatName = fileName.substring(fileName
.lastIndexOf('.') + 1);
ImageIO.write(srcImage, formatName, saveFile);
return;
}
}
// 缩放后的图像的宽和高
int w = srcImage.getWidth();
int h = srcImage.getHeight();
// 如果缩放后的图像和要求的图像宽度一样,就对缩放的图像的高度进行截取
if (w == width) {
// 计算X轴坐标
int x = 0;
int y = h / 2 - hight / 2;
saveSubImage(srcImage, new Rectangle(x, y, width, hight), saveFile);
}
// 否则如果是缩放后的图像的高度和要求的图像高度一样,就对缩放后的图像的宽度进行截取
else if (h == hight) {
// 计算X轴坐标
int x = w / 2 - width / 2;
int y = 0;
saveSubImage(srcImage, new Rectangle(x, y, width, hight), saveFile);
}
}
/**
* 实现缩放后的截图
* @param image 缩放后的图像
* @param subImageBounds 要截取的子图的范围
* @param subImageFile 要保存的文件
* @throws IOException
*/
private static void saveSubImage(BufferedImage image,
Rectangle subImageBounds, File subImageFile) throws IOException {
if (subImageBounds.x < 0 || subImageBounds.y < 0
|| subImageBounds.width - subImageBounds.x > image.getWidth()
|| subImageBounds.height - subImageBounds.y > image.getHeight()) {
System.out.println("Bad subimage bounds");
return;
}
BufferedImage subImage = image.getSubimage(subImageBounds.x,subImageBounds.y, subImageBounds.width, subImageBounds.height);
String fileName = subImageFile.getName();
String formatName = fileName.substring(fileName.lastIndexOf('.') + 1);
ImageIO.write(subImage, formatName, subImageFile);
}
/**
* 实现图像的等比缩放
* @param source
* @param targetW
* @param targetH
* @return
*/
private static BufferedImage resize(BufferedImage source, int targetW,
int targetH) {
// targetW,targetH分别表示目标长和宽
int type = source.getType();
BufferedImage target = null;
double sx = (double) targetW / source.getWidth();
double sy = (double) targetH / source.getHeight();
// 这里想实现在targetW,targetH范围内实现等比缩放。如果不需要等比缩放
// 则将下面的if else语句注释即可
if (sx < sy) {
sx = sy;
targetW = (int) (sx * source.getWidth());
} else {
sy = sx;
targetH = (int) (sy * source.getHeight());
}
if (type == BufferedImage.TYPE_CUSTOM) { // handmade
ColorModel cm = source.getColorModel();
WritableRaster raster = cm.createCompatibleWritableRaster(targetW,
targetH);
boolean alphaPremultiplied = cm.isAlphaPremultiplied();
target = new BufferedImage(cm, raster, alphaPremultiplied, null);
} else
target = new BufferedImage(targetW, targetH, type);
Graphics2D g = target.createGraphics();
// smoother than exlax:
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g.drawRenderedImage(source, AffineTransform.getScaleInstance(sx, sy));
g.dispose();
return target;
}
public static boolean isBlack(int colorInt)
{
Color color = new Color(colorInt);
if (color.getRed() + color.getGreen() + color.getBlue() <= 300)
{
return true;
}
return false;
}
public static boolean isWhite(int colorInt)
{
Color color = new Color(colorInt);
if (color.getRed() + color.getGreen() + color.getBlue() > 300)
{
return true;
}
return false;
}
public static int isBlackOrWhite(int colorInt)
{
if (getColorBright(colorInt) < 30 || getColorBright(colorInt) > 730)
{
return 1;
}
return 0;
}
public static int getColorBright(int colorInt)
{
Color color = new Color(colorInt);
return color.getRed() + color.getGreen() + color.getBlue();
}
public static int ostu(int[][] gray, int w, int h)
{
int[] histData = new int[w * h];
// Calculate histogram
for (int x = 0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
int red = 0xFF & gray[x][y];
histData[red]++;
}
}
// Total number of pixels
int total = w * h;
float sum = 0;
for (int t = 0; t < 256; t++)
sum += t * histData[t];
float sumB = 0;
int wB = 0;
int wF = 0;
float varMax = 0;
int threshold = 0;
for (int t = 0; t < 256; t++)
{
wB += histData[t]; // Weight Background
if (wB == 0)
continue;
wF = total - wB; // Weight Foreground
if (wF == 0)
break;
sumB += (float) (t * histData[t]);
float mB = sumB / wB; // Mean Background
float mF = (sum - sumB) / wF; // Mean Foreground
// Calculate Between Class Variance
float varBetween = (float) wB * (float) wF * (mB - mF) * (mB - mF);
// Check if new maximum found
if (varBetween > varMax)
{
varMax = varBetween;
threshold = t;
}
}
return threshold;
}
}