接着上一篇OCR所说的,上一篇给大家介绍了tesseract 在命令行的简单用法,当然了要继承到我们的程序中,还是需要代码实现的,下面给大家分享下Java实现的例子。
拿代码扫描上面的图片,然后输出结果。主要思想就是利用Java调用系统任务。
下面是核心代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
package com.zhy.test; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import org.jdesktop.swingx.util.OS; public class OCRHelper { private final String LANG_OPTION = "-l" ; private final String EOL = System.getProperty( "line.separator" ); /** * 文件位置我防止在,项目同一路径 */ private String tessPath = new File( "tesseract" ).getAbsolutePath(); /** * @param imageFile * 传入的图像文件 * @param imageFormat * 传入的图像格式 * @return 识别后的字符串 */ public String recognizeText(File imageFile) throws Exception { /** * 设置输出文件的保存的文件目录 */ File outputFile = new File(imageFile.getParentFile(), "output" ); StringBuffer strB = new StringBuffer(); List<String> cmd = new ArrayList<String>(); if (OS.isWindowsXP()) { cmd.add(tessPath + "\\tesseract" ); } else if (OS.isLinux()) { cmd.add( "tesseract" ); } else { cmd.add(tessPath + "\\tesseract" ); } cmd.add( "" ); cmd.add(outputFile.getName()); cmd.add(LANG_OPTION); // cmd.add("chi_sim"); cmd.add( "eng" ); ProcessBuilder pb = new ProcessBuilder(); /** *Sets this process builder's working directory. */ pb.directory(imageFile.getParentFile()); cmd.set( 1 , imageFile.getName()); pb.command(cmd); pb.redirectErrorStream( true ); Process process = pb.start(); // tesseract.exe 1.jpg 1 -l chi_sim // Runtime.getRuntime().exec("tesseract.exe 1.jpg 1 -l chi_sim"); /** * the exit value of the process. By convention, 0 indicates normal * termination. */ // System.out.println(cmd.toString()); int w = process.waitFor(); if (w == 0 ) // 0代表正常退出 { BufferedReader in = new BufferedReader( new InputStreamReader( new FileInputStream(outputFile.getAbsolutePath() + ".txt" ), "UTF-8" )); String str; while ((str = in.readLine()) != null ) { strB.append(str).append(EOL); } 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(outputFile.getAbsolutePath() + ".txt" ).delete(); return strB.toString().replaceAll( "\\s*" , "" ); } } |
代码很简单,中间那部分ProcessBuilder其实就类似Runtime.getRuntime().exec("tesseract.exe 1.jpg 1 -l chi_sim"),大家不习惯的可以使用Runtime。
测试代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
package com.zhy.test; import java.io.File; public class Test { public static void main(String[] args) { try { File testDataDir = new File( "testdata" ); System.out.println(testDataDir.listFiles().length); int i = 0 ; for (File file :testDataDir.listFiles()) { i++ ; String recognizeText = new OCRHelper().recognizeText(file); System.out.print(recognizeText+ "\t" ); if ( i % 5 == 0 ) { System.out.println(); } } } catch (Exception e) { e.printStackTrace(); } } } |
输出结果:
对比第一张图片,是不是很完美~哈哈 ,当然了如果你只需要实现验证码的读写,那么上面就足够了。下面继续普及图像处理的知识。
当然了,有时候图片被扭曲或者模糊的很厉害,很不容易识别,所以下面我给大家介绍一个去噪的辅助类,绝对碉堡了,先看下效果图。
来张特写:
一个类,不依赖任何jar,把图像中的干扰线消灭了,是不是很给力,然后再拿这样的图片去识别,会不会效果更好呢,嘿嘿,大家自己实验~
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
|
package com.zhy.test; import java.awt.Color; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; public class ClearImageHelper { public static void main(String[] args) throws IOException { File testDataDir = new File( "testdata" ); final String destDir = testDataDir.getAbsolutePath()+ "/tmp" ; for (File file : testDataDir.listFiles()) { cleanImage(file, destDir); } } /** * * @param sfile * 需要去噪的图像 * @param destDir * 去噪后的图像保存地址 * @throws IOException */ public static void cleanImage(File sfile, String destDir) throws IOException { File destF = new File(destDir); if (!destF.exists()) { destF.mkdirs(); } BufferedImage bufferedImage = ImageIO.read(sfile); 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(); } ImageIO.write(binaryBufferedImage, "jpg" , new File(destDir, sfile .getName())); } 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; } } |
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:http://blog.csdn.net/lmj623565791/article/details/23960391