@ -1,30 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
|
|||
<groupId>com.visual.open.anpr</groupId> |
|||
<artifactId>open-anpr-client</artifactId> |
|||
<version>1.1.0</version> |
|||
|
|||
<properties> |
|||
<maven.compiler.source>8</maven.compiler.source> |
|||
<maven.compiler.target>8</maven.compiler.target> |
|||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
|||
</properties> |
|||
|
|||
<dependencies> |
|||
<dependency> |
|||
<groupId>com.alibaba</groupId> |
|||
<artifactId>fastjson</artifactId> |
|||
<version>1.2.58</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.apache.httpcomponents</groupId> |
|||
<artifactId>httpclient</artifactId> |
|||
<version>4.5</version> |
|||
</dependency> |
|||
</dependencies> |
|||
|
|||
</project> |
@ -1,47 +0,0 @@ |
|||
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<String, PlateRecognition> 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); |
|||
} |
|||
|
|||
|
|||
} |
@ -1,12 +0,0 @@ |
|||
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; |
|||
} |
|||
|
|||
} |
@ -1,63 +0,0 @@ |
|||
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<String, RecognitionHandler> 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<List<RecognitionRep>> 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<Response<List<RecognitionRep>>>() {}); |
|||
} |
|||
|
|||
} |
@ -1,207 +0,0 @@ |
|||
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<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> 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 <T> |
|||
* @return |
|||
*/ |
|||
public static <T> Response<T> post(String url, Object data) { |
|||
return post(url, data, new TypeReference<Response<T>>() {}); |
|||
} |
|||
|
|||
/** |
|||
* post请求 |
|||
* @param url |
|||
* @param data |
|||
* @param <T> |
|||
* @return |
|||
*/ |
|||
public static <T> Response<T> post(String url, Object data, TypeReference<Response<T>> 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 <T> |
|||
* @return |
|||
*/ |
|||
public static <T> Response<T> get(String url, MapParam param) { |
|||
return get(url, param, new TypeReference<Response<T>>() {}); |
|||
} |
|||
|
|||
/** |
|||
* get |
|||
* @param url |
|||
* @param param |
|||
* @param <T> |
|||
* @return |
|||
*/ |
|||
public static <T> Response<T> get(String url, MapParam param, TypeReference<Response<T>> type) { |
|||
try { |
|||
//参数构建
|
|||
URIBuilder uriBuilder = new URIBuilder(url); |
|||
if(null != param && !param.isEmpty()){ |
|||
List<NameValuePair> 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); |
|||
} |
|||
} |
|||
|
|||
} |
@ -1,4 +0,0 @@ |
|||
package com.visual.open.anpr.http; |
|||
|
|||
public class HttpClientResult { |
|||
} |
@ -1,455 +0,0 @@ |
|||
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<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> 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<String, String> 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<String, String> headers, Map<String, String> params, boolean https){ |
|||
// 创建HttpGet
|
|||
HttpGet httpGet = null; |
|||
// 创建httpResponse对象
|
|||
CloseableHttpResponse httpResponse = null; |
|||
try { |
|||
// 创建访问的地址
|
|||
URIBuilder uriBuilder = new URIBuilder(url); |
|||
if (params != null) { |
|||
Set<Map.Entry<String, String>> entrySet = params.entrySet(); |
|||
for (Map.Entry<String, String> 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<String, String>)null, https); |
|||
} |
|||
|
|||
/** |
|||
* 带参数的post请求,支持https协议 |
|||
* @param url 请求url |
|||
* @param params 请求参数 |
|||
* @param https 是否是https协议 |
|||
*/ |
|||
public static HttpClientResult doPost(String url, Map<String, String> 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<String, String> headers, Map<String, String> 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<String, String> 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<String, String> 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<String, String> params, boolean https) { |
|||
if (params == null) { |
|||
params = new HashMap<String, String>(); |
|||
} |
|||
params.put("_method", "delete"); |
|||
return doPost(url, params, https); |
|||
} |
|||
|
|||
/** |
|||
* 获取cookie信息 |
|||
* @return 返回所有cookie集合 |
|||
*/ |
|||
public static List<Cookie> getCookies() { |
|||
return cookieStore.getCookies(); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 设置封装请求头 |
|||
* |
|||
* @param params 头信息 |
|||
* @param httpMethod 请求对象 |
|||
*/ |
|||
public static void setHeader(Map<String, String> params, HttpRequestBase httpMethod) { |
|||
// 封装请求头
|
|||
if (null != params && !params.isEmpty()) { |
|||
Set<Map.Entry<String, String>> entrySet = params.entrySet(); |
|||
for (Map.Entry<String, String> entry : entrySet) { |
|||
// 设置到请求头到HttpRequestBase对象中
|
|||
httpMethod.setHeader(entry.getKey(), entry.getValue()); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 封装请求参数 |
|||
* |
|||
* @param params 请求参数 |
|||
* @param httpMethod 请求方法 |
|||
*/ |
|||
public static void setParam(Map<String, String> params, HttpEntityEnclosingRequestBase httpMethod) { |
|||
// 封装请求参数
|
|||
if (null != params && !params.isEmpty()) { |
|||
List<NameValuePair> nvps = new ArrayList<NameValuePair>(); |
|||
Set<Map.Entry<String, String>> entrySet = params.entrySet(); |
|||
for (Map.Entry<String, String> 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(); |
|||
} |
|||
} |
|||
} |
|||
} |
@ -1,34 +0,0 @@ |
|||
package com.visual.open.anpr.model; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
public class LocationPoint implements Serializable { |
|||
|
|||
/**坐标X的值**/ |
|||
private int x; |
|||
/**坐标Y的值**/ |
|||
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; |
|||
} |
|||
} |
@ -1,17 +0,0 @@ |
|||
package com.visual.open.anpr.model; |
|||
|
|||
import java.util.HashMap; |
|||
|
|||
public class MapParam extends HashMap<String, Object> { |
|||
|
|||
public static MapParam build(){ |
|||
return new MapParam(); |
|||
} |
|||
|
|||
|
|||
public MapParam put(String key, Object value){ |
|||
super.put(key, value); |
|||
return this; |
|||
} |
|||
|
|||
} |
@ -1,31 +0,0 @@ |
|||
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; |
|||
} |
|||
|
|||
} |
@ -1,8 +0,0 @@ |
|||
package com.visual.open.anpr.model; |
|||
|
|||
public enum PlateLayout { |
|||
|
|||
SINGLE, //单排
|
|||
DOUBLE, //双排
|
|||
UNKNOWN; //未知
|
|||
} |
@ -1,96 +0,0 @@ |
|||
package com.visual.open.anpr.model; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
public class PlateLocation implements Serializable { |
|||
|
|||
/**左上角坐标值**/ |
|||
private LocationPoint leftTop; |
|||
/**右上角坐标**/ |
|||
private LocationPoint rightTop; |
|||
/**右下角坐标**/ |
|||
private LocationPoint rightBottom; |
|||
/**左下角坐标**/ |
|||
private LocationPoint leftBottom; |
|||
|
|||
public LocationPoint getLeftTop() { |
|||
return leftTop; |
|||
} |
|||
|
|||
public void setLeftTop(LocationPoint leftTop) { |
|||
this.leftTop = leftTop; |
|||
} |
|||
|
|||
public LocationPoint getRightTop() { |
|||
return rightTop; |
|||
} |
|||
|
|||
public void setRightTop(LocationPoint rightTop) { |
|||
this.rightTop = rightTop; |
|||
} |
|||
|
|||
public LocationPoint getRightBottom() { |
|||
return rightBottom; |
|||
} |
|||
|
|||
public void setRightBottom(LocationPoint rightBottom) { |
|||
this.rightBottom = rightBottom; |
|||
} |
|||
|
|||
public LocationPoint getLeftBottom() { |
|||
return leftBottom; |
|||
} |
|||
|
|||
public void setLeftBottom(LocationPoint leftBottom) { |
|||
this.leftBottom = leftBottom; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* x的最小坐标 |
|||
* @return |
|||
*/ |
|||
public int minX(){ |
|||
return Math.min(Math.min(Math.min(leftTop.getX(), rightTop.getX()), rightBottom.getX()), leftBottom.getX()); |
|||
} |
|||
|
|||
/** |
|||
* 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()); |
|||
} |
|||
|
|||
/** |
|||
* 获取宽度 |
|||
* @return |
|||
*/ |
|||
public float width(){ |
|||
return (float) Math.sqrt(Math.pow((rightTop.getX()-leftTop.getX()), 2)+Math.pow((rightTop.getY()-leftTop.getY()), 2)); |
|||
} |
|||
|
|||
/** |
|||
* 获取高度 |
|||
* @return |
|||
*/ |
|||
public float height(){ |
|||
return (float) Math.sqrt(Math.pow((rightTop.getX()-rightBottom.getX()), 2)+Math.pow((rightTop.getY()-rightBottom.getY()), 2)); |
|||
} |
|||
} |
@ -1,40 +0,0 @@ |
|||
package com.visual.open.anpr.model; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
public class Recognition<ExtendsVo extends Recognition<ExtendsVo>> 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; |
|||
} |
|||
|
|||
} |
@ -1,36 +0,0 @@ |
|||
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; |
|||
} |
|||
} |
@ -1,40 +0,0 @@ |
|||
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; |
|||
} |
|||
|
|||
} |
@ -1,13 +0,0 @@ |
|||
package com.visual.open.anpr.model; |
|||
|
|||
public class RecognitionReq extends Recognition<RecognitionReq>{ |
|||
|
|||
/** |
|||
* 构建比对对象 |
|||
* @return |
|||
*/ |
|||
public static RecognitionReq build(){ |
|||
return new RecognitionReq(); |
|||
} |
|||
|
|||
} |
@ -1,62 +0,0 @@ |
|||
package com.visual.open.anpr.model; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
/** |
|||
* des:接口返回对象 |
|||
* @author diven |
|||
* @date 上午9:34 2018/7/12 |
|||
*/ |
|||
public class Response<T> 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 + '}'; |
|||
} |
|||
} |
@ -1,48 +0,0 @@ |
|||
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); |
|||
} |
|||
} |
|||
|
|||
} |
@ -1,40 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<parent> |
|||
<artifactId>open-anpr</artifactId> |
|||
<groupId>com.visual.open.anpr</groupId> |
|||
<version>1.1.0</version> |
|||
</parent> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
|
|||
<artifactId>open-anpr-core</artifactId> |
|||
|
|||
<dependencies> |
|||
<dependency> |
|||
<groupId>org.openpnp</groupId> |
|||
<artifactId>opencv</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.microsoft.onnxruntime</groupId> |
|||
<artifactId>onnxruntime</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.alibaba</groupId> |
|||
<artifactId>fastjson</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.apache.commons</groupId> |
|||
<artifactId>commons-collections4</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.apache.commons</groupId> |
|||
<artifactId>commons-math3</artifactId> |
|||
</dependency> |
|||
</dependencies> |
|||
</project> |
@ -1,10 +0,0 @@ |
|||
package com.visual.open.anpr.core.base; |
|||
|
|||
import java.util.Map; |
|||
import com.visual.open.anpr.core.domain.ImageMat; |
|||
import com.visual.open.anpr.core.domain.PlateInfo.ParseInfo; |
|||
|
|||
public interface PlateRecognition { |
|||
|
|||
ParseInfo inference(ImageMat image, Boolean single, Map<String, Object> params); |
|||
} |
@ -1,131 +0,0 @@ |
|||
package com.visual.open.anpr.core.domain; |
|||
|
|||
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 drawLine(Point point1, Point point2, int lineWidth, Color color){ |
|||
Graphics2D g = (Graphics2D)image.getGraphics(); |
|||
g.setColor(color); |
|||
g.setStroke(new BasicStroke(lineWidth)); |
|||
g.drawLine(point1.x, point1.y, point2.x, point2.y); |
|||
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; |
|||
} |
|||
} |
|||
|
|||
} |
@ -1,128 +0,0 @@ |
|||
package com.visual.open.anpr.core.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> T toEntity(String json, Class<T> clazz) { |
|||
return JSON.parseObject(json, clazz); |
|||
} |
|||
|
|||
/** |
|||
* 将字符串转换为Entity |
|||
* |
|||
* @param json 数据字符串 |
|||
* @param typeReference Entity class |
|||
* @return |
|||
*/ |
|||
public static <T> T toEntity(String json, TypeReference<T> typeReference) { |
|||
return JSON.parseObject(json, typeReference); |
|||
} |
|||
|
|||
/** |
|||
* 将字符串转换为Map |
|||
* |
|||
* @param json 数据字符串 |
|||
* @return Map |
|||
*/ |
|||
public static Map<String, Object> toMap(String json) { |
|||
return JSON.parseObject(json, new TypeReference<Map<String, Object>>() { |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 将字符串转换为List<T> |
|||
* |
|||
* @param json 数据字符串 |
|||
* @param collectionClass 泛型 |
|||
* @return list<T> |
|||
*/ |
|||
public static <T> List<T> toList(String json, Class<T> collectionClass) { |
|||
return JSON.parseArray(json, collectionClass); |
|||
} |
|||
|
|||
/** |
|||
* 将字符串转换为List<Map<String, Object>> |
|||
* |
|||
* @param json 数据字符串 |
|||
* @return list<map> |
|||
*/ |
|||
public static List<Map<String, Object>> toListMap(String json) { |
|||
return JSON.parseObject(json, new TypeReference<List<Map<String, Object>>>() { |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 将字符串转换为Object |
|||
* |
|||
* @param json 数据字符串 |
|||
* @return list<map> |
|||
*/ |
|||
public static JSONObject toJsonObject(String json) { |
|||
return JSON.parseObject(json); |
|||
} |
|||
|
|||
/** |
|||
* 将字符串转换为Array |
|||
* |
|||
* @param json 数据字符串 |
|||
* @return list<map> |
|||
*/ |
|||
public static JSONArray toJsonArray(String json) { |
|||
return JSON.parseArray(json); |
|||
} |
|||
|
|||
} |
|||
|
@ -1,28 +0,0 @@ |
|||
package com.visual.open.anpr.core.base; |
|||
|
|||
import ai.onnxruntime.OrtEnvironment; |
|||
|
|||
import java.io.File; |
|||
import java.util.Map; |
|||
import java.util.TreeMap; |
|||
|
|||
public abstract class BaseTest { |
|||
|
|||
//静态加载动态链接库
|
|||
static{ nu.pattern.OpenCV.loadShared(); } |
|||
private OrtEnvironment env = OrtEnvironment.getEnvironment(); |
|||
|
|||
public static Map<String, String> getImagePathMap(String imagePath){ |
|||
Map<String, String> map = new TreeMap<>(); |
|||
File file = new File(imagePath); |
|||
if(file.isFile()){ |
|||
map.put(file.getName(), file.getAbsolutePath()); |
|||
}else if(file.isDirectory()){ |
|||
for(File tmpFile : file.listFiles()){ |
|||
map.putAll(getImagePathMap(tmpFile.getPath())); |
|||
} |
|||
} |
|||
return map; |
|||
} |
|||
|
|||
} |
@ -1,77 +0,0 @@ |
|||
package com.visual.open.anpr.core.extract; |
|||
|
|||
import com.visual.open.anpr.core.base.BaseTest; |
|||
import com.visual.open.anpr.core.domain.*; |
|||
import com.visual.open.anpr.core.models.TorchPlateDetection; |
|||
import com.visual.open.anpr.core.models.TorchPlateRecognition; |
|||
import org.opencv.core.Mat; |
|||
import org.opencv.core.Point; |
|||
import org.opencv.core.Scalar; |
|||
import org.opencv.highgui.HighGui; |
|||
import org.opencv.imgcodecs.Imgcodecs; |
|||
import org.opencv.imgproc.Imgproc; |
|||
|
|||
import java.awt.*; |
|||
import java.util.HashMap; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
public class PlateExtractorTest extends BaseTest { |
|||
|
|||
private static String plateDetectionPath = "open-anpr-core/src/main/resources/models/plate_detect.onnx"; |
|||
private static String plateRecognitionPath = "open-anpr-core/src/main/resources/models/plate_rec_color.onnx"; |
|||
|
|||
public static void main(String[] args) { |
|||
TorchPlateDetection torchPlateDetection = new TorchPlateDetection(plateDetectionPath, 1); |
|||
TorchPlateRecognition torchPlateRecognition = new TorchPlateRecognition(plateRecognitionPath, 1); |
|||
PlateExtractor extractor = new PlateExtractorImpl(torchPlateDetection, torchPlateRecognition); |
|||
|
|||
String imagePath = "open-anpr-core/src/test/resources/images"; |
|||
Map<String, String> map = getImagePathMap(imagePath); |
|||
for(String fileName : map.keySet()) { |
|||
String imageFilePath = map.get(fileName); |
|||
System.out.println(imageFilePath); |
|||
Mat image = Imgcodecs.imread(imageFilePath); |
|||
long startTime = System.currentTimeMillis(); |
|||
ExtParam extParam = ExtParam.build() |
|||
.setTopK(20) |
|||
.setScoreTh(0.3f) |
|||
.setIouTh(0.5f); |
|||
//推理
|
|||
PlateImage plateImage = extractor.extract(ImageMat.fromCVMat(image), extParam, new HashMap<>()); |
|||
System.out.println("cost:" + (System.currentTimeMillis()-startTime)); |
|||
List<PlateInfo> plateInfos = plateImage.PlateInfos(); |
|||
//可视化
|
|||
DrawImage drawImage = DrawImage.build(imageFilePath); |
|||
for(PlateInfo plateInfo: plateInfos){ |
|||
//画框
|
|||
PlateInfo.Point [] points = plateInfo.box.toArray(); |
|||
for(int i =0; i< points.length; i++){ |
|||
if(i+1 == points.length){ |
|||
drawImage.drawLine( |
|||
new DrawImage.Point((int)points[i].x, (int)points[i].y), |
|||
new DrawImage.Point((int)points[0].x, (int)points[0].y), |
|||
2, Color.RED |
|||
); |
|||
}else{ |
|||
drawImage.drawLine( |
|||
new DrawImage.Point((int)points[i].x, (int)points[i].y), |
|||
new DrawImage.Point((int)points[i+1].x, (int)points[i+1].y), |
|||
2, Color.RED |
|||
); |
|||
} |
|||
} |
|||
//添加文本
|
|||
PlateInfo.ParseInfo parseInfo = plateInfo.parseInfo; |
|||
int fonSize = Float.valueOf(plateInfo.box.width() / parseInfo.plateNo.length() * 1.4f).intValue(); |
|||
drawImage.drawText(parseInfo.plateNo, |
|||
new DrawImage.Point((int)points[0].x, (int)points[0].y-(int)(fonSize*2.2)), fonSize, Color.RED); |
|||
drawImage.drawText((plateInfo.single ? "单排" : "双排") + ":" + parseInfo.plateColor, |
|||
new DrawImage.Point((int)points[0].x, (int)points[0].y-(int)(fonSize*1.2)), fonSize, Color.RED); |
|||
} |
|||
//show
|
|||
ImageMat.fromCVMat(drawImage.toMat()).imShow(); |
|||
image.release(); |
|||
} |
|||
} |
|||
} |
@ -1,42 +0,0 @@ |
|||
package com.visual.open.anpr.core.models; |
|||
|
|||
import com.visual.open.anpr.core.domain.DrawImage; |
|||
import com.visual.open.anpr.core.domain.ImageMat; |
|||
import com.visual.open.anpr.core.domain.PlateInfo; |
|||
|
|||
import java.awt.*; |
|||
import java.util.HashMap; |
|||
import java.util.List; |
|||
|
|||
public class TorchPlateDetectionTest { |
|||
public static void main(String[] args) { |
|||
TorchPlateDetection torchPlateDetection = new TorchPlateDetection("open-anpr-core/src/main/resources/models/plate_detect.onnx", 1); |
|||
|
|||
String imagePath = "open-anpr-core/src/test/resources/images/image001.jpg"; |
|||
ImageMat imageMat = ImageMat.fromImage(imagePath); |
|||
List<PlateInfo> plateInfos = torchPlateDetection.inference(imageMat, 0.3f,0.5f, new HashMap<>()); |
|||
System.out.println(plateInfos); |
|||
|
|||
DrawImage drawImage = DrawImage.build(imagePath); |
|||
for(PlateInfo plateInfo : plateInfos){ |
|||
PlateInfo.Point [] points = plateInfo.box.toArray(); |
|||
for(int i =0; i< points.length; i++){ |
|||
if(i+1 == points.length){ |
|||
drawImage.drawLine( |
|||
new DrawImage.Point((int)points[i].x, (int)points[i].y), |
|||
new DrawImage.Point((int)points[0].x, (int)points[0].y), |
|||
2, Color.RED |
|||
); |
|||
}else{ |
|||
drawImage.drawLine( |
|||
new DrawImage.Point((int)points[i].x, (int)points[i].y), |
|||
new DrawImage.Point((int)points[i+1].x, (int)points[i+1].y), |
|||
2, Color.RED |
|||
); |
|||
} |
|||
} |
|||
} |
|||
ImageMat.fromCVMat(drawImage.toMat()).imShow(); |
|||
} |
|||
|
|||
} |
@ -1,28 +0,0 @@ |
|||
package com.visual.open.anpr.core.models; |
|||
|
|||
import com.visual.open.anpr.core.domain.ImageMat; |
|||
import com.visual.open.anpr.core.domain.PlateInfo; |
|||
import com.visual.open.anpr.core.utils.CropUtil; |
|||
import org.opencv.core.Mat; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.List; |
|||
|
|||
public class TorchPlateRecognitionTest { |
|||
|
|||
public static void main(String[] args) { |
|||
TorchPlateDetection torchPlateDetection = new TorchPlateDetection("open-anpr-core/src/main/resources/models/plate_detect.onnx", 1); |
|||
TorchPlateRecognition torchPlateRecognition = new TorchPlateRecognition("open-anpr-core/src/main/resources/models/plate_rec_color.onnx", 1); |
|||
|
|||
String imagePath = "open-anpr-core/src/test/resources/images"; |
|||
ImageMat imageMat = ImageMat.fromImage(imagePath); |
|||
List<PlateInfo> plateInfos = torchPlateDetection.inference(imageMat, 0.3f,0.5f, new HashMap<>()); |
|||
System.out.println(plateInfos); |
|||
for(PlateInfo plateInfo : plateInfos){ |
|||
Mat crop = CropUtil.crop(imageMat.toCvMat(), plateInfo.box); |
|||
// ImageMat.fromCVMat(crop).imShow();
|
|||
PlateInfo.ParseInfo parseInfo = torchPlateRecognition.inference(ImageMat.fromCVMat(crop), plateInfo.single, new HashMap<>()); |
|||
System.out.println(parseInfo); |
|||
} |
|||
} |
|||
} |
Before Width: | Height: | Size: 107 KiB |
Before Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 390 KiB |
Before Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 671 KiB |
Before Width: | Height: | Size: 328 KiB |
Before Width: | Height: | Size: 382 KiB |
Before Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 999 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 400 KiB |
Before Width: | Height: | Size: 116 KiB |
@ -1,10 +1,10 @@ |
|||
package com.visual.open.anpr.core.base; |
|||
package com.visual.open.anpr.server.base; |
|||
|
|||
import ai.onnxruntime.OrtEnvironment; |
|||
import ai.onnxruntime.OrtLoggingLevel; |
|||
import ai.onnxruntime.OrtSession; |
|||
|
|||
public abstract class BaseOnnxInfer extends OpenCVLoader{ |
|||
public abstract class BaseOnnxInfer extends OpenCVLoader { |
|||
|
|||
private OrtEnvironment env; |
|||
private String[] inputNames; |
@ -1,4 +1,4 @@ |
|||
package com.visual.open.anpr.core.base; |
|||
package com.visual.open.anpr.server.base; |
|||
|
|||
public abstract class OpenCVLoader { |
|||
|
@ -1,7 +1,7 @@ |
|||
package com.visual.open.anpr.core.base; |
|||
package com.visual.open.anpr.server.base; |
|||
|
|||
import com.visual.open.anpr.core.domain.ImageMat; |
|||
import com.visual.open.anpr.core.domain.PlateInfo; |
|||
import com.visual.open.anpr.server.domain.ImageMat; |
|||
import com.visual.open.anpr.server.domain.PlateInfo; |
|||
|
|||
import java.util.List; |
|||
import java.util.Map; |
@ -0,0 +1,11 @@ |
|||
package com.visual.open.anpr.server.base; |
|||
|
|||
import com.visual.open.anpr.server.domain.ImageMat; |
|||
import com.visual.open.anpr.server.domain.PlateInfo.ParseInfo; |
|||
|
|||
import java.util.Map; |
|||
|
|||
public interface PlateRecognition { |
|||
|
|||
ParseInfo inference(ImageMat image, Boolean single, Map<String, Object> params); |
|||
} |
@ -1,4 +1,4 @@ |
|||
package com.visual.open.anpr.core.domain; |
|||
package com.visual.open.anpr.server.domain; |
|||
|
|||
import org.opencv.core.Mat; |
|||
|
@ -1,4 +1,4 @@ |
|||
package com.visual.open.anpr.utils; |
|||
package com.visual.open.anpr.server.domain; |
|||
|
|||
import org.opencv.core.CvType; |
|||
import org.opencv.core.Mat; |
@ -1,4 +1,4 @@ |
|||
package com.visual.open.anpr.core.domain; |
|||
package com.visual.open.anpr.server.domain; |
|||
|
|||
import java.io.Serializable; |
|||
|
@ -1,8 +1,8 @@ |
|||
package com.visual.open.anpr.core.domain; |
|||
package com.visual.open.anpr.server.domain; |
|||
|
|||
import ai.onnxruntime.OnnxTensor; |
|||
import ai.onnxruntime.OrtEnvironment; |
|||
import com.visual.open.anpr.core.utils.MatUtil; |
|||
import com.visual.open.anpr.server.utils.MatUtil; |
|||
import org.opencv.core.Point; |
|||
import org.opencv.core.*; |
|||
import org.opencv.dnn.Dnn; |
@ -1,4 +1,4 @@ |
|||
package com.visual.open.anpr.core.domain; |
|||
package com.visual.open.anpr.server.domain; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.ArrayList; |
@ -1,4 +1,4 @@ |
|||
package com.visual.open.anpr.core.domain; |
|||
package com.visual.open.anpr.server.domain; |
|||
|
|||
import java.io.Serializable; |
|||
|
@ -1,9 +1,10 @@ |
|||
package com.visual.open.anpr.core.extract; |
|||
package com.visual.open.anpr.server.extract; |
|||
|
|||
import com.visual.open.anpr.server.domain.ExtParam; |
|||
import com.visual.open.anpr.server.domain.ImageMat; |
|||
import com.visual.open.anpr.server.domain.PlateImage; |
|||
|
|||
import java.util.Map; |
|||
import com.visual.open.anpr.core.domain.ExtParam; |
|||
import com.visual.open.anpr.core.domain.ImageMat; |
|||
import com.visual.open.anpr.core.domain.PlateImage; |
|||
|
|||
public interface PlateExtractor { |
|||
|
@ -1,12 +1,12 @@ |
|||
package com.visual.open.anpr.core.extract; |
|||
package com.visual.open.anpr.server.extract; |
|||
|
|||
import com.visual.open.anpr.core.base.PlateDetection; |
|||
import com.visual.open.anpr.core.base.PlateRecognition; |
|||
import com.visual.open.anpr.core.domain.ExtParam; |
|||
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.utils.CropUtil; |
|||
import com.visual.open.anpr.server.base.PlateDetection; |
|||
import com.visual.open.anpr.server.base.PlateRecognition; |
|||
import com.visual.open.anpr.server.domain.ExtParam; |
|||
import com.visual.open.anpr.server.domain.ImageMat; |
|||
import com.visual.open.anpr.server.domain.PlateImage; |
|||
import com.visual.open.anpr.server.domain.PlateInfo; |
|||
import com.visual.open.anpr.server.utils.CropUtil; |
|||
import org.opencv.core.Core; |
|||
import org.opencv.core.Mat; |
|||
|
@ -1,14 +1,17 @@ |
|||
package com.visual.open.anpr.core.models; |
|||
package com.visual.open.anpr.server.models; |
|||
|
|||
import ai.onnxruntime.OnnxTensor; |
|||
import ai.onnxruntime.OrtSession; |
|||
import com.visual.open.anpr.core.base.BaseOnnxInfer; |
|||
import com.visual.open.anpr.core.base.PlateDetection; |
|||
import com.visual.open.anpr.core.domain.ImageMat; |
|||
import com.visual.open.anpr.core.domain.BorderMat; |
|||
import com.visual.open.anpr.core.domain.PlateInfo; |
|||
import com.visual.open.anpr.core.utils.ReleaseUtil; |
|||
import org.opencv.core.*; |
|||
import com.visual.open.anpr.server.base.BaseOnnxInfer; |
|||
import com.visual.open.anpr.server.base.PlateDetection; |
|||
import com.visual.open.anpr.server.domain.BorderMat; |
|||
import com.visual.open.anpr.server.domain.ImageMat; |
|||
import com.visual.open.anpr.server.domain.PlateInfo; |
|||
import com.visual.open.anpr.server.utils.ReleaseUtil; |
|||
import org.opencv.core.Core; |
|||
import org.opencv.core.Mat; |
|||
import org.opencv.core.Scalar; |
|||
import org.opencv.core.Size; |
|||
import org.opencv.imgproc.Imgproc; |
|||
|
|||
import java.util.*; |
@ -1,20 +1,21 @@ |
|||
package com.visual.open.anpr.core.models; |
|||
package com.visual.open.anpr.server.models; |
|||
|
|||
import ai.onnxruntime.OnnxTensor; |
|||
import ai.onnxruntime.OrtSession; |
|||
import com.visual.open.anpr.core.base.BaseOnnxInfer; |
|||
import com.visual.open.anpr.core.base.PlateRecognition; |
|||
import com.visual.open.anpr.core.domain.ImageMat; |
|||
import com.visual.open.anpr.core.domain.PlateInfo.ParseInfo; |
|||
import com.visual.open.anpr.core.utils.ArrayUtil; |
|||
import com.visual.open.anpr.core.utils.MatUtil; |
|||
import com.visual.open.anpr.core.utils.ReleaseUtil; |
|||
import com.visual.open.anpr.core.utils.SoftMaxUtil; |
|||
import com.visual.open.anpr.server.base.BaseOnnxInfer; |
|||
import com.visual.open.anpr.server.base.PlateRecognition; |
|||
import com.visual.open.anpr.server.domain.ImageMat; |
|||
import com.visual.open.anpr.server.domain.PlateInfo.ParseInfo; |
|||
import com.visual.open.anpr.server.utils.ArrayUtil; |
|||
import com.visual.open.anpr.server.utils.MatUtil; |
|||
import com.visual.open.anpr.server.utils.ReleaseUtil; |
|||
import com.visual.open.anpr.server.utils.SoftMaxUtil; |
|||
import org.opencv.core.Mat; |
|||
import org.opencv.core.Rect; |
|||
import org.opencv.core.Scalar; |
|||
import org.opencv.core.Size; |
|||
import org.opencv.imgproc.Imgproc; |
|||
|
|||
import java.util.Collections; |
|||
import java.util.Map; |
|||
|
@ -1,4 +1,4 @@ |
|||
package com.visual.open.anpr.core.utils; |
|||
package com.visual.open.anpr.server.utils; |
|||
|
|||
import org.apache.commons.math3.linear.RealMatrix; |
|||
import org.apache.commons.math3.linear.RealVector; |
@ -1,4 +1,4 @@ |
|||
package com.visual.open.anpr.core.utils; |
|||
package com.visual.open.anpr.server.utils; |
|||
|
|||
public class ArrayUtil { |
|||
|
@ -1,6 +1,6 @@ |
|||
package com.visual.open.anpr.core.utils; |
|||
package com.visual.open.anpr.server.utils; |
|||
|
|||
import com.visual.open.anpr.core.domain.PlateInfo; |
|||
import com.visual.open.anpr.server.domain.PlateInfo; |
|||
import org.opencv.core.CvType; |
|||
import org.opencv.core.Mat; |
|||
import org.opencv.core.Point; |
@ -0,0 +1,324 @@ |
|||
package com.visual.open.anpr.server.utils; |
|||
|
|||
import ws.schild.jave.Encoder; |
|||
import ws.schild.jave.EncoderException; |
|||
import ws.schild.jave.MultimediaObject; |
|||
import ws.schild.jave.encode.AudioAttributes; |
|||
import ws.schild.jave.encode.EncodingAttributes; |
|||
import ws.schild.jave.encode.VideoAttributes; |
|||
import ws.schild.jave.info.MultimediaInfo; |
|||
import ws.schild.jave.process.ProcessWrapper; |
|||
import ws.schild.jave.process.ffmpeg.DefaultFFMPEGLocator; |
|||
|
|||
import java.io.BufferedReader; |
|||
import java.io.File; |
|||
import java.io.IOException; |
|||
import java.io.InputStreamReader; |
|||
import java.net.URL; |
|||
import java.text.SimpleDateFormat; |
|||
import java.util.Date; |
|||
|
|||
/** |
|||
* @author ruibo.duan, <1573434995@qq.com> |
|||
* @since 2021/7/22 |
|||
*/ |
|||
public class FfmpegUtil { |
|||
|
|||
/** |
|||
* 通过本地路径获取多媒体文件信息(宽,高,时长,编码等) |
|||
* |
|||
* @param localPath 本地路径 |
|||
* @return MultimediaInfo 对象,包含 (宽,高,时长,编码等) |
|||
* @throws EncoderException |
|||
*/ |
|||
public static MultimediaInfo getMultimediaInfo(String localPath) { |
|||
MultimediaInfo multimediaInfo = null; |
|||
try { |
|||
multimediaInfo = new MultimediaObject(new File(localPath)).getInfo(); |
|||
} catch (EncoderException e) { |
|||
System.out.println("获取多媒体文件信息异常"); |
|||
e.printStackTrace(); |
|||
} |
|||
return multimediaInfo; |
|||
} |
|||
|
|||
/** |
|||
// * 通过URL获取多媒体文件信息
|
|||
* |
|||
* @param url 网络url |
|||
* @return MultimediaInfo 对象,包含 (宽,高,时长,编码等) |
|||
* @throws EncoderException |
|||
*/ |
|||
public static MultimediaInfo getMultimediaInfoFromUrl(String url) { |
|||
MultimediaInfo multimediaInfo = null; |
|||
try { |
|||
multimediaInfo = new MultimediaObject(new URL(url)).getInfo(); |
|||
} catch (Exception e) { |
|||
System.out.println("获取多媒体文件信息异常"); |
|||
e.printStackTrace(); |
|||
} |
|||
return multimediaInfo; |
|||
} |
|||
|
|||
private static final int SAMPLING_RATE = 16000; |
|||
private static final int SINGLE_CHANNEL = 1; |
|||
|
|||
/** |
|||
* 音频格式化为wav,并设置单声道和采样率 |
|||
* |
|||
* @param url 需要转格式的音频 |
|||
* @param targetPath 格式化后要保存的目标路径 |
|||
*/ |
|||
public static boolean formatAudio(String url, String targetPath) { |
|||
File target = new File(targetPath); |
|||
MultimediaObject multimediaObject; |
|||
try { |
|||
// 若是本地文件: multimediaObject = new MultimediaObject(new File("你的本地路径"));
|
|||
multimediaObject = new MultimediaObject(new URL(url)); |
|||
// 音频参数
|
|||
// TODO: 2023/1/31 此处按需自定义音频参数
|
|||
AudioAttributes audio = new AudioAttributes(); |
|||
// 采样率
|
|||
audio.setSamplingRate(SAMPLING_RATE); |
|||
// 单声道
|
|||
audio.setChannels(SINGLE_CHANNEL); |
|||
Encoder encoder = new Encoder(); |
|||
EncodingAttributes attrs = new EncodingAttributes(); |
|||
// 输出格式
|
|||
attrs.setOutputFormat("wav"); |
|||
attrs.setAudioAttributes(audio); |
|||
encoder.encode(multimediaObject, target, attrs); |
|||
return true; |
|||
} catch (Exception e) { |
|||
System.out.println("格式化音频异常"); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 视频格式化为mp4 |
|||
* |
|||
* @param url |
|||
* @param targetPath |
|||
* @return |
|||
*/ |
|||
public static boolean formatToMp4(String url, String targetPath) { |
|||
File target = new File(targetPath); |
|||
MultimediaObject multimediaObject; |
|||
try { |
|||
// 若是本地文件: multimediaObject = new MultimediaObject(new File("你的本地路径"));
|
|||
multimediaObject = new MultimediaObject(new URL(url)); |
|||
EncodingAttributes attributes = new EncodingAttributes(); |
|||
// 设置视频的音频参数
|
|||
AudioAttributes audioAttributes = new AudioAttributes(); |
|||
attributes.setAudioAttributes(audioAttributes); |
|||
// 设置视频的视频参数
|
|||
VideoAttributes videoAttributes = new VideoAttributes(); |
|||
// 设置帧率
|
|||
videoAttributes.setFrameRate(25); |
|||
attributes.setVideoAttributes(videoAttributes); |
|||
// 设置输出格式
|
|||
attributes.setOutputFormat("mp4"); |
|||
Encoder encoder = new Encoder(); |
|||
encoder.encode(multimediaObject, target, attributes); |
|||
return true; |
|||
} catch (Exception e) { |
|||
System.out.println("格式化视频异常"); |
|||
e.printStackTrace(); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 获取视频缩略图 获取视频第0秒的第一帧图片 |
|||
* |
|||
* <p>执行的ffmpeg 命令为: ffmpeg -i 你的视频文件路径 -ss 指定的秒数 生成文件的全路径地址 |
|||
* |
|||
* @param localPath 本地路径 |
|||
* @param targetPath 存放的目标路径 |
|||
* @return |
|||
*/ |
|||
public static boolean getTargetThumbnail(String localPath, String targetPath) { |
|||
// FIXME: 2023/1/31 该方法基本可作为执行ffmpeg命令的模板方法,之后的几个方法与此类似
|
|||
try { |
|||
ProcessWrapper ffmpeg = new DefaultFFMPEGLocator().createExecutor(); |
|||
ffmpeg.addArgument("-i"); |
|||
ffmpeg.addArgument(localPath); |
|||
ffmpeg.addArgument("-ss"); |
|||
// 此处可自定义视频的秒数
|
|||
ffmpeg.addArgument("0"); |
|||
ffmpeg.addArgument(targetPath); |
|||
ffmpeg.execute(); |
|||
try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) { |
|||
blockFfmpeg(br); |
|||
} |
|||
} catch (IOException e) { |
|||
System.out.println("获取视频缩略图失败"); |
|||
e.printStackTrace(); |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 抓拍实况 |
|||
* @param localPath 实况地址 |
|||
* @param targetPath 存放的目标路径 |
|||
* @return 返回抓拍图片的文件名 |
|||
*/ |
|||
// 获取实况抓拍图片
|
|||
public static String getLiveCapture(String localPath, String targetPath) { |
|||
|
|||
String formattedDate =""; |
|||
|
|||
try { |
|||
ProcessWrapper ffmpeg = new DefaultFFMPEGLocator().createExecutor(); |
|||
ffmpeg.addArgument("-i"); |
|||
ffmpeg.addArgument(localPath); |
|||
ffmpeg.addArgument("-vf"); |
|||
// 加上 "select=eq(pict_type\,I)" -frames:v 1
|
|||
ffmpeg.addArgument("select='eq(pict_type,I)'"); |
|||
ffmpeg.addArgument("-frames:v"); |
|||
ffmpeg.addArgument("1"); |
|||
|
|||
// 生成一个根据时间的文件名
|
|||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); |
|||
// 获取当前时间
|
|||
Date currentDate = new Date(); |
|||
// 格式化时间为字符串
|
|||
formattedDate = sdf.format(currentDate)+ ".jpg"; |
|||
|
|||
ffmpeg.addArgument(formattedDate); |
|||
|
|||
ffmpeg.addArgument(targetPath + formattedDate); |
|||
|
|||
ffmpeg.execute(); |
|||
try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) { |
|||
blockFfmpeg(br); |
|||
} |
|||
} catch (IOException e) { |
|||
formattedDate = "获取实况抓拍图片失败"; |
|||
System.out.println(formattedDate); |
|||
e.printStackTrace(); |
|||
return formattedDate; |
|||
} return formattedDate; |
|||
} |
|||
|
|||
/** |
|||
* 等待命令执行成功,退出 |
|||
* |
|||
* @param br |
|||
* @throws IOException |
|||
*/ |
|||
private static void blockFfmpeg(BufferedReader br) throws IOException { |
|||
String line; |
|||
// 该方法阻塞线程,直至合成成功
|
|||
while ((line = br.readLine()) != null) { |
|||
doNothing(line); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 打印日志 |
|||
* |
|||
* @param line |
|||
*/ |
|||
private static void doNothing(String line) { |
|||
// FIXME: 2023/1/31 正式使用时注释掉此行,仅用于观察日志
|
|||
System.out.println(line); |
|||
} |
|||
|
|||
/** |
|||
* 视频增加字幕 |
|||
* |
|||
* @param originVideoPath 原视频地址 |
|||
* @param targetVideoPath 目标视频地址 |
|||
* @param srtPath 固定格式的srt文件地址或存储位置,字母文件名: xxx.srt,样例看博客 |
|||
* @return |
|||
* @throws Exception |
|||
*/ |
|||
public static boolean addSubtitle( |
|||
String originVideoPath, String srtPath, String targetVideoPath) { |
|||
try { |
|||
ProcessWrapper ffmpeg = new DefaultFFMPEGLocator().createExecutor(); |
|||
ffmpeg.addArgument("-i"); |
|||
ffmpeg.addArgument(originVideoPath); |
|||
ffmpeg.addArgument("-i"); |
|||
ffmpeg.addArgument(srtPath); |
|||
ffmpeg.addArgument("-c"); |
|||
ffmpeg.addArgument("copy"); |
|||
ffmpeg.addArgument(targetVideoPath); |
|||
ffmpeg.execute(); |
|||
try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) { |
|||
blockFfmpeg(br); |
|||
} |
|||
} catch (IOException e) { |
|||
System.out.println("字幕增加失败"); |
|||
e.printStackTrace(); |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 常用命令 |
|||
* |
|||
* @return |
|||
*/ |
|||
public static void cmd() { |
|||
// FIXME: 2023/1/31 还有很多类似命令 不再一一列举 ,附上命令,具体写法参考 getTargetThumbnail或addSubtitle方法
|
|||
// FIXME: 2023/1/31 ffmpeg命令网上搜索即可
|
|||
|
|||
// 剪切视频
|
|||
// ffmpeg -ss 00:00:00 -t 00:00:30 -i test.mp4 -vcodec copy -acodec copy output.mp4
|
|||
// * -ss 指定从什么时间开始
|
|||
// * -t 指定需要截取多长时间
|
|||
// * -i 指定输入文件
|
|||
|
|||
// ffmpeg -ss 10 -t 15 -accurate_seek -i test.mp4 -codec copy cut.mp4
|
|||
// ffmpeg -ss 10 -t 15 -accurate_seek -i test.mp4 -codec copy -avoid_negative_ts 1 cut.mp4
|
|||
|
|||
// 拼接MP4
|
|||
// 第一种方法:
|
|||
// ffmpeg -i "concat:1.mp4|2.mp4|3.mp4" -codec copy out_mp4.mp4
|
|||
// 1.mp4 第一个视频文件的全路径
|
|||
// 2.mp4 第二个视频文件的全路径
|
|||
|
|||
// 提取视频中的音频
|
|||
// ffmpeg -i input.mp4 -acodec copy -vn output.mp3
|
|||
// -vn: 去掉视频;-acodec: 音频选项, 一般后面加copy表示拷贝
|
|||
|
|||
// 音视频合成
|
|||
// ffmpeg -y –i input.mp4 –i input.mp3 –vcodec copy –acodec copy output.mp4
|
|||
// -y 覆盖输出文件
|
|||
|
|||
// 剪切视频
|
|||
// ffmpeg -ss 0:1:30 -t 0:0:20 -i input.mp4 -vcodec copy -acodec copy output.mp4
|
|||
// -ss 开始时间; -t 持续时间
|
|||
|
|||
// 视频截图
|
|||
// ffmpeg –i test.mp4 –f image2 -t 0.001 -s 320x240 image-%3d.jpg
|
|||
// -s 设置分辨率; -f 强迫采用格式fmt;
|
|||
|
|||
// 视频分解为图片
|
|||
// ffmpeg –i test.mp4 –r 1 –f image2 image-%3d.jpg
|
|||
// -r 指定截屏频率
|
|||
|
|||
// 将图片合成视频
|
|||
// ffmpeg -f image2 -i image%d.jpg output.mp4
|
|||
|
|||
// 视频拼接
|
|||
// ffmpeg -f concat -i filelist.txt -c copy output.mp4
|
|||
|
|||
// 将视频转为gif
|
|||
// ffmpeg -i input.mp4 -ss 0:0:30 -t 10 -s 320x240 -pix_fmt rgb24 output.gif
|
|||
// -pix_fmt 指定编码
|
|||
|
|||
// 视频添加水印
|
|||
// ffmpeg -i input.mp4 -i logo.jpg
|
|||
// -filter_complex[0:v][1:v]overlay=main_w-overlay_w-10:main_h-overlay_h-10[out] -map [out] -map
|
|||
// 0:a -codec:a copy output.mp4
|
|||
// main_w-overlay_w-10 视频的宽度-水印的宽度-水印边距;
|
|||
|
|||
} |
|||
} |
|||
|
@ -0,0 +1,173 @@ |
|||
package com.visual.open.anpr.server.utils; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.core.io.ClassPathResource; |
|||
import org.springframework.core.io.Resource; |
|||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver; |
|||
import org.springframework.core.io.support.ResourcePatternResolver; |
|||
|
|||
import java.io.*; |
|||
|
|||
|
|||
@Slf4j |
|||
public class FileCopyUtil { |
|||
|
|||
|
|||
/** |
|||
* 复制path目录下所有文件 |
|||
* @param path 文件目录 不能以/开头 |
|||
* @param newpath 新文件目录 |
|||
*/ |
|||
public static void BatCopyFileFromJar(String path,String newpath) { |
|||
if (!new File(newpath).exists()){ |
|||
new File(newpath).mkdir(); |
|||
} |
|||
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); |
|||
try { |
|||
//获取所有匹配的文件
|
|||
Resource[] resources = resolver.getResources(path+"/*"); |
|||
//打印有多少文件
|
|||
for(int i=0;i<resources.length;i++) { |
|||
Resource resource=resources[i]; |
|||
try { |
|||
//以jar运行时,resource.getFile().isFile() 无法获取文件类型,会报异常,抓取异常后直接生成新的文件即可;以非jar运行时,需要判断文件类型,避免如果是目录会复制错误,将目录写成文件。
|
|||
if(resource.getFile().isFile()) { |
|||
makeFile(newpath+"/"+resource.getFilename()); |
|||
InputStream stream = resource.getInputStream(); |
|||
write2File(stream, newpath+"/"+resource.getFilename()); |
|||
} |
|||
}catch (Exception e) { |
|||
makeFile(newpath+"/"+resource.getFilename()); |
|||
InputStream stream = resource.getInputStream(); |
|||
write2File(stream, newpath+"/"+resource.getFilename()); |
|||
} |
|||
} |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
/** |
|||
* 创建文件 |
|||
* @param path 全路径 指向文件 |
|||
* @return |
|||
*/ |
|||
public static boolean makeFile(String path) { |
|||
File file = new File(path); |
|||
if(file.exists()) { |
|||
return false; |
|||
} |
|||
if (path.endsWith(File.separator)) { |
|||
return false; |
|||
} |
|||
if(!file.getParentFile().exists()) { |
|||
if(!file.getParentFile().mkdirs()) { |
|||
return false; |
|||
} |
|||
} |
|||
try { |
|||
if (file.createNewFile()) { |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
} catch (IOException e) { |
|||
e.printStackTrace(); |
|||
return false; |
|||
} |
|||
} |
|||
/** |
|||
* 输入流写入文件 |
|||
* |
|||
* @param is |
|||
* 输入流 |
|||
* @param filePath |
|||
* 文件保存目录路径 |
|||
* @throws IOException |
|||
*/ |
|||
public static void write2File(InputStream is, String filePath) throws IOException { |
|||
OutputStream os = new FileOutputStream(filePath); |
|||
int len = 8192; |
|||
byte[] buffer = new byte[len]; |
|||
while ((len = is.read(buffer, 0, len)) != -1) { |
|||
os.write(buffer, 0, len); |
|||
} |
|||
os.close(); |
|||
is.close(); |
|||
} |
|||
/** |
|||
*处理异常报错(springboot读取classpath里的文件,解决打jar包java.io.FileNotFoundException: class path resource cannot be opened) |
|||
**/ |
|||
public static File getFileFromClassPath(String path){ |
|||
File targetFile = new File(path); |
|||
if(!targetFile.exists()){ |
|||
if(targetFile.getParent()!=null){ |
|||
File parent=new File(targetFile.getParent()); |
|||
if(!parent.exists()){ |
|||
parent.mkdirs(); |
|||
} |
|||
} |
|||
InputStream initialStream=null; |
|||
OutputStream outStream =null; |
|||
try { |
|||
Resource resource=new ClassPathResource(path); |
|||
//注意通过getInputStream,不能用getFile
|
|||
initialStream=resource.getInputStream(); |
|||
byte[] buffer = new byte[initialStream.available()]; |
|||
initialStream.read(buffer); |
|||
outStream = new FileOutputStream(targetFile); |
|||
outStream.write(buffer); |
|||
} catch (IOException e) { |
|||
} finally { |
|||
if (initialStream != null) { |
|||
try { |
|||
initialStream.close(); // 关闭流
|
|||
} catch (IOException e) { |
|||
} |
|||
} |
|||
if (outStream != null) { |
|||
try { |
|||
outStream.close(); // 关闭流
|
|||
} catch (IOException e) { |
|||
} |
|||
} |
|||
} |
|||
} |
|||
return targetFile; |
|||
} |
|||
private static String userDir = System.getProperty("user.dir"); |
|||
public static void copyHCNetSDKFromLinux(){ |
|||
log.info("开始复制文件"); |
|||
String linuxSOFolder1 = userDir + "/lib/hk/linux/"; |
|||
String linuxSOFolder2 = userDir + "/lib/hk/linux/HKNetSDKCom/"; |
|||
|
|||
File fileFromClassPath1 = FileCopyUtil.getFileFromClassPath("/lib/hk/linux64/"); |
|||
File fileFromClassPath2 = FileCopyUtil.getFileFromClassPath("/lib/hk/linux64/HCNetSDKCom/"); |
|||
|
|||
BatCopyFileFromJar(fileFromClassPath1.toString(),linuxSOFolder1); |
|||
BatCopyFileFromJar(fileFromClassPath2.toString(),linuxSOFolder2); |
|||
log.info("文件复制结束"); |
|||
} |
|||
|
|||
public static void copyHCNetSdkFromWindows(){ |
|||
|
|||
log.info("开始复制文件"); |
|||
String WindowsDllFolder1 = userDir + "/models/"; |
|||
|
|||
File fileFromClassPath1 = FileCopyUtil.getFileFromClassPath("/models/"); |
|||
|
|||
BatCopyFileFromJar(fileFromClassPath1.toString(), WindowsDllFolder1); |
|||
log.info("文件复制结束"); |
|||
|
|||
} |
|||
|
|||
public static <T> boolean isStartupFromJar() { |
|||
String protocol = FileCopyUtil.class.getResource("").getProtocol(); |
|||
if ("jar".equals(protocol)){ |
|||
return true; |
|||
}else { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
@ -0,0 +1,140 @@ |
|||
package com.visual.open.anpr.server.utils; |
|||
|
|||
import org.springframework.core.io.ClassPathResource; |
|||
import org.springframework.core.io.Resource; |
|||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver; |
|||
import org.springframework.core.io.support.ResourcePatternResolver; |
|||
|
|||
import java.io.*; |
|||
|
|||
/** |
|||
* @author:hahaha |
|||
* @creattime:2021-12-02 10:33 |
|||
*/ |
|||
|
|||
public class FreeMarkerUtil { |
|||
|
|||
|
|||
/** |
|||
* 复制path目录下所有文件 |
|||
* @param path 文件目录 不能以/开头 |
|||
* @param newpath 新文件目录 |
|||
*/ |
|||
public static void BatCopyFileFromJar(String path,String newpath) { |
|||
if (!new File(newpath).exists()){ |
|||
new File(newpath).mkdir(); |
|||
} |
|||
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); |
|||
try { |
|||
//获取所有匹配的文件
|
|||
Resource[] resources = resolver.getResources(path+"/*"); |
|||
//打印有多少文件
|
|||
for(int i=0;i<resources.length;i++) { |
|||
Resource resource=resources[i]; |
|||
try { |
|||
//以jar运行时,resource.getFile().isFile() 无法获取文件类型,会报异常,抓取异常后直接生成新的文件即可;以非jar运行时,需要判断文件类型,避免如果是目录会复制错误,将目录写成文件。
|
|||
if(resource.getFile().isFile()) { |
|||
makeFile(newpath+"/"+resource.getFilename()); |
|||
InputStream stream = resource.getInputStream(); |
|||
write2File(stream, newpath+"/"+resource.getFilename()); |
|||
} |
|||
}catch (Exception e) { |
|||
makeFile(newpath+"/"+resource.getFilename()); |
|||
InputStream stream = resource.getInputStream(); |
|||
write2File(stream, newpath+"/"+resource.getFilename()); |
|||
} |
|||
} |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
/** |
|||
* 创建文件 |
|||
* @param path 全路径 指向文件 |
|||
* @return |
|||
*/ |
|||
public static boolean makeFile(String path) { |
|||
File file = new File(path); |
|||
if(file.exists()) { |
|||
return false; |
|||
} |
|||
if (path.endsWith(File.separator)) { |
|||
return false; |
|||
} |
|||
if(!file.getParentFile().exists()) { |
|||
if(!file.getParentFile().mkdirs()) { |
|||
return false; |
|||
} |
|||
} |
|||
try { |
|||
if (file.createNewFile()) { |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
} catch (IOException e) { |
|||
e.printStackTrace(); |
|||
return false; |
|||
} |
|||
} |
|||
/** |
|||
* 输入流写入文件 |
|||
* |
|||
* @param is |
|||
* 输入流 |
|||
* @param filePath |
|||
* 文件保存目录路径 |
|||
* @throws IOException |
|||
*/ |
|||
public static void write2File(InputStream is, String filePath) throws IOException { |
|||
OutputStream os = new FileOutputStream(filePath); |
|||
int len = 8192; |
|||
byte[] buffer = new byte[len]; |
|||
while ((len = is.read(buffer, 0, len)) != -1) { |
|||
os.write(buffer, 0, len); |
|||
} |
|||
os.close(); |
|||
is.close(); |
|||
} |
|||
/** |
|||
*处理异常报错(springboot读取classpath里的文件,解决打jar包java.io.FileNotFoundException: class path resource cannot be opened) |
|||
**/ |
|||
public static File getFileFromClassPath(String path){ |
|||
File targetFile = new File(path); |
|||
if(!targetFile.exists()){ |
|||
if(targetFile.getParent()!=null){ |
|||
File parent=new File(targetFile.getParent()); |
|||
if(!parent.exists()){ |
|||
parent.mkdirs(); |
|||
} |
|||
} |
|||
InputStream initialStream=null; |
|||
OutputStream outStream =null; |
|||
try { |
|||
Resource resource=new ClassPathResource(path); |
|||
//注意通过getInputStream,不能用getFile
|
|||
initialStream=resource.getInputStream(); |
|||
byte[] buffer = new byte[initialStream.available()]; |
|||
initialStream.read(buffer); |
|||
outStream = new FileOutputStream(targetFile); |
|||
outStream.write(buffer); |
|||
} catch (IOException e) { |
|||
} finally { |
|||
if (initialStream != null) { |
|||
try { |
|||
initialStream.close(); // 关闭流
|
|||
} catch (IOException e) { |
|||
} |
|||
} |
|||
if (outStream != null) { |
|||
try { |
|||
outStream.close(); // 关闭流
|
|||
} catch (IOException e) { |
|||
} |
|||
} |
|||
} |
|||
} |
|||
return targetFile; |
|||
} |
|||
} |
|||
|
@ -0,0 +1,82 @@ |
|||
package com.visual.open.anpr.server.utils; |
|||
|
|||
import javax.imageio.ImageIO; |
|||
import java.awt.image.BufferedImage; |
|||
import java.io.ByteArrayInputStream; |
|||
import java.io.ByteArrayOutputStream; |
|||
import java.io.File; |
|||
import java.io.IOException; |
|||
import java.util.Base64; |
|||
|
|||
public class ImageUtil { |
|||
|
|||
/** |
|||
* 图片转Base64字符串 |
|||
* @param imageFileName |
|||
* @return |
|||
*/ |
|||
public static String convertImageToBase64Str(String imageFileName) { |
|||
ByteArrayOutputStream baos = null; |
|||
try { |
|||
//获取图片类型
|
|||
String suffix = imageFileName.substring(imageFileName.lastIndexOf(".") + 1); |
|||
//构建文件
|
|||
File imageFile = new File(imageFileName); |
|||
//通过ImageIO把文件读取成BufferedImage对象
|
|||
BufferedImage bufferedImage = ImageIO.read(imageFile); |
|||
//构建字节数组输出流
|
|||
baos = new ByteArrayOutputStream(); |
|||
//写入流
|
|||
ImageIO.write(bufferedImage, suffix, baos); |
|||
//通过字节数组流获取字节数组
|
|||
byte[] bytes = baos.toByteArray(); |
|||
//获取JDK8里的编码器Base64.Encoder转为base64字符
|
|||
return Base64.getEncoder().encodeToString(bytes); |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} finally { |
|||
try { |
|||
if (baos != null) { |
|||
baos.close(); |
|||
} |
|||
} catch (IOException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
/** |
|||
* Base64字符串转图片 |
|||
* @param base64String |
|||
* @param imageFileName |
|||
*/ |
|||
public static void convertBase64StrToImage(String base64String, String imageFileName) { |
|||
ByteArrayInputStream bais = null; |
|||
try { |
|||
//获取图片类型
|
|||
String suffix = imageFileName.substring(imageFileName.lastIndexOf(".") + 1); |
|||
//获取JDK8里的解码器Base64.Decoder,将base64字符串转为字节数组
|
|||
byte[] bytes = Base64.getDecoder().decode(base64String); |
|||
//构建字节数组输入流
|
|||
bais = new ByteArrayInputStream(bytes); |
|||
//通过ImageIO把字节数组输入流转为BufferedImage
|
|||
BufferedImage bufferedImage = ImageIO.read(bais); |
|||
//构建文件
|
|||
File imageFile = new File(imageFileName); |
|||
//写入生成文件
|
|||
ImageIO.write(bufferedImage, suffix, imageFile); |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} finally { |
|||
try { |
|||
if (bais != null) { |
|||
bais.close(); |
|||
} |
|||
} catch (IOException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
@ -1,4 +1,4 @@ |
|||
package com.visual.open.anpr.utils; |
|||
package com.visual.open.anpr.server.utils; |
|||
|
|||
import com.alibaba.fastjson.JSON; |
|||
import com.alibaba.fastjson.JSONArray; |
@ -1,4 +1,4 @@ |
|||
package com.visual.open.anpr.core.utils; |
|||
package com.visual.open.anpr.server.utils; |
|||
|
|||
import org.opencv.core.Mat; |
|||
import org.opencv.core.Range; |
@ -1,4 +1,4 @@ |
|||
package com.visual.open.anpr.core.utils; |
|||
package com.visual.open.anpr.server.utils; |
|||
|
|||
import org.apache.commons.math3.linear.Array2DRowRealMatrix; |
|||
import org.apache.commons.math3.linear.ArrayRealVector; |
@ -1,9 +1,9 @@ |
|||
package com.visual.open.anpr.core.utils; |
|||
package com.visual.open.anpr.server.utils; |
|||
|
|||
import ai.onnxruntime.OnnxTensor; |
|||
import ai.onnxruntime.OrtSession; |
|||
import com.visual.open.anpr.core.domain.BorderMat; |
|||
import com.visual.open.anpr.core.domain.ImageMat; |
|||
import com.visual.open.anpr.server.domain.BorderMat; |
|||
import com.visual.open.anpr.server.domain.ImageMat; |
|||
import org.opencv.core.Mat; |
|||
|
|||
public class ReleaseUtil { |
@ -1,4 +1,4 @@ |
|||
package com.visual.open.anpr.core.utils; |
|||
package com.visual.open.anpr.server.utils; |
|||
|
|||
import java.util.function.DoubleUnaryOperator; |
|||
|
@ -1,9 +1,7 @@ |
|||
package com.visual.open.anpr.core.utils; |
|||
package com.visual.open.anpr.server.utils; |
|||
|
|||
import org.apache.commons.math3.linear.RealMatrix; |
|||
|
|||
import com.visual.open.anpr.core.utils.ArrayUtil; |
|||
|
|||
public class Similarity { |
|||
|
|||
/** |
@ -1,4 +1,4 @@ |
|||
package com.visual.open.anpr.core.utils; |
|||
package com.visual.open.anpr.server.utils; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.NoSuchElementException; |
@ -1,4 +1,4 @@ |
|||
package com.visual.open.anpr.core.utils; |
|||
package com.visual.open.anpr.server.utils; |
|||
|
|||
public class ThreadUtil { |
|||
|
@ -0,0 +1,170 @@ |
|||
//package com.visual.open.anpr.server.utils;
|
|||
//
|
|||
//import org.bytedeco.ffmpeg.avcodec.AVCodecParameters;
|
|||
//import org.bytedeco.ffmpeg.avformat.AVFormatContext;
|
|||
//import org.bytedeco.ffmpeg.avformat.AVStream;
|
|||
//import org.bytedeco.ffmpeg.global.avcodec;
|
|||
//import org.bytedeco.javacv.*;
|
|||
//import org.springframework.beans.factory.annotation.Value;
|
|||
//
|
|||
//import java.util.logging.Logger;
|
|||
//
|
|||
//
|
|||
//public class VideoUtil {
|
|||
//
|
|||
// @Value("3")
|
|||
// private Integer retryCount;//重试次数,默认值
|
|||
// @Value("100")
|
|||
// private Integer sleepTime;//休眠时间,默认值
|
|||
//
|
|||
// private static final Logger logger = Logger.getLogger(VideoUtil.class.getName());
|
|||
// /**
|
|||
// * 视频转码函数(仅转码)
|
|||
// *
|
|||
// * @param inputfile 原始视频文件完整路径
|
|||
// * @param outputfile 目标视频文件完整保存路径(必须完整文件名,即包含格式后缀,推荐格式后缀为.mp4)
|
|||
// * @throws Exception 异常
|
|||
// */
|
|||
// public static void videoConvert(String inputfile, String outputfile, Integer retryCount, Integer sleepTime) throws Exception {
|
|||
// if (outputfile.lastIndexOf('.') < 0) {
|
|||
// throw new Exception("Error! Output file format undetected!");
|
|||
// }
|
|||
// String format = outputfile.substring(outputfile.lastIndexOf('.'));
|
|||
//
|
|||
// FFmpegLogCallback.set();
|
|||
// Frame frame;
|
|||
// FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputfile);
|
|||
// FFmpegFrameRecorder recorder = null;
|
|||
//
|
|||
// try {
|
|||
// long start = System.currentTimeMillis();
|
|||
// logger.info("视频存储开始:"+ DateUtil.getCurrentDateTime());
|
|||
// logger.info("开始初始化帧抓取器");
|
|||
// // 初始化帧抓取器,例如数据结构(时间戳、编码器上下文、帧对象等),
|
|||
// // 如果入参等于true,还会调用avformat_find_stream_info方法获取流的信息,放入AVFormatContext类型的成员变量oc中
|
|||
// grabber.start(true);
|
|||
//
|
|||
// logger.info("帧抓取器初始化完成");
|
|||
//
|
|||
// // grabber.start方法中,初始化的解码器信息存在放在grabber的成员变量oc中
|
|||
// AVFormatContext avformatcontext = grabber.getFormatContext();
|
|||
//
|
|||
// // 文件内有几个媒体流(一般是视频流+音频流)
|
|||
// int streamNum = avformatcontext.nb_streams();
|
|||
//
|
|||
// // 没有媒体流就不用继续了
|
|||
// if (streamNum < 1)
|
|||
// {
|
|||
// logger.info("文件内不存在媒体流");
|
|||
// throw new Exception("Error! There is no media stream in the file!");
|
|||
// }
|
|||
//
|
|||
// // 取得视频的帧率
|
|||
// double framerate = grabber.getVideoFrameRate();
|
|||
//
|
|||
// System.out.printf("视频帧率[%f],视频时长[%d]秒,媒体流数量[%d]\r\n", framerate, avformatcontext.duration() / 1000000,
|
|||
// avformatcontext.nb_streams());
|
|||
//
|
|||
// // 遍历每一个流,检查其类型
|
|||
// for (int i = 0; i < streamNum; i++) {
|
|||
// AVStream avstream = avformatcontext.streams(i);
|
|||
// AVCodecParameters avcodecparameters = avstream.codecpar();
|
|||
// System.out.printf("流的索引[%d],编码器类型[%d],编码器ID[%d]\r\n", i, avcodecparameters.codec_type(),
|
|||
// avcodecparameters.codec_id());
|
|||
// }
|
|||
//
|
|||
// // 视频宽度
|
|||
// int frameWidth = grabber.getImageWidth();
|
|||
// // 视频高度
|
|||
// int frameHeight = grabber.getImageHeight();
|
|||
// // 音频通道数量
|
|||
// int audiochannels = grabber.getAudioChannels();
|
|||
//
|
|||
// System.out.printf("视频宽度[%d],视频高度[%d],音频通道数[%d]\r\n", frameWidth, frameHeight, audiochannels);
|
|||
//
|
|||
// recorder = new FFmpegFrameRecorder(outputfile, frameWidth, frameHeight, audiochannels);
|
|||
// recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
|
|||
//
|
|||
// recorder.setFormat(format);
|
|||
// // 使用原始视频的码率,若需要则自行修改码率
|
|||
// recorder.setVideoBitrate(grabber.getVideoBitrate());
|
|||
//
|
|||
// // 一秒内的帧数,帧率
|
|||
// recorder.setFrameRate(framerate);
|
|||
//
|
|||
// // 两个关键帧之间的帧数
|
|||
// recorder.setGopSize((int)framerate);
|
|||
//
|
|||
// // 设置音频通道数,与视频源的通道数相等
|
|||
// recorder.setAudioChannels(grabber.getAudioChannels());
|
|||
//
|
|||
// recorder.start();
|
|||
//
|
|||
// int videoframenum = 0;
|
|||
// int audioframenum = 0;
|
|||
// int dataframenum = 0;
|
|||
//
|
|||
// logger.info("开始录制\r\n");
|
|||
//
|
|||
// // 循环条件
|
|||
// int count = 0;
|
|||
//
|
|||
// // 持续从视频源取帧
|
|||
// while (true) {
|
|||
// frame = grabber.grab();
|
|||
// if (frame != null) {
|
|||
// // 有图像,就把视频帧加一
|
|||
// if (null != frame.image) {
|
|||
// videoframenum++;
|
|||
// // 取出的每一帧,都保存到视频
|
|||
// recorder.record(frame);
|
|||
// }
|
|||
// // 有声音,就把音频帧加一
|
|||
// if (null != frame.samples) {
|
|||
// audioframenum++;
|
|||
// // 取出的每一帧,都保存到视频
|
|||
// recorder.record(frame);
|
|||
// }
|
|||
// // 有数据,就把数据帧加一
|
|||
// if (null != frame.data) {
|
|||
// dataframenum++;
|
|||
// }
|
|||
// count = 0;
|
|||
// }else {
|
|||
// if (retryCount == null || retryCount == 0) {
|
|||
// break;
|
|||
// }
|
|||
// if (count > retryCount) {
|
|||
// break;
|
|||
// }
|
|||
// if (sleepTime != null && sleepTime > 0) {
|
|||
// // 休眠一段时间后重试
|
|||
// Thread.sleep(sleepTime);
|
|||
// }
|
|||
// count ++;
|
|||
// }
|
|||
// }
|
|||
// long end = System.currentTimeMillis();
|
|||
// long second = (end - start) / 1000;
|
|||
// logger.info("视频存储结束:"+ DateUtil.getCurrentDateTime());
|
|||
// logger.info("视频存储总耗时(秒):"+ second);
|
|||
// System.out.printf("转码完成,视频帧[%d],音频帧[%d],数据帧[%d]\r\n", videoframenum, audioframenum, dataframenum);
|
|||
// logger.info("转码完成,视频帧"+videoframenum+",音频帧" + audioframenum + ",数据帧" + dataframenum);
|
|||
// } catch (Exception e) {
|
|||
// e.printStackTrace();
|
|||
// } finally {
|
|||
// if (recorder != null) {
|
|||
// try {
|
|||
// recorder.close();
|
|||
// } catch (Exception e) {
|
|||
// e.printStackTrace();
|
|||
// }
|
|||
// }
|
|||
// try {
|
|||
// grabber.close();
|
|||
// } catch (FrameGrabber.Exception e) {
|
|||
// e.printStackTrace();
|
|||
// }
|
|||
// }
|
|||
// }
|
|||
//}
|
@ -1,32 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
|
|||
<groupId>com.visual.open.anpr</groupId> |
|||
<artifactId>open-anpr-test</artifactId> |
|||
<version>1.1.0</version> |
|||
|
|||
<properties> |
|||
<java.version>1.8</java.version> |
|||
<maven.compiler.source>8</maven.compiler.source> |
|||
<maven.compiler.target>8</maven.compiler.target> |
|||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
|||
</properties> |
|||
|
|||
<dependencies> |
|||
<dependency> |
|||
<groupId>com.visual.open.anpr</groupId> |
|||
<artifactId>open-anpr-client</artifactId> |
|||
<version>${project.version}</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.openpnp</groupId> |
|||
<artifactId>opencv</artifactId> |
|||
<version>4.6.0-0</version> |
|||
</dependency> |
|||
</dependencies> |
|||
|
|||
</project> |
@ -1,84 +0,0 @@ |
|||
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()); |
|||
System.out.println(files.length); |
|||
for(int i=0; i < files.length; i++){ |
|||
System.out.println(i); |
|||
File imageA = files[i]; |
|||
String imageBase64 = Base64Util.encode(imageA.getAbsolutePath()); |
|||
Response<List<RecognitionRep>> 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.drawLine( |
|||
new DrawImage.Point(location.getLeftTop().getX(), location.getLeftTop().getY()), |
|||
new DrawImage.Point(location.getRightTop().getX(), location.getRightTop().getY()), |
|||
2, Color.RED |
|||
); |
|||
drawImage.drawLine( |
|||
new DrawImage.Point(location.getRightTop().getX(), location.getRightTop().getY()), |
|||
new DrawImage.Point(location.getRightBottom().getX(), location.getRightBottom().getY()), |
|||
2, Color.RED |
|||
); |
|||
drawImage.drawLine( |
|||
new DrawImage.Point(location.getRightBottom().getX(), location.getRightBottom().getY()), |
|||
new DrawImage.Point(location.getLeftBottom().getX(), location.getLeftBottom().getY()), |
|||
2, Color.RED |
|||
); |
|||
drawImage.drawLine( |
|||
new DrawImage.Point(location.getLeftBottom().getX(), location.getLeftBottom().getY()), |
|||
new DrawImage.Point(location.getLeftTop().getX(), location.getLeftTop().getY()), |
|||
2, Color.RED |
|||
); |
|||
//画识别信息
|
|||
RecognitionInfo recognition = recognitionRep.getRecognition(); |
|||
int fonSize = Float.valueOf(1.4f * location.width() / recognition.getPlateNo().length()).intValue(); |
|||
drawImage.drawText(recognition.getPlateNo(), |
|||
new DrawImage.Point(location.minX(), location.minY()-(int)(fonSize*2.2)), fonSize, Color.RED); |
|||
drawImage.drawText((recognition.getLayout() == PlateLayout.SINGLE ? "单排" : "双排") + ":" + recognition.getPlateColor().getName(), |
|||
new DrawImage.Point(location.minX(), location.minY()-(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(); |
|||
} |
|||
|
|||
} |
@ -1,107 +0,0 @@ |
|||
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; |
|||
} |
|||
|
|||
} |
Before Width: | Height: | Size: 107 KiB |
Before Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 390 KiB |
Before Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 671 KiB |
Before Width: | Height: | Size: 328 KiB |
Before Width: | Height: | Size: 382 KiB |
Before Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 999 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 400 KiB |
Before Width: | Height: | Size: 659 KiB |
Before Width: | Height: | Size: 82 KiB |
Before Width: | Height: | Size: 979 KiB |