服务端代码:
import com.sun.jna.Library;
import com.sun.jna.Native;
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class OcrServer {
//全局是否运行中的标志位
private static ServerSocket server = null;
//TODO 修改监听端口
private static int iOcrPort = 4444;
private static String sOcrFolderName = "ocrLib";
private static String sHomePath = System.getProperty("user.dir");
private static String sDllPath = sHomePath+"\\"+ sOcrFolderName +"\\Ocr.dll";
//主程序
public static void main(String[] args) {
MyRunnable mi = new MyRunnable();
Thread t = new Thread(mi);
t.start();
}
//线程函数
static class MyRunnable implements Runnable {
@Override
public void run() {
startServer();
}
}
//CPU模式识别
private static void startServer() {
System.out.println("当前目录:"+sHomePath);
System.out.println("识别库目录:"+sHomePath+"\\"+ sOcrFolderName +"\\");
System.out.println("识别库DLL:"+sHomePath+"\\"+ sOcrFolderName +"\\Ocr.dll");
System.out.println("识别库初始化中......");
// 初始化识别库
//TODO 修改这里, 变更识别模式
// 第二个参数如果是CPU模式, 传-1, 如果是GPU模式, 传 GPU序号, 1块显卡传0, 2块显卡可以选0和1
OCRDll.INSTANCE.INIT(sHomePath +"\\"+ sOcrFolderName +"\\", -1, 1);
//图片数据放在这里
byte[] bData;
System.out.println("识别库初始化完成!");
System.out.println("正在启动服务器......");
InputStreamReader isr;
BufferedReader br;
OutputStreamWriter osw;
BufferedWriter bw;
String str, sFile;
try {
// 在本机的4444端口开放Server
server = new ServerSocket(iOcrPort);
System.out.println("服务器已启动, 监听端口: "+Integer.toString(iOcrPort));
CLibrary.INSTANCE.MessageBoxTimeoutA(0, "服务器已启动, 监听端口: "+Integer.toString(iOcrPort), "提示", 64, 0, 3000);
//不能开启超时, 开启后, 一段时间内没有客户端连接, 服务器就会退出.
//server.setSoTimeout(30000);
while (true) {
//只要产生连接,socket便可以代表所连接的那个物体,同时这个server.accept()只有产生了连接才会进行下一步操作。
Socket socket = server.accept();
InetAddress clientIp = socket.getInetAddress();
System.out.println("建立了一个连接!" + clientIp.toString());
//取得输入流
isr = new InputStreamReader(socket.getInputStream(), "GBK");
br = new BufferedReader(isr);
clientIp = socket.getInetAddress();
sFile = br.readLine();
if(sFile != null){
System.out.println(clientIp.toString() + ":" + sFile.length());
//取得输出流对象
osw = new OutputStreamWriter(socket.getOutputStream(), "GBK");
bw = new BufferedWriter(osw);
//删除十六进制开头的0x符
sFile = sFile.substring(2,sFile.length());
//把读取到的十六进制文本, 转成字节数组
bData = hexstring2byte(sFile);
//如果转成功了. 则去识别
if(bData.length > 0){
//System.out.println("图片长度:"+bData.length);
str = doOcr(bData);
System.out.println("图片长度:"+bData.length +", 识别结果:" + str);
bw.write(str+"\n");
}
bw.flush();
bw.close();
osw.close();
}
br.close();
isr.close();
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("服务器启动失败,请检查端口是否被占用!");
CLibrary.INSTANCE.MessageBoxTimeoutA(0, "服务器启动失败,请检查端口是否被占用!", "警告", 48, 0, 3000);
}
}
//系统MessageBoxTimeoutA API
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary) Native.loadLibrary("User32", CLibrary.class);
//int MessageBoxTimeoutA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType, WORD wLanguageId, DWORD dwMilliseconds);
int MessageBoxTimeoutA(int hwnd, String sText, String sTitle, int uType, int wLanguageID, int dwMillisecondsi);
}
// OCR dll 调用接口
public interface OCRDll extends Library {
OCRDll INSTANCE = Native.loadLibrary(sDllPath, OCRDll.class);
void INIT(String rpcPath, int gpuID, int ii);
int OCR(byte[] read, int iLen, byte[] ret);
}
//真正的识别函数. 调用机器学习生成的DLL库, 识别图片
private static String doOcr(byte[] read) {
// 存储结果的缓冲区
byte[] bRet = new byte[512];
// 调用识别
OCRDll.INSTANCE.OCR(read, read.length, bRet);
// 存储结果字符串
String sRet = "";
// 从结果缓冲区中取出结果
for (byte aBRet : bRet) {
if (aBRet != 0)
sRet += (char) aBRet;
else
break;
}
//System.out.println("识别结果:" + sRet);
return sRet;
}
//16进制字符串到字节数组
private static byte[] hexstring2byte(String s) {
int len = s.length();
byte[] b = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
// 两位一组,表示一个字节,把这样表示的16进制字符串,还原成一个字节
b[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character
.digit(s.charAt(i + 1), 16));
}
return b;
}
}
客户端代码:
public static String ocr(BufferedImage imgPintu, String sIp, int sPort) {
String sRet = "";
try {
//连接服务端
Socket socket = new Socket();
//设置超时时间30秒
socket.connect(new InetSocketAddress(sIp, sPort), 30000);
//获取连接的IP
//InetAddress ipAddress = socket.getInetAddress();
// 输出连接者的IP。
//System.out.println(ipAddress.toString()+"成功连接服务器");
//获取输出流
OutputStreamWriter osw = new OutputStreamWriter(socket.getOutputStream(), "GBK");
BufferedWriter bw = new BufferedWriter(osw);
//通过数据流转字节数组
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(imgPintu, "png", out);
byte[] bImg= out.toByteArray();
//字节数组转16进制文本
String sImg = ManagePhoto.byte2hexstring(bImg);
System.out.println("图片长度 = "+bImg.length +"\r\n十六进制长度 = "+sImg.length());
//将内容写到输出流, 发送到服务器
bw.write(sImg+"\n");
bw.flush();
//取得输入流对象
InputStreamReader isr = new InputStreamReader(socket.getInputStream(), "GBK");
BufferedReader br = new BufferedReader(isr);
//读取结果
sRet = br.readLine();
//关闭连接
br.close();
isr.close();
bw.close();
osw.close();
socket.close();
} catch (Exception e) {
System.err.println("Error: Connect server failed!!");
}
//如果返回结果长度大于10, 证明是正确的
if (sRet != null && sRet.length() > 10)
sRet = sRet.substring(0, sRet.length() - 1);
//System.out.println( "识别结果 = " +sRet );
return sRet;
}
// byte数组到16进制字符串
public static String byte2hexstring(byte[] data) {
if (data == null || data.length <= 1)
return "0x";
StringBuffer sb = new StringBuffer();
int buf[] = new int[data.length];
for (int k = 0; k < data.length; k++) {
buf[k] = data[k] < 0 ? (data[k] + 256) : (data[k]);
}
for (int k = 0; k < buf.length; k++) {
if (buf[k] < 16)
sb.append("0" + Integer.toHexString(buf[k]));
else
sb.append(Integer.toHexString(buf[k]));
}
return "0x" + sb.toString().toUpperCase();
}