参考文章链接:
1.https://blog.csdn.net/kobesdu/article/details/8142068
2.https://blog.csdn.net/fjssharpsword/article/details/52651845
一、识别图片的步骤顺序如下:
1.先使用java代码对图片的亮度、对比度、饱和度进行调整
2.对图片进行的灰度化和二值化以便更好的识别
3.使用OCR库对处理后的文件进行识别
二、图片的分类以及不同的处理办法
1.简单图片
图片的背景颜色比较单一的,例如红绿灯的倒计时。在图片预处理的时候只需要保留图片中的红色、绿色以及黄色即可
颜色比较单一,代码思路就是读取图片后获取各个像素点的RGB数值,然后根据下面的阈值进行颜色替换就可以,使用的OCR白底黑字识别较高,所以替换时需要保留的替换成黑色,其余颜色全部替换白色即可。
检测所用的阈值如下
其中ThR=0.4;ThG=0.3,ThB=0.4,thy=0.85
这种方式,阈值在这个空间里很容易地找到。然而,出现了一些问题:这个标准化的空间,因为照度低(低RGB值),该转换是不稳定的,并在接近零的值,噪声被放大。
2.复杂背景图片
图片的背景颜色可能是一种或多种的情况。在图片预处理的时候则需要对图片进行一系列调整,测试代码如下,测试代码中的参数可能需要调整。
//读取原图片转化为BufferedImage对象
public static BufferedImage file2img(String imgpath) {
try {
BufferedImage bufferedImage=ImageIO.read(new File(imgpath));
return bufferedImage;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
//调整图片对比度、亮度和饱和度
public static BufferedImage changeImage(BufferedImage src, BufferedImage dest,float contrast,float brightness){
int width = src.getWidth();
int height = src.getHeight();
if ( dest == null )
dest = creatCompatibleDestImage( src, null );
int[] inPixels = new int[width*height];
int[] outPixels = new int[width*height];
src.getRGB( 0, 0, width, height, inPixels, 0, width );
int index = 0;
int[] rgbmeans = new int[3];
double redSum = 0, greenSum = 0, blueSum = 0;
double total = height * width;
for(int row=0; row<height; row++) {
int ta = 0, tr = 0, tg = 0, tb = 0;
for(int col=0; col<width; col++) {
index = row * width + col;
ta = (inPixels[index] >> 24) & 0xff;
tr = (inPixels[index] >> 16) & 0xff;
tg = (inPixels[index] >> 8) & 0xff;
tb = inPixels[index] & 0xff;
redSum += tr;
greenSum += tg;
blueSum +=tb;
}
}
rgbmeans[0] = (int)(redSum / total);
rgbmeans[1] = (int)(greenSum / total);
rgbmeans[2] = (int)(blueSum / total);
for(int row=0; row<height; row++) {
int ta = 0, tr = 0, tg = 0, tb = 0;
for(int col=0; col<width; col++) {
index = row * width + col;
ta = (inPixels[index] >> 24) & 0xff;
tr = (inPixels[index] >> 16) & 0xff;
tg = (inPixels[index] >> 8) & 0xff;
tb = inPixels[index] & 0xff;
tr -=rgbmeans[0];
tg -=rgbmeans[1];
tb -=rgbmeans[2];
tr = (int)(tr * contrast);
tg = (int)(tg * contrast);
tb = (int)(tb * contrast);
tr += (int)(rgbmeans[0] * brightness);
tg += (int)(rgbmeans[1] * brightness);
tb += (int)(rgbmeans[2] * brightness);
outPixels[index] = (ta << 24) | (clamp(tr) << 16) | (clamp(tg) << 8) | clamp(tb);
}
}
setRGB( dest, 0, 0, width, height, outPixels );
return dest;
}
//图片灰度化
public static BufferedImage Color2Gray(BufferedImage image){
//BufferedImage image;
try {
//image = ImageIO.read(file);
BufferedImage destImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
ColorConvertOp cco = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
cco.filter(image, destImage);
//img_color_brightness(destImage, 120);
//ImageIO.write(destImage, "png", destFile);
return destImage;
} catch (Exception e1) {
e1.printStackTrace();
return null;
}
}
//图片去燥二值化
public static BufferedImage cleanImage(BufferedImage bufferedImage){
try {
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]);
}
}
return binaryBufferedImage;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
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;
}
//保存图片,extent为格式,"jpg"、"png"等
public static void img2file(BufferedImage img,String extent,String newfile) {
try {
ImageIO.write(img, extent, new File(newfile));
} catch (Exception e) {
e.printStackTrace();
}
}
测试函数
public static void main(String[] args) {
//要处理的图片目录
File dir = new File("D:/newreport/picTest/1");
//列出目录中的图片,得到数组
File[] files = dir.listFiles();
for (int i = 0; i < files.length; i++) {
if(files[i].isFile()){
//读取原图片
BufferedImage bi=file2img(files[i].getAbsolutePath().toString()); //读取图片
//调整原图片对比度以及亮度参数 3.0f 0.5f
BufferedImage duibi1=changeImage(bi, null,3.0f,0.5f);
//对原图片进行灰度化
BufferedImage huisebi = Color2Gray(duibi1);
//灰度化图片调整对比度2.5f -1.0f
BufferedImage duibi2 = changeImage(huisebi, null,2.5f,-1.0f);
//图片二值化
BufferedImage erzhibi = cleanImage(duibi2);
//保存图片
img2file(erzhibi,"png","D:/newreport/picTest/2/" + "test" + i + ".png");
}
}
}
public static BufferedImage creatCompatibleDestImage(BufferedImage src,BufferedImage dest){
return new BufferedImage(src.getWidth(),src.getHeight(),BufferedImage.TYPE_INT_RGB);
}