diff --git a/open-anpr-client/pom.xml b/open-anpr-client/pom.xml new file mode 100644 index 0000000..65001e1 --- /dev/null +++ b/open-anpr-client/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + + com.visual.open.anpr + open-anpr-client + 1.0.0 + + + 8 + 8 + UTF-8 + + + + + com.alibaba + fastjson + 1.2.58 + + + org.apache.httpcomponents + httpclient + 4.5 + + + + \ No newline at end of file diff --git a/open-anpr-client/src/main/java/com/visual/open/anpr/PlateRecognition.java b/open-anpr-client/src/main/java/com/visual/open/anpr/PlateRecognition.java new file mode 100644 index 0000000..40d66ca --- /dev/null +++ b/open-anpr-client/src/main/java/com/visual/open/anpr/PlateRecognition.java @@ -0,0 +1,47 @@ +package com.visual.open.anpr; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import com.visual.open.anpr.handle.RecognitionHandler; + +public class PlateRecognition { + /**服务地址**/ + private String serverHost; + /**实例对象**/ + private final static Map ins = new ConcurrentHashMap<>(); + + /** + * 构建集合对象 + * @param serverHost 服务地址 + * @return + */ + private PlateRecognition(String serverHost){ + this.serverHost = serverHost; + } + + /** + * 构建集合对象 + * @param serverHost 服务地址 + * @return + */ + public static PlateRecognition build (String serverHost){ + String key = serverHost; + if(!ins.containsKey(key)){ + synchronized (PlateRecognition.class){ + if(!ins.containsKey(key)){ + ins.put(key, new PlateRecognition(serverHost)); + } + } + } + return ins.get(key); + } + /** + * 人脸比对操作对象 + * @return CollectHandler + */ + public RecognitionHandler detection(){ + return RecognitionHandler.build(serverHost); + } + + +} diff --git a/open-anpr-client/src/main/java/com/visual/open/anpr/common/Api.java b/open-anpr-client/src/main/java/com/visual/open/anpr/common/Api.java new file mode 100755 index 0000000..099938d --- /dev/null +++ b/open-anpr-client/src/main/java/com/visual/open/anpr/common/Api.java @@ -0,0 +1,12 @@ +package com.visual.open.anpr.common; + +public class Api { + + public static final String plate_recognition = "/visual/plate/recognition"; + + public static String getUrl(String host, String uri){ + host = host.replaceAll ("/+$", ""); + return host + uri; + } + +} diff --git a/open-anpr-client/src/main/java/com/visual/open/anpr/handle/RecognitionHandler.java b/open-anpr-client/src/main/java/com/visual/open/anpr/handle/RecognitionHandler.java new file mode 100644 index 0000000..28dc8b5 --- /dev/null +++ b/open-anpr-client/src/main/java/com/visual/open/anpr/handle/RecognitionHandler.java @@ -0,0 +1,63 @@ +package com.visual.open.anpr.handle; + +import com.alibaba.fastjson.TypeReference; +import com.visual.open.anpr.common.Api; +import com.visual.open.anpr.http.HttpClient; +import com.visual.open.anpr.model.Recognition; +import com.visual.open.anpr.model.RecognitionRep; +import com.visual.open.anpr.model.RecognitionReq; +import com.visual.open.anpr.model.Response; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class RecognitionHandler { + + /**服务地址**/ + protected String serverHost; + /**实例对象**/ + private final static Map ins = new ConcurrentHashMap<>(); + + public String getServerHost() { + return serverHost; + } + + public RecognitionHandler setServerHost(String serverHost) { + this.serverHost = serverHost; + return this; + } + + /** + * 构建车牌检测对象 + * @param serverHost 服务地址 + * @return + */ + public static RecognitionHandler build(String serverHost){ + String key = serverHost; + if(!ins.containsKey(key)){ + synchronized (RecognitionHandler.class){ + if(!ins.containsKey(key)){ + ins.put(key, new RecognitionHandler().setServerHost(serverHost)); + } + } + } + return ins.get(key); + } + + /** + * 车牌检测 + * @param recognition 待检测的数据信息 + * @return 车牌检测结果 + */ + public Response> recognition(Recognition recognition){ + RecognitionReq compareReq = RecognitionReq.build() + .setImage(recognition.getImage()) + .setLimit(recognition.getLimit()); + return HttpClient.post( + Api.getUrl(this.serverHost, Api.plate_recognition), + compareReq, + new TypeReference>>() {}); + } + +} diff --git a/open-anpr-client/src/main/java/com/visual/open/anpr/http/HttpClient.java b/open-anpr-client/src/main/java/com/visual/open/anpr/http/HttpClient.java new file mode 100755 index 0000000..1028324 --- /dev/null +++ b/open-anpr-client/src/main/java/com/visual/open/anpr/http/HttpClient.java @@ -0,0 +1,207 @@ +package com.visual.open.anpr.http; + +import com.alibaba.fastjson.TypeReference; + +import com.visual.open.anpr.model.MapParam; +import com.visual.open.anpr.model.Response; +import com.visual.open.anpr.utils.JsonUtil; +import org.apache.http.NameValuePair; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.BasicCookieStore; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.io.IOException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.LinkedList; +import java.util.List; + +public class HttpClient { + + /**编码方式*/ + private static final String ENCODING = "UTF-8"; + /**连接超时时间,10秒*/ + public static final int DEFAULT_CONNECT_TIMEOUT = 10 * 1000; + /**socket连接超时时间,10秒*/ + public static final int DEFAULT_READ_TIMEOUT = 10 * 000; + /**请求超时时间,60秒*/ + public static final int DEFAULT_CONNECT_REQUEST_TIMEOUT = 30 * 000; + /**最大连接数,默认为2*/ + private static final int MAX_TOTAL = 8; + /**设置指向特定路由的并发连接总数,默认为2*/ + private static final int MAX_PER_ROUTE = 4; + + private static RequestConfig requestConfig; + private static PoolingHttpClientConnectionManager connectionManager; + private static BasicCookieStore cookieStore; + private static HttpClientBuilder httpBuilder; + private static CloseableHttpClient httpClient; + private static CloseableHttpClient httpsClient; + private static SSLContext sslContext; + + /** + * 创建SSLContext对象,用来绕过https证书认证实现访问。 + */ + static { + try { + sslContext = SSLContext.getInstance("TLS"); + // 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法 + X509TrustManager tm = new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + } + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + } + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; + } + }; + sslContext.init(null, new TrustManager[] {tm}, null); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 初始化httpclient对象,以及在创建httpclient对象之前的一些自定义配置。 + */ + static { + // 自定义配置信息 + requestConfig = RequestConfig.custom() + .setSocketTimeout(DEFAULT_READ_TIMEOUT) + .setConnectTimeout(DEFAULT_CONNECT_TIMEOUT) + .setConnectionRequestTimeout(DEFAULT_CONNECT_REQUEST_TIMEOUT) + .build(); + //设置协议http和https对应的处理socket链接工厂的对象 + Registry socketFactoryRegistry = RegistryBuilder. create() + .register("http", new PlainConnectionSocketFactory()) + .register("https", new SSLConnectionSocketFactory(sslContext)) + .build(); + connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + // 设置cookie存储对像,在需要获取cookie信息时,可以使用这个对象。 + cookieStore = new BasicCookieStore(); + // 设置最大连接数 + connectionManager.setMaxTotal(MAX_TOTAL); + // 设置路由并发数 + connectionManager.setDefaultMaxPerRoute(MAX_PER_ROUTE); + httpBuilder = HttpClientBuilder.create(); + httpBuilder.setDefaultRequestConfig(requestConfig); + httpBuilder.setConnectionManager(connectionManager); + httpBuilder.setDefaultCookieStore(cookieStore); + // 实例化http 和 https的对象。 + httpClient = httpBuilder.build(); + httpsClient = httpBuilder.build(); + } + + /** + * post请求 + * @param url + * @param data + * @param + * @return + */ + public static Response post(String url, Object data) { + return post(url, data, new TypeReference>() {}); + } + + /** + * post请求 + * @param url + * @param data + * @param + * @return + */ + public static Response post(String url, Object data, TypeReference> type) { + // 创建HTTP对象 + HttpPost httpPost = new HttpPost(url); + httpPost.setConfig(requestConfig); + httpPost.addHeader("Content-Type", "application/json;charset=UTF-8"); + // 设置请求头 + if(null != data){ + String json = data instanceof String ? String.valueOf(data) : JsonUtil.toString(data); + StringEntity stringEntity = new StringEntity(json, ENCODING); + stringEntity.setContentEncoding(ENCODING); + httpPost.setEntity(stringEntity); + } + // 创建httpResponse对象 + CloseableHttpClient client = url.toLowerCase().startsWith("https") ? httpsClient : httpClient; + try { + CloseableHttpResponse httpResponse = client.execute(httpPost); + String content = EntityUtils.toString(httpResponse.getEntity(), ENCODING); + return JsonUtil.toEntity(content, type); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + + /** + * get + * @param url + * @param param + * @param + * @return + */ + public static Response get(String url, MapParam param) { + return get(url, param, new TypeReference>() {}); + } + + /** + * get + * @param url + * @param param + * @param + * @return + */ + public static Response get(String url, MapParam param, TypeReference> type) { + try { + //参数构建 + URIBuilder uriBuilder = new URIBuilder(url); + if(null != param && !param.isEmpty()){ + List list = new LinkedList<>(); + for(String key : param.keySet()){ + Object value = param.get(key); + if(null == value){ + list.add(new BasicNameValuePair(key, null)); + }else{ + list.add(new BasicNameValuePair(key, String.valueOf(value))); + } + } + uriBuilder.setParameters(list); + } + //构建请求 + HttpGet httpGet = new HttpGet(uriBuilder.build()); + httpGet.setConfig(requestConfig); + httpGet.addHeader("Content-Type", "application/json;charset=UTF-8"); + // 创建httpResponse对象 + CloseableHttpClient client = url.toLowerCase().startsWith("https") ? httpsClient : httpClient; + CloseableHttpResponse httpResponse = client.execute(httpGet); + String content = EntityUtils.toString(httpResponse.getEntity(), ENCODING); + return JsonUtil.toEntity(content, type); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/open-anpr-client/src/main/java/com/visual/open/anpr/http/HttpClientResult.java b/open-anpr-client/src/main/java/com/visual/open/anpr/http/HttpClientResult.java new file mode 100755 index 0000000..ac4fe00 --- /dev/null +++ b/open-anpr-client/src/main/java/com/visual/open/anpr/http/HttpClientResult.java @@ -0,0 +1,4 @@ +package com.visual.open.anpr.http; + +public class HttpClientResult { +} diff --git a/open-anpr-client/src/main/java/com/visual/open/anpr/http/HttpClientUtils.java b/open-anpr-client/src/main/java/com/visual/open/anpr/http/HttpClientUtils.java new file mode 100755 index 0000000..fedf3f5 --- /dev/null +++ b/open-anpr-client/src/main/java/com/visual/open/anpr/http/HttpClientUtils.java @@ -0,0 +1,455 @@ +package com.visual.open.anpr.http; + +import org.apache.http.NameValuePair; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.*; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.cookie.Cookie; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.BasicCookieStore; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.*; + +/** + * @Description: httpclient常用方法封装, + * @Author: ggf + * @Date: 2020/06/06 + */ +public class HttpClientUtils { + /** + * 编码方式 + */ + private static final String ENCODING = "UTF-8"; + /** + * 连接超时时间,60秒 + */ + public static final int DEFAULT_CONNECT_TIMEOUT = 6000; + /** + * socket连接超时时间,60秒 + */ + public static final int DEFAULT_READ_TIMEOUT = 6000; + /** + * 请求超时时间,60秒 + */ + public static final int DEFAULT_CONNECT_REQUEST_TIMEOUT = 6000; + /** + * 最大连接数,默认为2 + */ + private static final int MAX_TOTAL = 64; + /** + * 设置指向特定路由的并发连接总数,默认为2 + */ + private static final int MAX_PER_ROUTE = 32; + + private static RequestConfig requestConfig; + private static PoolingHttpClientConnectionManager connectionManager; + private static BasicCookieStore cookieStore; + private static HttpClientBuilder httpBuilder; + private static CloseableHttpClient httpClient; + private static CloseableHttpClient httpsClient; + private static SSLContext sslContext; + + /** + * 创建SSLContext对象,用来绕过https证书认证实现访问。 + */ + static { + try { + sslContext = SSLContext.getInstance("TLS"); + // 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法 + X509TrustManager tm = new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + } + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + } + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; + } + }; + sslContext.init(null, new TrustManager[] {tm}, null); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 初始化httpclient对象,以及在创建httpclient对象之前的一些自定义配置。 + */ + static { + // 自定义配置信息 + requestConfig = RequestConfig.custom() + .setSocketTimeout(DEFAULT_READ_TIMEOUT) + .setConnectTimeout(DEFAULT_CONNECT_TIMEOUT) + .setConnectionRequestTimeout(DEFAULT_CONNECT_REQUEST_TIMEOUT) + .build(); + //设置协议http和https对应的处理socket链接工厂的对象 + Registry socketFactoryRegistry = RegistryBuilder. create() + .register("http", new PlainConnectionSocketFactory()) + .register("https", new SSLConnectionSocketFactory(sslContext)) + .build(); + connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + // 设置cookie存储对像,在需要获取cookie信息时,可以使用这个对象。 + cookieStore = new BasicCookieStore(); + // 设置最大连接数 + connectionManager.setMaxTotal(MAX_TOTAL); + // 设置路由并发数 + connectionManager.setDefaultMaxPerRoute(MAX_PER_ROUTE); + httpBuilder = HttpClientBuilder.create(); + httpBuilder.setDefaultRequestConfig(requestConfig); + httpBuilder.setConnectionManager(connectionManager); + httpBuilder.setDefaultCookieStore(cookieStore); + // 实例化http 和 https的对象。 + httpClient = httpBuilder.build(); + httpsClient = httpBuilder.build(); + } + + /** + * 封装无参数的get请求(http) + * @param url 请求url + * @return 返回对象HttpClientResult + */ + public static HttpClientResult doGet(String url) { + return doGet(url, false); + } + + /** + * 封装无参get请求,支持https协议 + * @param url 请求url + * @param https 请求的是否是https协议,是:true 否false + * @return + */ + public static HttpClientResult doGet(String url, boolean https){ + return doGet(url, null, null, https); + } + + /** + * 封装带参数的get请求,支持https协议 + * @param url 请求url + * @param params 请求参数 + * @param https 是否是https协议 + */ + public static HttpClientResult doGet(String url, Map params, boolean https){ + return doGet(url, null, params, https); + } + + /** + * 封装带参数和带请求头信息的GET方法,支持https协议请求 + * @param url 请求url + * @param headers 请求头信息 + * @param params 请求参数 + * @param https 是否使用https协议 + */ + public static HttpClientResult doGet(String url, Map headers, Map params, boolean https){ + // 创建HttpGet + HttpGet httpGet = null; + // 创建httpResponse对象 + CloseableHttpResponse httpResponse = null; + try { + // 创建访问的地址 + URIBuilder uriBuilder = new URIBuilder(url); + if (params != null) { + Set> entrySet = params.entrySet(); + for (Map.Entry entry : entrySet) { + uriBuilder.setParameter(entry.getKey(), entry.getValue()); + } + } + // 创建HTTP对象 + httpGet = new HttpGet(uriBuilder.build()); + httpGet.setConfig(requestConfig); + // 设置请求头 + setHeader(headers, httpGet); + // 使用不同的协议进行请求,返回自定义的响应对象 + if (https) { + return getHttpClientResult(httpResponse, httpsClient, httpGet); + } else { + return getHttpClientResult(httpResponse, httpClient, httpGet); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + // 释放资源 + if (httpGet != null) { + httpGet.releaseConnection(); + } + release(httpResponse); + } + + return null; + } + + /** + * POST不带参数,只支持http协议 + * @param url 请求url + */ + public static HttpClientResult doPost(String url) { + return doPost(url, Boolean.FALSE); + } + + /** + * 封装不带参数的post请求,支持https协议 + * @param url 请求url + * @param https 是否是https协议 + */ + public static HttpClientResult doPost(String url, boolean https) { + return doPost(url, null, (Map)null, https); + } + + /** + * 带参数的post请求,支持https协议 + * @param url 请求url + * @param params 请求参数 + * @param https 是否是https协议 + */ + public static HttpClientResult doPost(String url, Map params, boolean https) { + return doPost(url, null, params, https); + } + + /** + * 带参数和请求头的POST请求,支持https + * + * @param url 请求url + * @param headers 请求头 + * @param params 请求参数,参数为K=V格式 + * @param https 是否https协议 + */ + public static HttpClientResult doPost(String url, Map headers, Map params, boolean https) { + // 创建HTTP对象 + HttpPost httpPost = new HttpPost(url); + httpPost.setConfig(requestConfig); + // 设置请求头 + setHeader(headers, httpPost); + // 封装请求参数 + setParam(params, httpPost); + // 创建httpResponse对象 + CloseableHttpResponse httpResponse = null; + try { + if (https) { + return getHttpClientResult(httpResponse, httpsClient, httpPost); + } else { + return getHttpClientResult(httpResponse, httpClient, httpPost); + } + } finally { + httpPost.releaseConnection(); + release(httpResponse); + } + } + + /** + * 带参数、带请求头的POST请求,支持https协议 + * + * @param url 请求url + * @param headers 请求头 + * @param json 请求参数为json格式 + * @param https 是否使用https协议 + * @throws Exception + */ + public static HttpClientResult doPost(String url, Map headers, String json, boolean https) { + // 创建HTTP对象 + HttpPost httpPost = new HttpPost(url); + httpPost.setConfig(requestConfig); + // 设置请求头 + setHeader(headers, httpPost); + StringEntity stringEntity = new StringEntity(json, ENCODING); + stringEntity.setContentEncoding(ENCODING); + httpPost.setEntity(stringEntity); + // 创建httpResponse对象 + CloseableHttpResponse httpResponse = null; + try { + if (https) { + return getHttpClientResult(httpResponse, httpsClient, httpPost); + } else { + return getHttpClientResult(httpResponse, httpClient, httpPost); + } + } finally { + httpPost.releaseConnection(); + release(httpResponse); + } + } + + + /** + * 发送put请求;不带请求参数 + * + * @param url 请求地址 + * @return + * @throws Exception + */ + public static HttpClientResult doPut(String url) { + return doPut(url); + } + + /** + * 发送put请求;带请求参数 + * + * @param url 请求地址 + * @param params 参数集合 + * @return + * @throws Exception + */ + public static HttpClientResult doPut(String url, Map params) { + HttpPut httpPut = new HttpPut(url); + httpPut.setConfig(requestConfig); + setParam(params, httpPut); + CloseableHttpResponse httpResponse = null; + try { + return getHttpClientResult(httpResponse, httpClient, httpPut); + } finally { + httpPut.releaseConnection(); + release(httpResponse); + } + } + + /** + * 发送delete请求,不带请求参数 + * + * @param url 请求url + * @return + * @throws Exception + */ + public static HttpClientResult doDelete(String url) { + HttpDelete httpDelete = new HttpDelete(url); + httpDelete.setConfig(requestConfig); + CloseableHttpResponse httpResponse = null; + try { + return getHttpClientResult(httpResponse, httpClient, httpDelete); + } finally { + httpDelete.releaseConnection(); + release(httpResponse); + } + } + + /** + * 发送delete请求,带请求参数, 支持https协议 + * + * @param url 请求url + * @param params 请求参数 + * @param https 是否https + * @return + * @throws Exception + */ + public static HttpClientResult doDelete(String url, Map params, boolean https) { + if (params == null) { + params = new HashMap(); + } + params.put("_method", "delete"); + return doPost(url, params, https); + } + + /** + * 获取cookie信息 + * @return 返回所有cookie集合 + */ + public static List getCookies() { + return cookieStore.getCookies(); + } + + + /** + * 设置封装请求头 + * + * @param params 头信息 + * @param httpMethod 请求对象 + */ + public static void setHeader(Map params, HttpRequestBase httpMethod) { + // 封装请求头 + if (null != params && !params.isEmpty()) { + Set> entrySet = params.entrySet(); + for (Map.Entry entry : entrySet) { + // 设置到请求头到HttpRequestBase对象中 + httpMethod.setHeader(entry.getKey(), entry.getValue()); + } + } + } + + /** + * 封装请求参数 + * + * @param params 请求参数 + * @param httpMethod 请求方法 + */ + public static void setParam(Map params, HttpEntityEnclosingRequestBase httpMethod) { + // 封装请求参数 + if (null != params && !params.isEmpty()) { + List nvps = new ArrayList(); + Set> entrySet = params.entrySet(); + for (Map.Entry entry : entrySet) { + nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); + } + + UrlEncodedFormEntity entity = null; + try { + entity = new UrlEncodedFormEntity(nvps, ENCODING); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + // 设置到请求的http对象中 + httpMethod.setEntity(entity); + } + } + + /** + * 获得响应结果 + * + * @param httpResponse 响应对象 + * @param httpClient httpclient对象 + * @param httpMethod 请求方法 + * @return + * @throws Exception + */ + public static HttpClientResult getHttpClientResult(CloseableHttpResponse httpResponse, CloseableHttpClient httpClient, HttpRequestBase httpMethod) { + try { + // 执行请求 + httpResponse = httpClient.execute(httpMethod); + // 获取返回结果 + if (httpResponse != null && httpResponse.getStatusLine() != null) { + String content = ""; + if (httpResponse.getEntity() != null) { + content = EntityUtils.toString(httpResponse.getEntity(), ENCODING); + } +// return new HttpClientResult(httpResponse.getStatusLine().getStatusCode(), content); + } + } catch (IOException e) { + e.printStackTrace(); + } +// return new HttpClientResult(HttpStatus.SC_INTERNAL_SERVER_ERROR); + return null; + } + + /** + * 释放资源 + * + * @param httpResponse 响应对象 + */ + public static void release(CloseableHttpResponse httpResponse) { + // 释放资源 + if (httpResponse != null) { + try { + httpResponse.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +} diff --git a/open-anpr-client/src/main/java/com/visual/open/anpr/model/MapParam.java b/open-anpr-client/src/main/java/com/visual/open/anpr/model/MapParam.java new file mode 100755 index 0000000..85b9a43 --- /dev/null +++ b/open-anpr-client/src/main/java/com/visual/open/anpr/model/MapParam.java @@ -0,0 +1,17 @@ +package com.visual.open.anpr.model; + +import java.util.HashMap; + +public class MapParam extends HashMap { + + public static MapParam build(){ + return new MapParam(); + } + + + public MapParam put(String key, Object value){ + super.put(key, value); + return this; + } + +} diff --git a/open-anpr-client/src/main/java/com/visual/open/anpr/model/PlateColor.java b/open-anpr-client/src/main/java/com/visual/open/anpr/model/PlateColor.java new file mode 100644 index 0000000..cabfffa --- /dev/null +++ b/open-anpr-client/src/main/java/com/visual/open/anpr/model/PlateColor.java @@ -0,0 +1,31 @@ +package com.visual.open.anpr.model; + +public enum PlateColor { + + BLACK("黑色"), + BLUE("蓝色"), + GREEN("绿色"), + WHITE("白色"), + YELLOW("黄色"), + UNKNOWN("未知"); + + private String name; + + PlateColor(String name){ + this.name = name; + } + + public String getName(){ + return this.name; + } + + public static PlateColor valueOfName(String name){ + for (PlateColor item : PlateColor.values()){ + if(item.name.equals(name)){ + return item; + } + } + return UNKNOWN; + } + +} diff --git a/open-anpr-client/src/main/java/com/visual/open/anpr/model/PlateLayout.java b/open-anpr-client/src/main/java/com/visual/open/anpr/model/PlateLayout.java new file mode 100644 index 0000000..d5ea815 --- /dev/null +++ b/open-anpr-client/src/main/java/com/visual/open/anpr/model/PlateLayout.java @@ -0,0 +1,8 @@ +package com.visual.open.anpr.model; + +public enum PlateLayout { + + SINGLE, //单排 + DOUBLE, //双排 + UNKNOWN; //未知 +} diff --git a/open-anpr-client/src/main/java/com/visual/open/anpr/model/PlateLocation.java b/open-anpr-client/src/main/java/com/visual/open/anpr/model/PlateLocation.java new file mode 100755 index 0000000..3078ba1 --- /dev/null +++ b/open-anpr-client/src/main/java/com/visual/open/anpr/model/PlateLocation.java @@ -0,0 +1,66 @@ +package com.visual.open.anpr.model; + +import java.io.Serializable; + +public class PlateLocation implements Serializable { + /**左上角x坐标**/ + private int x; + /**左上角y坐标**/ + private int y; + /**宽度**/ + private int w; + /**高度**/ + private int h; + + /** + * 构建坐标 + * @param x + * @param y + * @param w + * @param h + * @return + */ + public static PlateLocation build(int x, int y, int w, int h){ + return new PlateLocation().setX(x).setY(y).setW(w).setH(h); + } + + public static PlateLocation build(float x, float y, float w, float h){ + return new PlateLocation().setX((int) x).setY((int) y).setW((int) w).setH((int) h); + } + + public int getX() { + return x; + } + + public PlateLocation setX(int x) { + this.x = x; + return this; + } + + public int getY() { + return y; + } + + public PlateLocation setY(int y) { + this.y = y; + return this; + } + + public int getW() { + return w; + } + + public PlateLocation setW(int w) { + this.w = w; + return this; + } + + public int getH() { + return h; + } + + public PlateLocation setH(int h) { + this.h = h; + return this; + } +} diff --git a/open-anpr-client/src/main/java/com/visual/open/anpr/model/Recognition.java b/open-anpr-client/src/main/java/com/visual/open/anpr/model/Recognition.java new file mode 100644 index 0000000..3442660 --- /dev/null +++ b/open-anpr-client/src/main/java/com/visual/open/anpr/model/Recognition.java @@ -0,0 +1,40 @@ +package com.visual.open.anpr.model; + +import java.io.Serializable; + +public class Recognition> implements Serializable { + + /**图像Base64编码值**/ + private String image; + + /**搜索条数:默认5**/ + private Integer limit = 5; + + /** + * 构建比对对象 + * @return + */ + public static Recognition build(){ + return new Recognition(); + } + + + public String getImage() { + return image; + } + + public ExtendsVo setImage(String image) { + this.image = image; + return (ExtendsVo) this; + } + + public Integer getLimit() { + return limit; + } + + public ExtendsVo setLimit(Integer limit) { + this.limit = limit; + return (ExtendsVo) this; + } + +} diff --git a/open-anpr-client/src/main/java/com/visual/open/anpr/model/RecognitionInfo.java b/open-anpr-client/src/main/java/com/visual/open/anpr/model/RecognitionInfo.java new file mode 100644 index 0000000..d437812 --- /dev/null +++ b/open-anpr-client/src/main/java/com/visual/open/anpr/model/RecognitionInfo.java @@ -0,0 +1,36 @@ +package com.visual.open.anpr.model; + +import java.io.Serializable; + +public class RecognitionInfo implements Serializable { + /**车牌布局,单排还是双排**/ + private PlateLayout layout; + /**车牌文本信息**/ + private String plateNo; + /**车牌的颜色信息**/ + private PlateColor plateColor; + + public PlateLayout getLayout() { + return layout; + } + + public void setLayout(PlateLayout layout) { + this.layout = layout; + } + + public String getPlateNo() { + return plateNo; + } + + public void setPlateNo(String plateNo) { + this.plateNo = plateNo; + } + + public PlateColor getPlateColor() { + return plateColor; + } + + public void setPlateColor(PlateColor plateColor) { + this.plateColor = plateColor; + } +} diff --git a/open-anpr-client/src/main/java/com/visual/open/anpr/model/RecognitionRep.java b/open-anpr-client/src/main/java/com/visual/open/anpr/model/RecognitionRep.java new file mode 100644 index 0000000..2643fec --- /dev/null +++ b/open-anpr-client/src/main/java/com/visual/open/anpr/model/RecognitionRep.java @@ -0,0 +1,40 @@ +package com.visual.open.anpr.model; + +import java.io.Serializable; + +public class RecognitionRep implements Serializable { + + /**车牌置信分数**/ + private Float score; + + /**车牌位置信息**/ + private PlateLocation location; + + /**车牌识别信息**/ + private RecognitionInfo recognition; + + public Float getScore() { + return score; + } + + public void setScore(Float score) { + this.score = score; + } + + public PlateLocation getLocation() { + return location; + } + + public void setLocation(PlateLocation location) { + this.location = location; + } + + public RecognitionInfo getRecognition() { + return recognition; + } + + public void setRecognition(RecognitionInfo recognition) { + this.recognition = recognition; + } + +} diff --git a/open-anpr-client/src/main/java/com/visual/open/anpr/model/RecognitionReq.java b/open-anpr-client/src/main/java/com/visual/open/anpr/model/RecognitionReq.java new file mode 100644 index 0000000..ae55fc2 --- /dev/null +++ b/open-anpr-client/src/main/java/com/visual/open/anpr/model/RecognitionReq.java @@ -0,0 +1,13 @@ +package com.visual.open.anpr.model; + +public class RecognitionReq extends Recognition{ + + /** + * 构建比对对象 + * @return + */ + public static RecognitionReq build(){ + return new RecognitionReq(); + } + +} diff --git a/open-anpr-client/src/main/java/com/visual/open/anpr/model/Response.java b/open-anpr-client/src/main/java/com/visual/open/anpr/model/Response.java new file mode 100755 index 0000000..9be1c3d --- /dev/null +++ b/open-anpr-client/src/main/java/com/visual/open/anpr/model/Response.java @@ -0,0 +1,62 @@ +package com.visual.open.anpr.model; + +import java.io.Serializable; + +/** + * des:接口返回对象 + * @author diven + * @date 上午9:34 2018/7/12 + */ +public class Response implements Serializable{ + + private static final long serialVersionUID = -6919611972884058300L; + + private Integer code = -1; + private String message; + private T data; + + public Response(){} + + public Response(Integer code, String message, T data) { + if(null != code) { + this.code = code; + } + this.message = message; + this.data = data; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + if(null != code){ + this.code = code; + } + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + public boolean ok(){ + return new Integer(0).equals(code); + } + + @Override + public String toString() { + return "Response{" + "code=" + code + ", message='" + message + '\'' + ", data=" + data + '}'; + } +} diff --git a/open-anpr-client/src/main/java/com/visual/open/anpr/utils/Base64Util.java b/open-anpr-client/src/main/java/com/visual/open/anpr/utils/Base64Util.java new file mode 100755 index 0000000..c4b4445 --- /dev/null +++ b/open-anpr-client/src/main/java/com/visual/open/anpr/utils/Base64Util.java @@ -0,0 +1,48 @@ +package com.visual.open.anpr.utils; + +import org.apache.commons.codec.binary.Base64; + +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class Base64Util { + + public static String encode(byte[] binaryData) { + byte[] bytes = Base64.encodeBase64(binaryData); + return new String(bytes); + } + + public static String encode(InputStream in) { + // 读取图片字节数组 + try { + ByteArrayOutputStream swapStream = new ByteArrayOutputStream(); + byte[] buff = new byte[100]; + int rc; + while ((rc = in.read(buff, 0, 100)) > 0) { + swapStream.write(buff, 0, rc); + } + return encode(swapStream.toByteArray()); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + public static String encode(String filePath){ + try { + return encode(new FileInputStream(filePath)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/open-anpr-client/src/main/java/com/visual/open/anpr/utils/JsonUtil.java b/open-anpr-client/src/main/java/com/visual/open/anpr/utils/JsonUtil.java new file mode 100755 index 0000000..b6ba927 --- /dev/null +++ b/open-anpr-client/src/main/java/com/visual/open/anpr/utils/JsonUtil.java @@ -0,0 +1,128 @@ +package com.visual.open.anpr.utils; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.TypeReference; +import com.alibaba.fastjson.serializer.SerializerFeature; + +import java.util.List; +import java.util.Map; + +public class JsonUtil { + + /** + * 将Bean转化为json字符串 + * + * @param obj bean对象 + * @return json + */ + public static String toString(Object obj) { + return toString(obj, false, false); + } + + public static String toSimpleString(Object obj) { + return toString(obj, false, true); + } + + /** + * 将Bean转化为json字符串 + * + * @param obj bean对象 + * @param prettyFormat 是否格式化 + * @return json + */ + public static String toString(Object obj, boolean prettyFormat, boolean noNull) { + if (prettyFormat) { + if (noNull) { + return JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.PrettyFormat); + } else { + return JSON.toJSONString(obj, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullListAsEmpty, SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.PrettyFormat); + } + } else { + if (noNull) { + return JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect); + } else { + return JSON.toJSONString(obj, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullListAsEmpty, SerializerFeature.DisableCircularReferenceDetect); + } + } + } + + + /** + * 将字符串转换为Entity + * + * @param json 数据字符串 + * @param clazz Entity class + * @return + */ + public static T toEntity(String json, Class clazz) { + return JSON.parseObject(json, clazz); + } + + /** + * 将字符串转换为Entity + * + * @param json 数据字符串 + * @param typeReference Entity class + * @return + */ + public static T toEntity(String json, TypeReference typeReference) { + return JSON.parseObject(json, typeReference); + } + + /** + * 将字符串转换为Map + * + * @param json 数据字符串 + * @return Map + */ + public static Map toMap(String json) { + return JSON.parseObject(json, new TypeReference>() { + }); + } + + /** + * 将字符串转换为List + * + * @param json 数据字符串 + * @param collectionClass 泛型 + * @return list + */ + public static List toList(String json, Class collectionClass) { + return JSON.parseArray(json, collectionClass); + } + + /** + * 将字符串转换为List> + * + * @param json 数据字符串 + * @return list + */ + public static List> toListMap(String json) { + return JSON.parseObject(json, new TypeReference>>() { + }); + } + + /** + * 将字符串转换为Object + * + * @param json 数据字符串 + * @return list + */ + public static JSONObject toJsonObject(String json) { + return JSON.parseObject(json); + } + + /** + * 将字符串转换为Array + * + * @param json 数据字符串 + * @return list + */ + public static JSONArray toJsonArray(String json) { + return JSON.parseArray(json); + } + +} + diff --git a/open-anpr-server/src/main/java/com/visual/open/anpr/server/domain/extend/LocationPoint.java b/open-anpr-server/src/main/java/com/visual/open/anpr/server/domain/extend/LocationPoint.java new file mode 100644 index 0000000..ed491fa --- /dev/null +++ b/open-anpr-server/src/main/java/com/visual/open/anpr/server/domain/extend/LocationPoint.java @@ -0,0 +1,38 @@ +package com.visual.open.anpr.server.domain.extend; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class LocationPoint implements Serializable { + + /**坐标X的值**/ + @ApiModelProperty(value="坐标X的值", position = 1, required = true) + private int x; + /**坐标Y的值**/ + @ApiModelProperty(value="坐标Y的值", position = 2, required = true) + private int y; + + public LocationPoint(){} + + public LocationPoint(float x, float y) { + this.x = (int)x; + this.y = (int)y; + } + + public int getX() { + return x; + } + + public void setX(int x) { + this.x = x; + } + + public int getY() { + return y; + } + + public void setY(int y) { + this.y = y; + } +} diff --git a/open-anpr-server/src/main/java/com/visual/open/anpr/server/domain/extend/PlateLocation.java b/open-anpr-server/src/main/java/com/visual/open/anpr/server/domain/extend/PlateLocation.java index dc8cfbb..52657e9 100755 --- a/open-anpr-server/src/main/java/com/visual/open/anpr/server/domain/extend/PlateLocation.java +++ b/open-anpr-server/src/main/java/com/visual/open/anpr/server/domain/extend/PlateLocation.java @@ -5,68 +5,82 @@ import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; public class PlateLocation implements Serializable { - /**左上角x坐标**/ - @ApiModelProperty(value="左上角x坐标", position = 1, required = true) - private int x; - /**左上角y坐标**/ - @ApiModelProperty(value="左上角y坐标", position = 2, required = true) - private int y; - /**宽度**/ - @ApiModelProperty(value="车牌宽度", position = 3, required = true) - private int w; - /**高度**/ - @ApiModelProperty(value="车牌高度", position = 4, required = true) - private int h; - /** - * 构建坐标 - * @param x - * @param y - * @param w - * @param h - * @return - */ - public static PlateLocation build(int x, int y, int w, int h){ - return new PlateLocation().setX(x).setY(y).setW(w).setH(h); + /**左上角坐标值**/ + @ApiModelProperty(value="左上角坐标值", position = 1, required = true) + private LocationPoint leftTop; + /**右上角坐标**/ + @ApiModelProperty(value="右上角坐标", position = 2, required = true) + private LocationPoint rightTop; + /**右下角坐标**/ + @ApiModelProperty(value="右下角坐标", position = 3, required = true) + private LocationPoint rightBottom; + /**左下角坐标**/ + @ApiModelProperty(value="左下角坐标", position = 4, required = true) + private LocationPoint leftBottom; + + public LocationPoint getLeftTop() { + return leftTop; } - public static PlateLocation build(float x, float y, float w, float h){ - return new PlateLocation().setX((int) x).setY((int) y).setW((int) w).setH((int) h); + public void setLeftTop(LocationPoint leftTop) { + this.leftTop = leftTop; } - public int getX() { - return x; + public LocationPoint getRightTop() { + return rightTop; } - public PlateLocation setX(int x) { - this.x = x; - return this; + public void setRightTop(LocationPoint rightTop) { + this.rightTop = rightTop; } - public int getY() { - return y; + public LocationPoint getRightBottom() { + return rightBottom; } - public PlateLocation setY(int y) { - this.y = y; - return this; + public void setRightBottom(LocationPoint rightBottom) { + this.rightBottom = rightBottom; } - public int getW() { - return w; + public LocationPoint getLeftBottom() { + return leftBottom; } - public PlateLocation setW(int w) { - this.w = w; - return this; + public void setLeftBottom(LocationPoint leftBottom) { + this.leftBottom = leftBottom; } - public int getH() { - return h; + + /** + * x的最小坐标 + * @return + */ + public int minX(){ + return Math.min(Math.min(Math.min(leftTop.getX(), rightTop.getX()), rightBottom.getX()), leftBottom.getX()); } - public PlateLocation setH(int h) { - this.h = h; - return this; + /** + * y的最小坐标 + * @return + */ + public int minY(){ + return Math.min(Math.min(Math.min(leftTop.getY(), rightTop.getY()), rightBottom.getY()), leftBottom.getY()); + } + + /** + * x的最大坐标 + * @return + */ + public int maxX(){ + return Math.max(Math.max(Math.max(leftTop.getX(), rightTop.getX()), rightBottom.getX()), leftBottom.getX()); + } + + /** + * y的最大坐标 + * @return + */ + public int maxY(){ + return Math.max(Math.max(Math.max(leftTop.getY(), rightTop.getY()), rightBottom.getY()), leftBottom.getY()); } } diff --git a/open-anpr-server/src/main/java/com/visual/open/anpr/server/service/impl/PlateServiceImpl.java b/open-anpr-server/src/main/java/com/visual/open/anpr/server/service/impl/PlateServiceImpl.java index f324b79..d77f8d7 100644 --- a/open-anpr-server/src/main/java/com/visual/open/anpr/server/service/impl/PlateServiceImpl.java +++ b/open-anpr-server/src/main/java/com/visual/open/anpr/server/service/impl/PlateServiceImpl.java @@ -5,10 +5,7 @@ import com.visual.open.anpr.core.domain.ImageMat; import com.visual.open.anpr.core.domain.PlateImage; import com.visual.open.anpr.core.domain.PlateInfo; import com.visual.open.anpr.core.extract.PlateExtractor; -import com.visual.open.anpr.server.domain.extend.PlateColor; -import com.visual.open.anpr.server.domain.extend.PlateLayout; -import com.visual.open.anpr.server.domain.extend.PlateLocation; -import com.visual.open.anpr.server.domain.extend.RecognitionInfo; +import com.visual.open.anpr.server.domain.extend.*; import com.visual.open.anpr.server.domain.request.PlateInfoReqVo; import com.visual.open.anpr.server.domain.response.PlateInfoRepVo; import com.visual.open.anpr.server.service.api.PlateService; @@ -44,21 +41,19 @@ public class PlateServiceImpl implements PlateService { throw new RuntimeException("PlateExtractor extract error"); } //转换模型结果,并输出 - System.out.println(plateImage.PlateInfos().size()); - List plates = new ArrayList<>(); if(null != plateImage.PlateInfos() && !plateImage.PlateInfos().isEmpty()){ for(PlateInfo plateInfo : plateImage.PlateInfos()){ //检测信息 PlateInfoRepVo plate = new PlateInfoRepVo(); plate.setScore((float)Math.floor(plateInfo.score * 1000000)/10000); - PlateLocation location = PlateLocation.build( - plateInfo.box.x1(), - plateInfo.box.y1(), - plateInfo.box.x2()-plateInfo.box.x1(), - plateInfo.box.y2()-plateInfo.box.y1() - ); + PlateLocation location = new PlateLocation(); + location.setLeftTop(new LocationPoint(plateInfo.box.leftTop.x, plateInfo.box.leftTop.y)); + location.setRightTop(new LocationPoint(plateInfo.box.rightTop.x, plateInfo.box.rightTop.y)); + location.setRightBottom(new LocationPoint(plateInfo.box.rightBottom.x, plateInfo.box.rightBottom.y)); + location.setLeftBottom(new LocationPoint(plateInfo.box.leftBottom.x, plateInfo.box.leftBottom.y)); plate.setLocation(location); + //识别信息 RecognitionInfo recognition = new RecognitionInfo(); recognition.setLayout(plateInfo.single ? PlateLayout.SINGLE : PlateLayout.DOUBLE); diff --git a/open-anpr-test/pom.xml b/open-anpr-test/pom.xml new file mode 100644 index 0000000..c030068 --- /dev/null +++ b/open-anpr-test/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + com.visual.open.anpr + open-anpr-test + 1.0.0 + + + 1.8 + 8 + 8 + UTF-8 + + + + + com.visual.open.anpr + open-anpr-client + ${project.version} + + + + org.openpnp + opencv + 4.6.0-0 + + + + \ No newline at end of file diff --git a/open-anpr-test/src/main/java/com/visual/open/anpr/exps/PlateRecognitionExample.java b/open-anpr-test/src/main/java/com/visual/open/anpr/exps/PlateRecognitionExample.java new file mode 100755 index 0000000..8ba8b6e --- /dev/null +++ b/open-anpr-test/src/main/java/com/visual/open/anpr/exps/PlateRecognitionExample.java @@ -0,0 +1,65 @@ +package com.visual.open.anpr.exps; + +import com.visual.open.anpr.PlateRecognition; +import com.visual.open.anpr.model.*; +import com.visual.open.anpr.utils.Base64Util; +import com.visual.open.anpr.utils.DrawImage; +import org.opencv.highgui.HighGui; + +import java.awt.*; +import java.io.File; +import java.util.List; +import java.util.Objects; + +public class PlateRecognitionExample { + + static{ nu.pattern.OpenCV.loadShared(); } + //本地开发模式 + public static String serverHost = "http://127.0.0.1:8080"; + //docker部署模式 + //public static String serverHost = "http://127.0.0.1:56790"; + //远程测试服务 + //public static String serverHost = "http://open-anpr.diven.nat300.top"; + + public static PlateRecognition plateRecognition = PlateRecognition.build(serverHost); + + /**搜索*/ + public static void recognition() { + String searchPath = "open-anpr-test/src/main/resources/image"; + File [] files = Objects.requireNonNull(new File(searchPath).listFiles()); + for(int i=0; i< files.length-1; i++){ + File imageA = files[i]; + String imageBase64 = Base64Util.encode(imageA.getAbsolutePath()); + Response> response = plateRecognition.detection().recognition( + Recognition.build().setImage(imageBase64).setLimit(5) + ); + + DrawImage drawImage = DrawImage.build(imageA.getAbsolutePath()); + if(response.ok()){ + for(RecognitionRep recognitionRep : response.getData()){ + PlateLocation location = recognitionRep.getLocation(); + drawImage.drawRect( + new DrawImage.Rect(location.getX(), location.getY(), location.getW(), location.getH()), 2, Color.RED); + + + RecognitionInfo recognition = recognitionRep.getRecognition(); + int fonSize = Float.valueOf(1.4f * location.getW() / recognition.getPlateNo().length()).intValue(); + drawImage.drawText(recognition.getPlateNo(), + new DrawImage.Point(location.getX(), location.getY()-(int)(fonSize*2.2)), fonSize, Color.RED); + drawImage.drawText((recognition.getLayout() == PlateLayout.SINGLE ? "单排" : "双排") + ":" + recognition.getPlateColor().getName(), + new DrawImage.Point(location.getX(), location.getY()-(int)(fonSize*1.2)), fonSize, Color.RED); + } + } + HighGui.imshow("image", drawImage.toMat()); + HighGui.waitKey(); + } + //退出程序 + System.exit(1); + } + + /**main**/ + public static void main(String[] args) { + recognition(); + } + +} diff --git a/open-anpr-test/src/main/java/com/visual/open/anpr/utils/DrawImage.java b/open-anpr-test/src/main/java/com/visual/open/anpr/utils/DrawImage.java new file mode 100644 index 0000000..c6b1c00 --- /dev/null +++ b/open-anpr-test/src/main/java/com/visual/open/anpr/utils/DrawImage.java @@ -0,0 +1,124 @@ +package com.visual.open.anpr.utils; + + +import org.opencv.core.CvType; +import org.opencv.core.Mat; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; +import java.io.File; +import java.io.IOException; + + +public class DrawImage { + + private BufferedImage image; + + private DrawImage(BufferedImage image){ + this.image = image; + } + + public static DrawImage build(String image){ + try { + return build(ImageIO.read(new File(image))); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static DrawImage build(BufferedImage image){ + return new DrawImage(image); + } + + private static int getLength(String text) { + int textLength = text.length(); + int length = textLength; + for (int i = 0; i < textLength; i++) { + if (String.valueOf(text.charAt(i)).getBytes().length > 1) { + length++; + } + } + return (length % 2 == 0) ? length / 2 : length / 2 + 1; + } + + public DrawImage drawRect(Rect rect, int lineWidth, Color color){ + Graphics2D g = (Graphics2D)image.getGraphics(); + g.setColor(color); + g.setStroke(new BasicStroke(lineWidth)); + g.drawRect(rect.x, rect.y, rect.width, rect.height); + return this; + } + + public DrawImage drawText(String text, Point point, int fontSize, Color color){ + Graphics2D g = image.createGraphics(); + g.setColor(color); + g.setFont(new Font("微软雅黑", Font.PLAIN, fontSize)); + g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); + int width_1 = fontSize * getLength(text); + int height_1 = fontSize; + int widthDiff = image.getWidth() - width_1; + int heightDiff = image.getHeight() - height_1; + if(point.x < 0){ + point.x = widthDiff / 2; + }else if(point.x > widthDiff){ + point.x = widthDiff; + } + if(point.y < 0){ + point.y = heightDiff / 2; + }else if(point.y > heightDiff){ + point.y = heightDiff; + } + g.drawString(text, point.x, point.y + height_1); + return this; + } + + public Mat toMat(){ + try { + if(image.getType() != BufferedImage.TYPE_3BYTE_BGR){ + BufferedImage temp = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_3BYTE_BGR); + Graphics2D g = temp.createGraphics(); + try { + g.setComposite(AlphaComposite.Src); + g.drawImage(image, 0, 0, null); + } finally { + g.dispose(); + } + image = temp; + } + byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); + Mat mat = Mat.eye(image.getHeight(), image.getWidth(), CvType.CV_8UC3); + mat.put(0, 0, pixels); + return mat; + }catch (Exception e){ + throw new RuntimeException(e); + } + } + + public static class Rect{ + public int x; + public int y; + public int width; + public int height; + + public Rect(int x, int y, int width, int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + } + + public static class Point{ + public int x; + public int y; + + public Point(int x, int y) { + this.x = x; + this.y = y; + } + } + +} diff --git a/open-anpr-test/src/main/java/com/visual/open/anpr/utils/MatUtil.java b/open-anpr-test/src/main/java/com/visual/open/anpr/utils/MatUtil.java new file mode 100755 index 0000000..144f75e --- /dev/null +++ b/open-anpr-test/src/main/java/com/visual/open/anpr/utils/MatUtil.java @@ -0,0 +1,107 @@ +package com.visual.open.anpr.utils; + +import org.opencv.core.Mat; +import org.opencv.core.Range; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.util.Base64; +import java.util.Objects; + +public class MatUtil { + + /** + * 将Mat转换为BufferedImage + * @param mat + * @return BufferedImage + */ + public static BufferedImage matToBufferedImage(Mat mat) { + int dataSize = mat.cols() * mat.rows() * (int) mat.elemSize(); + byte[] data = new byte[dataSize]; + mat.get(0, 0, data); + int type = mat.channels() == 1 ? BufferedImage.TYPE_BYTE_GRAY : BufferedImage.TYPE_3BYTE_BGR; + if (type == BufferedImage.TYPE_3BYTE_BGR) { + for (int i = 0; i < dataSize; i += 3) { + byte blue = data[i + 0]; + data[i + 0] = data[i + 2]; + data[i + 2] = blue; + } + } + BufferedImage image = new BufferedImage(mat.cols(), mat.rows(), type); + image.getRaster().setDataElements(0, 0, mat.cols(), mat.rows(), data); + return image; + } + + /** + * 将Mat转换为 Base64 + * @param mat + * @return Base64 + */ + public static String matToBase64(Mat mat) { + ByteArrayOutputStream byteArrayOutputStream = null; + try { + byteArrayOutputStream = new ByteArrayOutputStream(); + ImageIO.write(matToBufferedImage(mat), "jpg", byteArrayOutputStream); + byte[] bytes = byteArrayOutputStream.toByteArray(); + Base64.Encoder encoder = Base64.getMimeEncoder(); + return encoder.encodeToString(Objects.requireNonNull(bytes)); + }catch (Exception e){ + throw new RuntimeException(e); + }finally { + if(null != byteArrayOutputStream){ + try { + byteArrayOutputStream.close(); + } catch (Exception e) {} + } + } + } + + public static Mat concat(Mat m1, Mat ...m2){ + Mat mat = m1; + if(null != m2){ + for(Mat m : m2){ + mat = concat(mat, m1); + } + } + return mat; + } + + /** + * 横向拼接两个图像的数据(Mat),该两个图像的类型必须是相同的类型,如:均为CvType.CV_8UC3类型 + * @author bailichun + * @since 2020.02.20 15:00 + * @param m1 要合并的图像1(左图) + * @param m2 要合并的图像2(右图) + * @return 拼接好的Mat图像数据集。其高度等于两个图像中高度较大者的高度;其宽度等于两个图像的宽度之和。类型与两个输入图像相同。 + * @throws Exception 当两个图像数据的类型不同时,抛出异常 + */ + public static Mat concat(Mat m1, Mat m2){ + if(m1.type() != m2.type()){ + throw new RuntimeException("concat:两个图像数据的类型不同!"); + } + long time = System.currentTimeMillis(); + //宽度为两图的宽度之和 + double w = m1.size().width + m2.size().width; + //高度取两个矩阵中的较大者的高度 + double h = m1.size().height > m2.size().height ? m1.size().height : m2.size().height; + //创建一个大矩阵对象 + Mat des = Mat.zeros((int)h, (int)w, m1.type()); + //在最终的大图上标记一块区域,用于存放复制图1(左图)的数据,大小为从第0列到m1.cols()列 + Mat rectForM1 = des.colRange(new Range(0, m1.cols())); + //标记出位于rectForM1的垂直方向上中间位置的区域,高度为图1的高度,此时该区域的大小已经和图1的大小相同。(用于存放复制图1(左图)的数据) + int rowOffset1 = (int)(rectForM1.size().height-m1.rows())/2; + rectForM1 = rectForM1.rowRange(rowOffset1, rowOffset1 + m1.rows()); + //在最终的大图上标记一块区域,用于存放复制图2(右图)的数据 + Mat rectForM2 = des.colRange(new Range(m1.cols(), des.cols())); + //标记出位于rectForM2的垂直方向上中间位置的区域,高度为图2的高度,此时该区域的大小已经和图2的大小相同。(用于存放复制图2(右图)的数据) + int rowOffset2 = (int)(rectForM2.size().height-m2.rows())/2; + rectForM2 = rectForM2.rowRange(rowOffset2, rowOffset2 + m2.rows()); + //将图1拷贝到des的指定区域 rectForM1 + m1.copyTo(rectForM1); + //将图2拷贝到des的指定区域 rectForM2 + m2.copyTo(rectForM2); + return des; + } + +} diff --git a/open-anpr-test/src/main/resources/image/image001.jpg b/open-anpr-test/src/main/resources/image/image001.jpg new file mode 100644 index 0000000..972f10e Binary files /dev/null and b/open-anpr-test/src/main/resources/image/image001.jpg differ diff --git a/open-anpr-test/src/main/resources/image/image002.jpg b/open-anpr-test/src/main/resources/image/image002.jpg new file mode 100644 index 0000000..215c8f6 Binary files /dev/null and b/open-anpr-test/src/main/resources/image/image002.jpg differ diff --git a/open-anpr-test/src/main/resources/image/image003.jpg b/open-anpr-test/src/main/resources/image/image003.jpg new file mode 100644 index 0000000..c80eb40 Binary files /dev/null and b/open-anpr-test/src/main/resources/image/image003.jpg differ diff --git a/open-anpr-test/src/main/resources/image/image004.jpg b/open-anpr-test/src/main/resources/image/image004.jpg new file mode 100644 index 0000000..eee6cac Binary files /dev/null and b/open-anpr-test/src/main/resources/image/image004.jpg differ diff --git a/open-anpr-test/src/main/resources/image/image005.jpg b/open-anpr-test/src/main/resources/image/image005.jpg new file mode 100644 index 0000000..f7c216d Binary files /dev/null and b/open-anpr-test/src/main/resources/image/image005.jpg differ diff --git a/open-anpr-test/src/main/resources/image/image006.jpg b/open-anpr-test/src/main/resources/image/image006.jpg new file mode 100644 index 0000000..219a4c9 Binary files /dev/null and b/open-anpr-test/src/main/resources/image/image006.jpg differ diff --git a/open-anpr-test/src/main/resources/image/image007.png b/open-anpr-test/src/main/resources/image/image007.png new file mode 100644 index 0000000..eabaf11 Binary files /dev/null and b/open-anpr-test/src/main/resources/image/image007.png differ diff --git a/open-anpr-test/src/main/resources/image/image008.png b/open-anpr-test/src/main/resources/image/image008.png new file mode 100644 index 0000000..cde51c1 Binary files /dev/null and b/open-anpr-test/src/main/resources/image/image008.png differ diff --git a/open-anpr-test/src/main/resources/image/image009.jpg b/open-anpr-test/src/main/resources/image/image009.jpg new file mode 100644 index 0000000..9ac0bb1 Binary files /dev/null and b/open-anpr-test/src/main/resources/image/image009.jpg differ diff --git a/open-anpr-test/src/main/resources/image/image010.jpg b/open-anpr-test/src/main/resources/image/image010.jpg new file mode 100644 index 0000000..57cfb90 Binary files /dev/null and b/open-anpr-test/src/main/resources/image/image010.jpg differ diff --git a/open-anpr-test/src/main/resources/image/image011.jpg b/open-anpr-test/src/main/resources/image/image011.jpg new file mode 100644 index 0000000..b42b61c Binary files /dev/null and b/open-anpr-test/src/main/resources/image/image011.jpg differ diff --git a/open-anpr-test/src/main/resources/image/image012.jpg b/open-anpr-test/src/main/resources/image/image012.jpg new file mode 100644 index 0000000..d583ac7 Binary files /dev/null and b/open-anpr-test/src/main/resources/image/image012.jpg differ diff --git a/open-anpr-test/src/main/resources/image/image013.jpg b/open-anpr-test/src/main/resources/image/image013.jpg new file mode 100644 index 0000000..993cd14 Binary files /dev/null and b/open-anpr-test/src/main/resources/image/image013.jpg differ diff --git a/open-anpr-test/src/main/resources/image/image014.png b/open-anpr-test/src/main/resources/image/image014.png new file mode 100644 index 0000000..c0d49db Binary files /dev/null and b/open-anpr-test/src/main/resources/image/image014.png differ diff --git a/pom.xml b/pom.xml index 0b8f3f6..d0f9a9b 100644 --- a/pom.xml +++ b/pom.xml @@ -19,6 +19,8 @@ open-anpr-core open-anpr-server + open-anpr-test + open-anpr-client @@ -41,6 +43,16 @@ open-anpr-core ${project.version} + + com.visual.open.anpr + open-anpr-server + ${project.version} + + + com.visual.open.anpr + open-anpr-client + ${project.version} + org.openpnp