Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
I
image-backend
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
陈皓
image-backend
Commits
003b7634
Commit
003b7634
authored
Nov 28, 2023
by
陈皓
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
init
parent
cae76626
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
47 changed files
with
3619 additions
and
3 deletions
+3619
-3
file-server/src/main/java/com/zq/file/controller/AccessController.java
+15
-0
gateway-server/src/main/resources/application.yml
+4
-0
imgproc-server/pom.xml
+80
-0
imgproc-server/src/main/java/com/zq/imgproc/config/FeignConfig.java
+83
-0
imgproc-server/src/main/java/com/zq/imgproc/config/InitConfig.java
+26
-0
imgproc-server/src/main/java/com/zq/imgproc/config/JwtAccessDeniedHandler.java
+38
-0
imgproc-server/src/main/java/com/zq/imgproc/config/JwtAuthenticationEntryPoint.java
+40
-0
imgproc-server/src/main/java/com/zq/imgproc/config/SpringSecurityConfig.java
+189
-0
imgproc-server/src/main/java/com/zq/imgproc/config/SwaggerConfig.java
+65
-0
imgproc-server/src/main/java/com/zq/imgproc/config/TokenConfigurer.java
+42
-0
imgproc-server/src/main/java/com/zq/imgproc/config/TokenFilter.java
+91
-0
imgproc-server/src/main/java/com/zq/imgproc/config/TokenProvider.java
+137
-0
imgproc-server/src/main/java/com/zq/imgproc/constant/Threshold.java
+45
-0
imgproc-server/src/main/java/com/zq/imgproc/controller/ApiController.java
+166
-0
imgproc-server/src/main/java/com/zq/imgproc/controller/ImageDetectionController.java
+51
-0
imgproc-server/src/main/java/com/zq/imgproc/controller/ImgProcController.java
+167
-0
imgproc-server/src/main/java/com/zq/imgproc/controller/ImgSettingController.java
+71
-0
imgproc-server/src/main/java/com/zq/imgproc/dao/ImageDetectionDao.java
+29
-0
imgproc-server/src/main/java/com/zq/imgproc/dao/ImgSettingDao.java
+17
-0
imgproc-server/src/main/java/com/zq/imgproc/entity/ImageDetection.java
+102
-0
imgproc-server/src/main/java/com/zq/imgproc/entity/ImgSetting.java
+119
-0
imgproc-server/src/main/java/com/zq/imgproc/server/ImageDetectionService.java
+169
-0
imgproc-server/src/main/java/com/zq/imgproc/server/ImgProcService.java
+0
-0
imgproc-server/src/main/java/com/zq/imgproc/utils/BendUtil.java
+83
-0
imgproc-server/src/main/java/com/zq/imgproc/utils/DecompressUtil.java
+155
-0
imgproc-server/src/main/java/com/zq/imgproc/utils/DemoUtil.java
+64
-0
imgproc-server/src/main/java/com/zq/imgproc/utils/Deskew.java
+163
-0
imgproc-server/src/main/java/com/zq/imgproc/utils/ImageCorrectionUtil.java
+168
-0
imgproc-server/src/main/java/com/zq/imgproc/utils/ImageUtil.java
+0
-0
imgproc-server/src/main/java/com/zq/imgproc/utils/RemoveBlackUtil.java
+210
-0
imgproc-server/src/main/java/com/zq/imgproc/utils/RemoveBlackUtil2.java
+142
-0
imgproc-server/src/main/java/com/zq/imgproc/utils/Test2.java
+170
-0
imgproc-server/src/main/java/com/zq/imgproc/utils/TestUtil.java
+166
-0
imgproc-server/src/main/java/com/zq/imgproc/utils/UploadUtils.java
+46
-0
imgproc-server/src/main/java/com/zq/imgproc/vo/BendResult.java
+39
-0
imgproc-server/src/main/java/com/zq/imgproc/vo/CompressReq.java
+22
-0
imgproc-server/src/main/java/com/zq/imgproc/vo/DetectionDTO.java
+43
-0
imgproc-server/src/main/java/com/zq/imgproc/vo/DetectionPageReq.java
+87
-0
imgproc-server/src/main/java/com/zq/imgproc/vo/DetectionResVo.java
+42
-0
imgproc-server/src/main/java/com/zq/imgproc/vo/DetectionVO.java
+47
-0
imgproc-server/src/main/java/com/zq/imgproc/vo/ImgVO.java
+32
-0
imgproc-server/src/main/java/com/zq/imgproc/vo/OptimizationReq.java
+20
-0
imgproc-server/src/main/java/com/zq/imgproc/vo/OptimizationVO.java
+56
-0
imgproc-server/src/main/java/com/zq/imgproc/vo/RotateReq.java
+31
-0
imgproc-server/src/main/java/com/zq/imgproc/vo/SettingVO.java
+32
-0
imgproc-server/src/main/resources/application.yml
+13
-3
imgproc-server/src/main/resources/mapper/ImageDetectionMapper.xml
+42
-0
No files found.
file-server/src/main/java/com/zq/file/controller/AccessController.java
View file @
003b7634
...
@@ -56,4 +56,19 @@ public class AccessController {
...
@@ -56,4 +56,19 @@ public class AccessController {
.
body
(
new
FileSystemResource
(
file
));
.
body
(
new
FileSystemResource
(
file
));
}
}
@GetMapping
(
value
=
"/data/**"
)
public
ResponseEntity
<
Resource
>
downloadData
(
HttpServletRequest
request
)
{
File
file
=
new
File
(
request
.
getRequestURI
());
AssertUtils
.
isTrue
(
file
.
exists
(),
"访问文件不存在"
);
String
contentDisposition
=
ContentDisposition
.
builder
(
"attachment"
)
.
filename
(
request
.
getRequestURI
())
.
build
().
toString
();
return
ResponseEntity
.
ok
()
.
header
(
HttpHeaders
.
CONTENT_DISPOSITION
,
contentDisposition
)
.
contentType
(
MediaType
.
APPLICATION_OCTET_STREAM
)
.
body
(
new
FileSystemResource
(
file
));
}
}
}
gateway-server/src/main/resources/application.yml
View file @
003b7634
...
@@ -33,6 +33,10 @@ spring:
...
@@ -33,6 +33,10 @@ spring:
uri
:
lb://FILE-SERVER
uri
:
lb://FILE-SERVER
predicates
:
predicates
:
-
Path=/file/**
-
Path=/file/**
-
id
:
data
uri
:
lb://FILE-SERVER
predicates
:
-
Path=/data/**
-
id
:
user
-
id
:
user
uri
:
lb://USER-SERVER
uri
:
lb://USER-SERVER
predicates
:
predicates
:
...
...
imgproc-server/pom.xml
View file @
003b7634
...
@@ -81,6 +81,86 @@
...
@@ -81,6 +81,86 @@
<artifactId>
mysql-connector-java
</artifactId>
<artifactId>
mysql-connector-java
</artifactId>
<scope>
runtime
</scope>
<scope>
runtime
</scope>
</dependency>
</dependency>
<dependency>
<groupId>
org.springframework.cloud
</groupId>
<artifactId>
spring-cloud-starter-bootstrap
</artifactId>
</dependency>
<!-- OpenCv -->
<!-- mvn install:install-file -Dfile=./src/main/resources/lib/opencv-460.jar -DgroupId=org.opencv -DartifactId=opencv -Dversion=4.6.0 -Dpackaging=jar -->
<dependency>
<groupId>
org.opencv
</groupId>
<artifactId>
opencv
</artifactId>
<version>
4.6.0
</version>
</dependency>
<!-- Webp图片格式支持 -->
<dependency>
<groupId>
org.sejda.imageio
</groupId>
<artifactId>
webp-imageio
</artifactId>
<version>
0.1.6
</version>
</dependency>
<!-- JPEG图片格式支持 -->
<dependency>
<groupId>
com.twelvemonkeys.imageio
</groupId>
<artifactId>
imageio-jpeg
</artifactId>
<version>
3.9.4
</version>
</dependency>
<!-- TIFF图片格式支持 -->
<dependency>
<groupId>
com.twelvemonkeys.imageio
</groupId>
<artifactId>
imageio-tiff
</artifactId>
<version>
3.9.4
</version>
</dependency>
<dependency>
<groupId>
org.apache.commons
</groupId>
<artifactId>
commons-imaging
</artifactId>
<version>
1.0-alpha3
</version>
</dependency>
<dependency>
<groupId>
org.apache.commons
</groupId>
<artifactId>
commons-compress
</artifactId>
<version>
1.22
</version>
</dependency>
<dependency>
<groupId>
org.tukaani
</groupId>
<artifactId>
xz
</artifactId>
<version>
1.9
</version>
</dependency>
<dependency>
<groupId>
cn.hutool
</groupId>
<artifactId>
hutool-all
</artifactId>
<version>
5.8.19
</version>
</dependency>
<dependency>
<groupId>
com.alibaba
</groupId>
<artifactId>
easyexcel
</artifactId>
<version>
3.3.2
</version>
</dependency>
<dependency>
<groupId>
com.drewnoakes
</groupId>
<artifactId>
metadata-extractor
</artifactId>
<version>
2.18.0
</version>
</dependency>
<dependency>
<groupId>
org.projectlombok
</groupId>
<artifactId>
lombok
</artifactId>
<version>
1.18.28
</version>
</dependency>
<dependency>
<groupId>
io.springfox
</groupId>
<artifactId>
springfox-swagger2
</artifactId>
<version>
2.9.2
</version>
</dependency>
<dependency>
<groupId>
io.springfox
</groupId>
<artifactId>
springfox-swagger-ui
</artifactId>
<version>
2.9.2
</version>
</dependency>
<!-- guava -->
<dependency>
<groupId>
com.google.guava
</groupId>
<artifactId>
guava
</artifactId>
<version>
32.1.3-jre
</version>
</dependency>
</dependencies>
</dependencies>
<build>
<build>
...
...
imgproc-server/src/main/java/com/zq/imgproc/config/FeignConfig.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
config
;
import
com.zq.common.constant.FeignHeader
;
import
feign.RequestInterceptor
;
import
feign.RequestTemplate
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.web.context.request.RequestAttributes
;
import
org.springframework.web.context.request.RequestContextHolder
;
import
org.springframework.web.context.request.ServletRequestAttributes
;
import
javax.servlet.http.HttpServletRequest
;
import
java.util.Arrays
;
import
java.util.Enumeration
;
import
java.util.List
;
/**
* @author wilmiam
* @since 2021-07-09 10:34
*/
@Configuration
public
class
FeignConfig
{
/**
* 转发请求头
*/
private
static
final
List
<
String
>
FORWARD_HEADERS
=
Arrays
.
asList
(
"AUTHORIZATION"
,
"X-FORWARDED-FOR"
,
"X-FORWARDED-PROTO"
,
"X-FORWARDED-PORT"
,
"X-FORWARDED-HOST"
,
"FORWARDED"
,
"PROXY-CLIENT-IP"
,
"WL-PROXY-CLIENT-IP"
,
"HTTP_X_FORWARDED_FOR"
,
"HTTP_X_FORWARDED"
,
"HTTP_X_CLUSTER_CLIENT_IP"
,
"HTTP_CLIENT_IP"
,
"HTTP_FORWARDED_FOR"
,
"HTTP_FORWARDED"
,
"HTTP_VIA"
,
"REMOTE_ADDR"
,
"X-REAL-IP"
,
"HOST"
);
/**
* 解决fein远程调用丢失请求头
*
* @return
*/
@Bean
public
RequestInterceptor
requestInterceptor
()
{
return
new
RequestInterceptor
()
{
@Override
public
void
apply
(
RequestTemplate
template
)
{
RequestAttributes
requestAttributes
=
RequestContextHolder
.
getRequestAttributes
();
if
(
requestAttributes
==
null
)
{
return
;
}
HttpServletRequest
request
=
((
ServletRequestAttributes
)
requestAttributes
).
getRequest
();
template
.
header
(
FeignHeader
.
API_TOKEN
,
request
.
getParameter
(
"token"
));
Enumeration
<
String
>
headerNames
=
request
.
getHeaderNames
();
if
(
headerNames
!=
null
)
{
while
(
headerNames
.
hasMoreElements
())
{
String
name
=
headerNames
.
nextElement
();
// 不要设置content-length
if
(
"content-length"
.
equals
(
name
))
{
continue
;
}
if
(
FORWARD_HEADERS
.
contains
(
name
.
toUpperCase
()))
{
String
values
=
request
.
getHeader
(
name
);
template
.
header
(
name
,
values
);
}
}
}
}
};
}
}
imgproc-server/src/main/java/com/zq/imgproc/config/InitConfig.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
config
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.context.annotation.Configuration
;
import
javax.annotation.PostConstruct
;
/**
* @author chenhao
* @since 2023/8/11 10:30
*/
@Slf4j
@Configuration
public
class
InitConfig
{
@Value
(
"${imgconfig.opencv}"
)
String
opencvUrl
;
@PostConstruct
public
void
asposeRegister
()
{
System
.
load
(
opencvUrl
);
log
.
info
(
">> opencv 加载成功..."
);
}
}
imgproc-server/src/main/java/com/zq/imgproc/config/JwtAccessDeniedHandler.java
0 → 100644
View file @
003b7634
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
zq
.
imgproc
.
config
;
import
org.springframework.security.access.AccessDeniedException
;
import
org.springframework.security.web.access.AccessDeniedHandler
;
import
org.springframework.stereotype.Component
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.IOException
;
/**
* @author Zheng Jie
*/
@Component
public
class
JwtAccessDeniedHandler
implements
AccessDeniedHandler
{
@Override
public
void
handle
(
HttpServletRequest
request
,
HttpServletResponse
response
,
AccessDeniedException
accessDeniedException
)
throws
IOException
{
//当用户在没有授权的情况下访问受保护的REST资源时,将调用此方法发送403 Forbidden响应
response
.
sendError
(
HttpServletResponse
.
SC_FORBIDDEN
,
accessDeniedException
.
getMessage
());
}
}
imgproc-server/src/main/java/com/zq/imgproc/config/JwtAuthenticationEntryPoint.java
0 → 100644
View file @
003b7634
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
zq
.
imgproc
.
config
;
import
org.springframework.security.core.AuthenticationException
;
import
org.springframework.security.web.AuthenticationEntryPoint
;
import
org.springframework.stereotype.Component
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.IOException
;
/**
* @author Zheng Jie
*/
@Component
public
class
JwtAuthenticationEntryPoint
implements
AuthenticationEntryPoint
{
@Override
public
void
commence
(
HttpServletRequest
request
,
HttpServletResponse
response
,
AuthenticationException
authException
)
throws
IOException
{
// 当用户尝试访问安全的REST资源而不提供任何凭据时,将调用此方法发送401 响应
response
.
sendError
(
HttpServletResponse
.
SC_UNAUTHORIZED
,
authException
==
null
?
"Unauthorized"
:
authException
.
getMessage
());
}
}
imgproc-server/src/main/java/com/zq/imgproc/config/SpringSecurityConfig.java
0 → 100644
View file @
003b7634
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
zq
.
imgproc
.
config
;
import
com.zq.common.annotation.AnonymousAccess
;
import
com.zq.common.config.redis.RedisUtils
;
import
com.zq.common.config.security.SecurityProperties
;
import
com.zq.common.utils.RequestMethodEnum
;
import
lombok.RequiredArgsConstructor
;
import
org.springframework.context.ApplicationContext
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.http.HttpMethod
;
import
org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity
;
import
org.springframework.security.config.annotation.web.builders.HttpSecurity
;
import
org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
;
import
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
;
import
org.springframework.security.config.core.GrantedAuthorityDefaults
;
import
org.springframework.security.config.http.SessionCreationPolicy
;
import
org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
;
import
org.springframework.security.crypto.password.PasswordEncoder
;
import
org.springframework.web.bind.annotation.RequestMethod
;
import
org.springframework.web.method.HandlerMethod
;
import
org.springframework.web.servlet.mvc.method.RequestMappingInfo
;
import
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
;
import
java.util.*
;
/**
* @author Zheng Jie
*/
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableGlobalMethodSecurity
(
prePostEnabled
=
true
,
securedEnabled
=
true
)
public
class
SpringSecurityConfig
extends
WebSecurityConfigurerAdapter
{
private
final
TokenProvider
tokenProvider
;
private
final
JwtAuthenticationEntryPoint
authenticationErrorHandler
;
private
final
JwtAccessDeniedHandler
jwtAccessDeniedHandler
;
private
final
ApplicationContext
applicationContext
;
private
final
SecurityProperties
properties
;
private
final
RedisUtils
redisUtils
;
@Bean
public
GrantedAuthorityDefaults
grantedAuthorityDefaults
()
{
// 去除 ROLE_ 前缀
return
new
GrantedAuthorityDefaults
(
""
);
}
@Bean
public
PasswordEncoder
passwordEncoder
()
{
// 密码加密方式
return
new
BCryptPasswordEncoder
();
}
@Override
protected
void
configure
(
HttpSecurity
httpSecurity
)
throws
Exception
{
// 搜寻匿名标记 url: @AnonymousAccess
RequestMappingHandlerMapping
requestMappingHandlerMapping
=
(
RequestMappingHandlerMapping
)
applicationContext
.
getBean
(
"requestMappingHandlerMapping"
);
Map
<
RequestMappingInfo
,
HandlerMethod
>
handlerMethodMap
=
requestMappingHandlerMapping
.
getHandlerMethods
();
// 获取匿名标记
Map
<
String
,
Set
<
String
>>
anonymousUrls
=
getAnonymousUrl
(
handlerMethodMap
);
Set
<
String
>
allType
=
anonymousUrls
.
get
(
RequestMethodEnum
.
ALL
.
getType
());
//不使用注解的时候在这添加url放行
allType
.
add
(
"/archive/api/**"
);
httpSecurity
// 禁用 CSRF
.
csrf
().
disable
()
// .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
// 授权异常
.
exceptionHandling
()
.
authenticationEntryPoint
(
authenticationErrorHandler
)
.
accessDeniedHandler
(
jwtAccessDeniedHandler
)
// 防止iframe 造成跨域
.
and
()
.
headers
()
.
frameOptions
()
.
disable
()
// 不创建会话
.
and
()
.
sessionManagement
()
.
sessionCreationPolicy
(
SessionCreationPolicy
.
STATELESS
)
.
and
()
.
authorizeRequests
()
// 静态资源等等
.
antMatchers
(
HttpMethod
.
GET
,
"/*.html"
,
"/**/*.html"
,
"/**/*.css"
,
"/**/*.js"
,
"/webSocket/**"
).
permitAll
()
// swagger 文档
.
antMatchers
(
"/swagger-ui.html"
).
permitAll
()
.
antMatchers
(
"/swagger-resources/**"
).
permitAll
()
.
antMatchers
(
"/webjars/**"
).
permitAll
()
.
antMatchers
(
"/*/api-docs"
).
permitAll
()
// 文件
.
antMatchers
(
"/avatar/**"
).
permitAll
()
.
antMatchers
(
"/file/**"
).
permitAll
()
// 阿里巴巴 druid
.
antMatchers
(
"/druid/**"
).
permitAll
()
// 放行OPTIONS请求
.
antMatchers
(
HttpMethod
.
OPTIONS
,
"/**"
).
permitAll
()
// 自定义匿名访问所有url放行:允许匿名和带Token访问,细腻化到每个 Request 类型
// GET
.
antMatchers
(
HttpMethod
.
GET
,
anonymousUrls
.
get
(
RequestMethodEnum
.
GET
.
getType
()).
toArray
(
new
String
[
0
])).
permitAll
()
// POST
.
antMatchers
(
HttpMethod
.
POST
,
anonymousUrls
.
get
(
RequestMethodEnum
.
POST
.
getType
()).
toArray
(
new
String
[
0
])).
permitAll
()
// PUT
.
antMatchers
(
HttpMethod
.
PUT
,
anonymousUrls
.
get
(
RequestMethodEnum
.
PUT
.
getType
()).
toArray
(
new
String
[
0
])).
permitAll
()
// PATCH
.
antMatchers
(
HttpMethod
.
PATCH
,
anonymousUrls
.
get
(
RequestMethodEnum
.
PATCH
.
getType
()).
toArray
(
new
String
[
0
])).
permitAll
()
// DELETE
.
antMatchers
(
HttpMethod
.
DELETE
,
anonymousUrls
.
get
(
RequestMethodEnum
.
DELETE
.
getType
()).
toArray
(
new
String
[
0
])).
permitAll
()
// 所有类型的接口都放行
.
antMatchers
(
allType
.
toArray
(
new
String
[
0
])).
permitAll
()
// 所有请求都需要认证
.
anyRequest
().
authenticated
()
.
and
().
apply
(
securityConfigurerAdapter
());
}
private
TokenConfigurer
securityConfigurerAdapter
()
{
return
new
TokenConfigurer
(
tokenProvider
,
redisUtils
,
properties
);
}
private
Map
<
String
,
Set
<
String
>>
getAnonymousUrl
(
Map
<
RequestMappingInfo
,
HandlerMethod
>
handlerMethodMap
)
{
Map
<
String
,
Set
<
String
>>
anonymousUrls
=
new
HashMap
<>(
6
);
Set
<
String
>
get
=
new
HashSet
<>();
Set
<
String
>
post
=
new
HashSet
<>();
Set
<
String
>
put
=
new
HashSet
<>();
Set
<
String
>
patch
=
new
HashSet
<>();
Set
<
String
>
delete
=
new
HashSet
<>();
Set
<
String
>
all
=
new
HashSet
<>();
for
(
Map
.
Entry
<
RequestMappingInfo
,
HandlerMethod
>
infoEntry
:
handlerMethodMap
.
entrySet
())
{
HandlerMethod
handlerMethod
=
infoEntry
.
getValue
();
AnonymousAccess
anonymousAccess
=
handlerMethod
.
getMethodAnnotation
(
AnonymousAccess
.
class
);
if
(
null
!=
anonymousAccess
)
{
List
<
RequestMethod
>
requestMethods
=
new
ArrayList
<>(
infoEntry
.
getKey
().
getMethodsCondition
().
getMethods
());
RequestMethodEnum
request
=
RequestMethodEnum
.
find
(
requestMethods
.
size
()
==
0
?
RequestMethodEnum
.
ALL
.
getType
()
:
requestMethods
.
get
(
0
).
name
());
switch
(
Objects
.
requireNonNull
(
request
))
{
case
GET:
get
.
addAll
(
infoEntry
.
getKey
().
getPatternsCondition
().
getPatterns
());
break
;
case
POST:
post
.
addAll
(
infoEntry
.
getKey
().
getPatternsCondition
().
getPatterns
());
break
;
case
PUT:
put
.
addAll
(
infoEntry
.
getKey
().
getPatternsCondition
().
getPatterns
());
break
;
case
PATCH:
patch
.
addAll
(
infoEntry
.
getKey
().
getPatternsCondition
().
getPatterns
());
break
;
case
DELETE:
delete
.
addAll
(
infoEntry
.
getKey
().
getPatternsCondition
().
getPatterns
());
break
;
default
:
all
.
addAll
(
infoEntry
.
getKey
().
getPatternsCondition
().
getPatterns
());
break
;
}
}
}
anonymousUrls
.
put
(
RequestMethodEnum
.
GET
.
getType
(),
get
);
anonymousUrls
.
put
(
RequestMethodEnum
.
POST
.
getType
(),
post
);
anonymousUrls
.
put
(
RequestMethodEnum
.
PUT
.
getType
(),
put
);
anonymousUrls
.
put
(
RequestMethodEnum
.
PATCH
.
getType
(),
patch
);
anonymousUrls
.
put
(
RequestMethodEnum
.
DELETE
.
getType
(),
delete
);
anonymousUrls
.
put
(
RequestMethodEnum
.
ALL
.
getType
(),
all
);
return
anonymousUrls
;
}
}
imgproc-server/src/main/java/com/zq/imgproc/config/SwaggerConfig.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
config
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.web.servlet.config.annotation.EnableWebMvc
;
import
org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
;
import
org.springframework.web.servlet.config.annotation.WebMvcConfigurer
;
import
springfox.documentation.builders.ApiInfoBuilder
;
import
springfox.documentation.builders.PathSelectors
;
import
springfox.documentation.builders.RequestHandlerSelectors
;
import
springfox.documentation.service.ApiInfo
;
import
springfox.documentation.spi.DocumentationType
;
import
springfox.documentation.spring.web.plugins.Docket
;
/**
* <p>
* Swagger配置类
* </p>
*
* @ClassName SwaggerConfig
* @Author chenhao
* @Date 2022/10/14 18:04
*/
@Configuration
@EnableWebMvc
public
class
SwaggerConfig
implements
WebMvcConfigurer
{
@Value
(
"${spring.cloud.config.profile:product}"
)
private
String
profile
;
@Override
public
void
addResourceHandlers
(
ResourceHandlerRegistry
registry
)
{
registry
.
addResourceHandler
(
"/**"
).
addResourceLocations
(
"classpath:/static/"
);
registry
.
addResourceHandler
(
"swagger-ui.html"
).
addResourceLocations
(
"classpath:/META-INF/resources/"
);
registry
.
addResourceHandler
(
"/webjars/**"
).
addResourceLocations
(
"classpath:/META-INF/resources/webjars/"
);
WebMvcConfigurer
.
super
.
addResourceHandlers
(
registry
);
}
@Bean
public
Docket
api
()
{
return
new
Docket
(
DocumentationType
.
SWAGGER_2
)
.
groupName
(
"项目"
)
// 生产环境关闭
.
enable
(!
"product"
.
equals
(
profile
))
.
select
()
.
apis
(
RequestHandlerSelectors
.
basePackage
(
"com.zq.archive.controller"
))
.
paths
(
PathSelectors
.
any
())
.
build
()
.
apiInfo
(
apiInfo
());
}
private
ApiInfo
apiInfo
()
{
return
new
ApiInfoBuilder
()
.
title
(
"后台接口文档"
)
.
description
(
"查看接口文档"
)
.
build
();
}
}
imgproc-server/src/main/java/com/zq/imgproc/config/TokenConfigurer.java
0 → 100644
View file @
003b7634
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
zq
.
imgproc
.
config
;
import
com.zq.common.config.redis.RedisUtils
;
import
com.zq.common.config.security.SecurityProperties
;
import
lombok.RequiredArgsConstructor
;
import
org.springframework.security.config.annotation.SecurityConfigurerAdapter
;
import
org.springframework.security.config.annotation.web.builders.HttpSecurity
;
import
org.springframework.security.web.DefaultSecurityFilterChain
;
import
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
;
/**
* @author /
*/
@RequiredArgsConstructor
public
class
TokenConfigurer
extends
SecurityConfigurerAdapter
<
DefaultSecurityFilterChain
,
HttpSecurity
>
{
private
final
TokenProvider
tokenProvider
;
private
final
RedisUtils
redisUtils
;
private
final
SecurityProperties
properties
;
@Override
public
void
configure
(
HttpSecurity
http
)
{
TokenFilter
customFilter
=
new
TokenFilter
(
tokenProvider
,
properties
,
redisUtils
);
http
.
addFilterBefore
(
customFilter
,
UsernamePasswordAuthenticationFilter
.
class
);
}
}
imgproc-server/src/main/java/com/zq/imgproc/config/TokenFilter.java
0 → 100644
View file @
003b7634
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
zq
.
imgproc
.
config
;
import
cn.hutool.core.util.StrUtil
;
import
com.zq.common.config.redis.BaseCacheKeys
;
import
com.zq.common.config.redis.RedisUtils
;
import
com.zq.common.config.security.SecurityProperties
;
import
com.zq.common.context.ContextUtils
;
import
com.zq.common.vo.OnlineUserDto
;
import
org.apache.commons.lang3.StringUtils
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.security.core.Authentication
;
import
org.springframework.security.core.context.SecurityContextHolder
;
import
org.springframework.web.filter.GenericFilterBean
;
import
javax.servlet.FilterChain
;
import
javax.servlet.ServletException
;
import
javax.servlet.ServletRequest
;
import
javax.servlet.ServletResponse
;
import
javax.servlet.http.HttpServletRequest
;
import
java.io.IOException
;
import
java.util.Objects
;
/**
* @author /
*/
public
class
TokenFilter
extends
GenericFilterBean
{
private
static
final
Logger
log
=
LoggerFactory
.
getLogger
(
TokenFilter
.
class
);
private
final
TokenProvider
tokenProvider
;
private
final
RedisUtils
redisUtils
;
private
SecurityProperties
properties
;
/**
* @param tokenProvider Token
* @param adminFeignClient admin
*/
public
TokenFilter
(
TokenProvider
tokenProvider
,
SecurityProperties
properties
,
RedisUtils
redisUtils
)
{
this
.
tokenProvider
=
tokenProvider
;
this
.
properties
=
properties
;
this
.
redisUtils
=
redisUtils
;
}
@Override
public
void
doFilter
(
ServletRequest
servletRequest
,
ServletResponse
servletResponse
,
FilterChain
filterChain
)
throws
IOException
,
ServletException
{
HttpServletRequest
httpServletRequest
=
(
HttpServletRequest
)
servletRequest
;
String
token
=
tokenProvider
.
getToken
(
httpServletRequest
);
// 对于 Token 为空的不需要去查 Redis
if
(
StrUtil
.
isNotBlank
(
token
))
{
OnlineUserDto
onlineUserDto
=
null
;
boolean
cleanUserCache
=
false
;
try
{
onlineUserDto
=
redisUtils
.
getObj
(
properties
.
getOnlineKey
()
+
token
,
OnlineUserDto
.
class
);
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
());
cleanUserCache
=
true
;
}
finally
{
if
(
cleanUserCache
||
Objects
.
isNull
(
onlineUserDto
))
{
String
username
=
String
.
valueOf
(
tokenProvider
.
getClaims
(
token
).
get
(
TokenProvider
.
AUTHORITIES_KEY
));
redisUtils
.
hdel
(
BaseCacheKeys
.
USER_DATA_MAP_KEY
,
username
);
}
}
if
(
onlineUserDto
!=
null
&&
StringUtils
.
isNotBlank
(
token
))
{
Authentication
authentication
=
tokenProvider
.
getAuthentication
(
token
);
SecurityContextHolder
.
getContext
().
setAuthentication
(
authentication
);
// 设置当前用户
ContextUtils
.
setAdminContext
(
onlineUserDto
);
}
}
filterChain
.
doFilter
(
servletRequest
,
servletResponse
);
}
}
imgproc-server/src/main/java/com/zq/imgproc/config/TokenProvider.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
config
;
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import
cn.hutool.core.date.DateField
;
import
cn.hutool.core.date.DateUtil
;
import
cn.hutool.core.util.IdUtil
;
import
cn.hutool.core.util.ObjectUtil
;
import
com.zq.common.config.redis.RedisUtils
;
import
com.zq.common.config.security.SecurityProperties
;
import
io.jsonwebtoken.Claims
;
import
io.jsonwebtoken.Jwts
;
import
io.jsonwebtoken.SignatureAlgorithm
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.InitializingBean
;
import
org.springframework.security.authentication.UsernamePasswordAuthenticationToken
;
import
org.springframework.security.core.Authentication
;
import
org.springframework.security.core.GrantedAuthority
;
import
org.springframework.security.core.authority.SimpleGrantedAuthority
;
import
org.springframework.security.core.userdetails.User
;
import
org.springframework.stereotype.Component
;
import
javax.crypto.spec.SecretKeySpec
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.xml.bind.DatatypeConverter
;
import
java.security.Key
;
import
java.util.Arrays
;
import
java.util.Collection
;
import
java.util.Collections
;
import
java.util.Date
;
import
java.util.concurrent.TimeUnit
;
import
java.util.stream.Collectors
;
/**
* @author /
*/
@Slf4j
@Component
@RequiredArgsConstructor
public
class
TokenProvider
implements
InitializingBean
{
private
final
RedisUtils
redisUtils
;
private
final
SecurityProperties
properties
;
public
static
final
String
AUTHORITIES_KEY
=
"auth"
;
private
static
Key
key
;
private
static
SignatureAlgorithm
signatureAlgorithm
;
@Override
public
void
afterPropertiesSet
()
{
signatureAlgorithm
=
SignatureAlgorithm
.
HS512
;
byte
[]
keyBytes
=
DatatypeConverter
.
parseBase64Binary
(
properties
.
getBase64Secret
());
key
=
new
SecretKeySpec
(
keyBytes
,
signatureAlgorithm
.
getJcaName
());
}
public
static
String
createToken
(
Authentication
authentication
)
{
String
authorities
=
authentication
.
getAuthorities
().
stream
()
.
map
(
GrantedAuthority:
:
getAuthority
)
.
collect
(
Collectors
.
joining
(
","
));
return
Jwts
.
builder
()
.
setSubject
(
authentication
.
getName
())
.
claim
(
AUTHORITIES_KEY
,
authorities
)
.
signWith
(
signatureAlgorithm
,
key
)
// 加入ID确保生成的 Token 都不一致
.
setId
(
IdUtil
.
simpleUUID
())
.
compact
();
}
public
Claims
getClaims
(
String
token
)
{
return
Jwts
.
parser
()
.
setSigningKey
(
DatatypeConverter
.
parseBase64Binary
(
properties
.
getBase64Secret
()))
.
parseClaimsJws
(
token
)
.
getBody
();
}
public
Authentication
getAuthentication
(
String
token
)
{
Claims
claims
=
getClaims
(
token
);
// fix bug: 当前用户如果没有任何权限时,在输入用户名后,刷新验证码会抛IllegalArgumentException
Object
authoritiesStr
=
claims
.
get
(
AUTHORITIES_KEY
);
Collection
<?
extends
GrantedAuthority
>
authorities
=
ObjectUtil
.
isNotEmpty
(
authoritiesStr
)
?
Arrays
.
stream
(
authoritiesStr
.
toString
().
split
(
","
))
.
map
(
SimpleGrantedAuthority:
:
new
)
.
collect
(
Collectors
.
toList
())
:
Collections
.
emptyList
();
User
principal
=
new
User
(
claims
.
getSubject
(),
"******"
,
authorities
);
return
new
UsernamePasswordAuthenticationToken
(
principal
,
token
,
authorities
);
}
/**
* @param token 需要检查的token
*/
public
void
checkRenewal
(
String
token
)
{
// 判断是否续期token,计算token的过期时间
long
time
=
redisUtils
.
getExpire
(
properties
.
getOnlineKey
()
+
token
)
*
1000
;
Date
expireDate
=
DateUtil
.
offset
(
new
Date
(),
DateField
.
MILLISECOND
,
(
int
)
time
);
// 判断当前时间与过期时间的时间差
long
differ
=
expireDate
.
getTime
()
-
System
.
currentTimeMillis
();
// 如果在续期检查的范围内,则续期
if
(
differ
<=
properties
.
getDetect
())
{
long
renew
=
time
+
properties
.
getRenew
();
redisUtils
.
expire
(
properties
.
getOnlineKey
()
+
token
,
renew
,
TimeUnit
.
MILLISECONDS
);
}
}
public
String
getToken
(
HttpServletRequest
request
)
{
String
bearerToken
=
request
.
getHeader
(
properties
.
getHeader
());
if
(
StringUtils
.
isBlank
(
bearerToken
))
{
return
null
;
}
if
(
bearerToken
.
startsWith
(
properties
.
getTokenStartWith
()))
{
// 去掉令牌前缀
return
bearerToken
.
replace
(
properties
.
getTokenStartWith
(),
""
);
}
else
{
log
.
debug
(
"非法Token:{}"
,
bearerToken
);
}
return
null
;
}
}
imgproc-server/src/main/java/com/zq/imgproc/constant/Threshold.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
constant
;
import
lombok.Getter
;
/**
* <p>
* 常用的阈值
* </P>
*
* @author chenhao
* @since 2023/11/26
*/
@Getter
public
enum
Threshold
{
/**
* 亮度过低阈值
*/
START_VALUE
(
"img-start"
,
75
),
/**
* 亮度过低阈值
*/
END_VALUE
(
"img-end"
,
175
),
/**
* 清晰度阈值
*/
CLARITY
(
"img-clarity"
,
2.5
),
/**
* 弯曲度阈值
*/
BEND
(
"img-clarity"
,
2.5
);
private
final
String
key
;
private
final
double
value
;
Threshold
(
String
key
,
double
value
)
{
this
.
key
=
key
;
this
.
value
=
value
;
}
}
imgproc-server/src/main/java/com/zq/imgproc/controller/ApiController.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
controller
;
import
cn.hutool.core.codec.Base64Encoder
;
import
cn.hutool.core.io.FileUtil
;
import
cn.hutool.http.HttpUtil
;
import
cn.hutool.json.JSONObject
;
import
cn.hutool.json.JSONUtil
;
import
com.zq.common.annotation.rest.AnonymousGetMapping
;
import
com.zq.common.utils.AssertUtils
;
import
com.zq.common.utils.UuidUtils
;
import
com.zq.common.vo.ResultVo
;
import
com.zq.imgproc.server.ImgProcService
;
import
com.zq.imgproc.utils.*
;
import
com.zq.imgproc.vo.DetectionVO
;
import
com.zq.imgproc.vo.OptimizationReq
;
import
com.zq.imgproc.vo.OptimizationVO
;
import
io.swagger.annotations.ApiOperation
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.multipart.MultipartFile
;
import
java.io.IOException
;
import
java.text.SimpleDateFormat
;
import
java.util.Date
;
import
java.util.HashMap
;
/**
* <p>
* 图片处理API
* </p>
*
* @author chenhao
* @since 2023/3/18 9:32
*/
@io
.
swagger
.
annotations
.
Api
(
tags
=
"图片处理API"
)
@RequestMapping
(
"/imgproc/v1"
)
@RestController
public
class
ApiController
{
@Value
(
"${imgconfig.opencv}"
)
String
opencvUrl
;
@Value
(
"${imgconfig.deskew}"
)
String
deskewUrl
;
private
final
ImgProcService
service
;
@Autowired
public
ApiController
(
ImgProcService
service
)
{
this
.
service
=
service
;
}
@ApiOperation
(
"测试"
)
@AnonymousGetMapping
(
"/ping"
)
public
ResultVo
<?>
ping
()
{
return
ResultVo
.
success
(
"测试成功"
);
}
@ApiOperation
(
"图片检测"
)
@PostMapping
(
"/detection"
)
public
ResultVo
<
DetectionVO
>
detection
(
@RequestBody
OptimizationReq
req
)
throws
Exception
{
AssertUtils
.
hasText
(
req
.
getFileContent
(),
"缺少文件内容"
);
AssertUtils
.
hasText
(
req
.
getFilename
(),
"缺少文件名"
);
return
ResultVo
.
success
(
service
.
detection2
(
req
));
}
@ApiOperation
(
"图片校正(deskew工具)"
)
@PostMapping
(
"/imageCorrection"
)
public
ResultVo
<?>
imageCorrection
(
@RequestPart
MultipartFile
file
)
{
if
(
file
.
isEmpty
())
{
return
ResultVo
.
fail
(
"文件不能为空"
);
}
String
imgPath
=
UploadUtils
.
saveTempFile
(
file
,
"api"
);
String
ext
=
FileUtil
.
extName
(
file
.
getOriginalFilename
());
String
yyyyMMdd
=
new
SimpleDateFormat
(
"/yyyyMM/dd/"
).
format
(
new
Date
());
String
savePath
=
"/file/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
"."
+
ext
;
// 图片矫正
ImageCorrectionUtil
.
deskew
(
imgPath
,
savePath
,
deskewUrl
,
false
);
return
ResultVo
.
success
(
Base64Encoder
.
encode
(
FileUtil
.
readBytes
(
savePath
)));
}
@ApiOperation
(
"去黑边"
)
@PostMapping
(
"/removeBlack"
)
public
ResultVo
<?>
removeBlack
(
@RequestPart
MultipartFile
file
)
{
if
(
file
.
isEmpty
())
{
return
ResultVo
.
fail
(
"文件不能为空"
);
}
System
.
load
(
opencvUrl
);
String
imgPath
=
UploadUtils
.
saveTempFile
(
file
,
"api"
);
String
ext
=
FileUtil
.
extName
(
file
.
getOriginalFilename
());
String
yyyyMMdd
=
new
SimpleDateFormat
(
"/yyyyMM/dd/"
).
format
(
new
Date
());
String
savePath
=
"/file/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
"."
+
ext
;
// 去黑边
RemoveBlackUtil2
.
remove
(
imgPath
,
savePath
);
return
ResultVo
.
success
(
Base64Encoder
.
encode
(
savePath
));
}
@ApiOperation
(
"图片灰度化"
)
@PostMapping
(
"/gray"
)
public
ResultVo
<?>
gray
(
@RequestPart
MultipartFile
file
)
{
if
(
file
.
isEmpty
())
{
return
ResultVo
.
fail
(
"文件不能为空"
);
}
System
.
load
(
opencvUrl
);
String
imgPath
=
UploadUtils
.
saveTempFile
(
file
,
"api"
);
String
ext
=
FileUtil
.
extName
(
file
.
getOriginalFilename
());
String
yyyyMMdd
=
new
SimpleDateFormat
(
"/yyyyMM/dd/"
).
format
(
new
Date
());
String
savePath
=
"/file/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
"."
+
ext
;
// 灰度化
ImageUtil
.
gray
(
imgPath
,
savePath
);
return
ResultVo
.
success
(
Base64Encoder
.
encode
(
FileUtil
.
readBytes
(
savePath
)));
}
@ApiOperation
(
"图片边缘检测"
)
@PostMapping
(
"/canny"
)
public
ResultVo
<?>
canny
(
@RequestPart
MultipartFile
file
)
{
if
(
file
.
isEmpty
())
{
return
ResultVo
.
fail
(
"文件不能为空"
);
}
System
.
load
(
opencvUrl
);
String
imgPath
=
UploadUtils
.
saveTempFile
(
file
,
"api"
);
String
ext
=
FileUtil
.
extName
(
file
.
getOriginalFilename
());
String
yyyyMMdd
=
new
SimpleDateFormat
(
"/yyyyMM/dd/"
).
format
(
new
Date
());
String
savePath
=
"/file/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
"."
+
ext
;
// 边缘检测
ImageUtil
.
canny
(
imgPath
,
savePath
);
return
ResultVo
.
success
(
Base64Encoder
.
encode
(
FileUtil
.
readBytes
(
savePath
)));
}
@ApiOperation
(
"图片弯曲矫正"
)
@PostMapping
(
"/correct"
)
public
ResultVo
<?>
correct
(
@RequestPart
MultipartFile
file
)
{
if
(
file
.
isEmpty
())
{
return
ResultVo
.
fail
(
"文件不能为空"
);
}
String
imgPath
=
UploadUtils
.
saveTempFile
(
file
,
"api"
);
// 图片弯曲矫正
HashMap
<
String
,
Object
>
map
=
new
HashMap
<>();
map
.
put
(
"file"
,
FileUtil
.
file
(
imgPath
));
String
response
=
HttpUtil
.
post
(
"http://ddns.gxmailu.com:18888/api/correct"
,
map
);
JSONObject
res
=
JSONUtil
.
parseObj
(
response
);
if
(
res
.
get
(
"success"
,
Boolean
.
class
))
{
String
base64
=
res
.
get
(
"data"
,
String
.
class
);
return
ResultVo
.
success
(
base64
);
}
else
{
return
ResultVo
.
fail
(
res
.
get
(
"msg"
,
String
.
class
));
}
}
@ApiOperation
(
"图片优化"
)
@PostMapping
(
"/imageOptimization"
)
public
ResultVo
<
OptimizationVO
>
imageOptimization
(
@RequestBody
OptimizationReq
req
)
throws
IOException
{
AssertUtils
.
hasText
(
req
.
getFileContent
(),
"缺少文件内容"
);
AssertUtils
.
hasText
(
req
.
getFilename
(),
"缺少文件名"
);
return
ResultVo
.
success
(
service
.
optimization
(
req
));
}
}
imgproc-server/src/main/java/com/zq/imgproc/controller/ImageDetectionController.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
controller
;
import
com.zq.common.utils.AssertUtils
;
import
com.zq.common.vo.PageVo
;
import
com.zq.common.vo.ResultVo
;
import
com.zq.imgproc.entity.ImageDetection
;
import
com.zq.imgproc.server.ImageDetectionService
;
import
com.zq.imgproc.vo.DetectionPageReq
;
import
io.swagger.annotations.ApiOperation
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.multipart.MultipartFile
;
/**
* <p>
* 前端控制器
* </p>
*
* @author chenhao
* @since 2023/11/28
*/
@RequestMapping
(
"/imgproc/detection"
)
@RestController
public
class
ImageDetectionController
{
@Autowired
ImageDetectionService
service
;
@ApiOperation
(
"分页查询"
)
@PostMapping
(
"/selectPage"
)
public
ResultVo
<
PageVo
<
ImageDetection
>>
selectPage
(
@RequestBody
DetectionPageReq
req
)
{
return
ResultVo
.
success
(
service
.
selectPage
(
req
));
}
@ApiOperation
(
"根据ID查询记录"
)
@GetMapping
(
"/selectOne/{id}"
)
public
ResultVo
<
ImageDetection
>
selectOne
(
@PathVariable
Long
id
)
{
AssertUtils
.
notNull
(
id
,
"数据ID不能为空!"
);
return
ResultVo
.
success
(
service
.
selectOne
(
id
));
}
@ApiOperation
(
"文件解压"
)
@PostMapping
(
"/upload"
)
public
ResultVo
<?>
upload
(
@RequestParam
Long
userId
,
@RequestParam
String
nickName
,
@RequestPart
MultipartFile
[]
file
)
throws
Exception
{
AssertUtils
.
notNull
(
userId
,
"用户ID不能为空!"
);
return
service
.
detection
(
userId
,
nickName
,
file
);
}
}
imgproc-server/src/main/java/com/zq/imgproc/controller/ImgProcController.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
controller
;
import
cn.hutool.core.io.FileUtil
;
import
cn.hutool.extra.servlet.ServletUtil
;
import
com.google.common.cache.Cache
;
import
com.google.common.cache.CacheBuilder
;
import
com.zq.common.utils.AssertUtils
;
import
com.zq.common.vo.ResultVo
;
import
com.zq.imgproc.server.ImgProcService
;
import
com.zq.imgproc.utils.DecompressUtil
;
import
com.zq.imgproc.utils.ImageUtil
;
import
com.zq.imgproc.vo.*
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiOperation
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.core.io.Resource
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.multipart.MultipartFile
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.InputStream
;
import
java.nio.charset.StandardCharsets
;
import
java.time.Duration
;
import
java.util.List
;
/**
* <p>
* 图片检测接口
* </p>
*
* @author chenhao
* @since 2022/10/24 14:58
*/
@Api
(
tags
=
"图片检测接口"
)
@RequestMapping
(
"/imgproc/server"
)
@RestController
public
class
ImgProcController
{
/**
* 普通的缓存 Cache
*/
private
final
Cache
<
String
,
Double
>
cache
=
CacheBuilder
.
newBuilder
()
.
expireAfterAccess
(
Duration
.
ofMinutes
(
30
))
.
expireAfterWrite
(
Duration
.
ofHours
(
48
))
.
maximumSize
(
1024
)
.
concurrencyLevel
(
4
)
.
initialCapacity
(
1024
)
.
build
();
private
final
ImgProcService
service
;
@Autowired
public
ImgProcController
(
ImgProcService
service
)
{
this
.
service
=
service
;
}
@ApiOperation
(
"图片检测"
)
@PostMapping
(
"/detection"
)
public
ResultVo
<
DetectionResVo
>
detection
(
@RequestPart
MultipartFile
file
)
throws
Exception
{
AssertUtils
.
notNull
(
file
,
"图片不能为空"
);
return
ResultVo
.
success
(
service
.
detection
(
file
));
}
@ApiOperation
(
"文件压缩(zip)"
)
@PostMapping
(
"/compressZip"
)
public
void
compressZip
(
@RequestBody
CompressReq
req
,
HttpServletResponse
response
)
{
String
path
=
DecompressUtil
.
compress
(
req
.
getPathList
());
InputStream
inputStream
=
FileUtil
.
getInputStream
(
path
);
String
name
=
new
String
(
req
.
getName
().
getBytes
(),
StandardCharsets
.
ISO_8859_1
);
ServletUtil
.
write
(
response
,
inputStream
,
"application/octet-stream;charset=utf-8"
,
name
);
}
@ApiOperation
(
"图片检测"
)
@PostMapping
(
"/detectionByPath"
)
public
ResultVo
<?>
detection
(
@RequestBody
List
<
ImgVO
>
pathList
)
throws
Exception
{
if
(
pathList
.
isEmpty
())
{
return
ResultVo
.
success
();
}
return
ResultVo
.
success
(
service
.
detection
(
pathList
));
}
@ApiOperation
(
"导出检测结果"
)
@PostMapping
(
"/getDetection"
)
public
ResponseEntity
<
Resource
>
getDetection
(
@RequestBody
List
<
ImgVO
>
pathList
)
throws
Exception
{
return
service
.
getDetection
(
pathList
);
}
@ApiOperation
(
"图片校正(deskew工具)"
)
@PostMapping
(
"/imageCorrection"
)
public
ResultVo
<?>
imageCorrection
(
@RequestBody
List
<
ImgVO
>
pathList
)
{
if
(
pathList
.
isEmpty
())
{
return
ResultVo
.
success
();
}
return
ResultVo
.
success
(
service
.
deskew
(
pathList
));
}
@ApiOperation
(
"去黑边"
)
@PostMapping
(
"/removeBlack"
)
public
ResultVo
<?>
removeBlack
(
@RequestBody
List
<
ImgVO
>
pathList
)
{
if
(
pathList
.
isEmpty
())
{
return
ResultVo
.
success
();
}
return
ResultVo
.
success
(
service
.
removeBlack
(
pathList
));
}
@ApiOperation
(
"图片旋转"
)
@PostMapping
(
"/rotate"
)
public
ResultVo
<?>
rotate
(
@RequestBody
RotateReq
req
)
{
if
(
req
==
null
)
{
return
ResultVo
.
success
();
}
return
ResultVo
.
success
(
service
.
rotate
(
req
));
}
@ApiOperation
(
"图片灰度化"
)
@PostMapping
(
"/gray"
)
public
ResultVo
<?>
rotate
(
@RequestBody
List
<
ImgVO
>
pathList
)
{
if
(
pathList
.
isEmpty
())
{
return
ResultVo
.
success
();
}
return
ResultVo
.
success
(
service
.
gray
(
pathList
));
}
@ApiOperation
(
"图片边缘检测"
)
@PostMapping
(
"/canny"
)
public
ResultVo
<?>
canny
(
@RequestBody
List
<
ImgVO
>
pathList
)
{
if
(
pathList
.
isEmpty
())
{
return
ResultVo
.
success
();
}
return
ResultVo
.
success
(
service
.
canny
(
pathList
));
}
@ApiOperation
(
"图片上传"
)
@PostMapping
(
"/upload"
)
public
ResultVo
<?>
upload
(
@RequestPart
MultipartFile
file
)
{
if
(
file
.
isEmpty
())
{
return
ResultVo
.
fail
(
"文件不能为空"
);
}
return
ResultVo
.
success
(
ImageUtil
.
saveTempFile
(
file
));
}
@ApiOperation
(
"识别红色"
)
@PostMapping
(
"/recognizeRed"
)
public
ResultVo
<
Boolean
>
recognizeRed
(
@RequestBody
OptimizationReq
req
)
{
ResultVo
<
Boolean
>
resultVo
;
try
{
resultVo
=
ResultVo
.
success
(
service
.
recognizeRed
(
req
));
}
catch
(
Exception
e
)
{
resultVo
=
ResultVo
.
success
(
false
);
}
return
resultVo
;
}
@ApiOperation
(
"去除红色"
)
@PostMapping
(
"/removeRed"
)
public
ResultVo
<?>
removeRed
(
@RequestBody
OptimizationReq
req
)
{
ResultVo
<?>
resultVo
;
try
{
resultVo
=
ResultVo
.
success
(
service
.
removeRed
(
req
));
}
catch
(
Exception
e
)
{
resultVo
=
ResultVo
.
fail
(
"处理失败"
);
}
return
resultVo
;
}
}
imgproc-server/src/main/java/com/zq/imgproc/controller/ImgSettingController.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
controller
;
import
cn.hutool.core.date.DateUtil
;
import
com.baomidou.mybatisplus.core.toolkit.Wrappers
;
import
com.zq.common.vo.ResultVo
;
import
com.zq.imgproc.dao.ImgSettingDao
;
import
com.zq.imgproc.entity.ImgSetting
;
import
io.swagger.annotations.ApiOperation
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.*
;
/**
* <p>
*
* </p>
*
* @author chenhao
* @since 2023/11/28
*/
@io
.
swagger
.
annotations
.
Api
(
tags
=
"图片指标"
)
@RequestMapping
(
"/imgproc/setting"
)
@RestController
public
class
ImgSettingController
{
@Autowired
ImgSettingDao
imgSettingDao
;
@ApiOperation
(
"根据用户ID获取指标"
)
@GetMapping
(
"/getSetting/{userId}"
)
public
ResultVo
<?>
getSetting
(
@PathVariable
long
userId
)
{
return
ResultVo
.
success
(
imgSettingDao
.
selectOne
(
Wrappers
.
lambdaQuery
(
ImgSetting
.
builder
().
userId
(
userId
).
build
()))
);
}
@ApiOperation
(
"设置或更新图片指标"
)
@PostMapping
(
"/setSetting"
)
public
ResultVo
<?>
setSetting
(
@RequestBody
ImgSetting
imgSetting
)
{
if
(
imgSetting
.
getUserId
()
==
null
||
imgSetting
.
getUserId
()
<
0
)
{
return
ResultVo
.
fail
(
"用户ID不能为空!"
);
}
if
(
imgSetting
.
getBrightnessStart
()
!=
null
)
{
if
(
imgSetting
.
getBrightnessStart
()
<
0
||
imgSetting
.
getBrightnessStart
()
>
255
)
{
return
ResultVo
.
fail
(
"亮度值的范围在0到255之间!"
);
}
}
if
(
imgSetting
.
getBrightnessEnd
()
!=
null
)
{
if
(
imgSetting
.
getBrightnessEnd
()
<
0
||
imgSetting
.
getBrightnessEnd
()
>
255
)
{
return
ResultVo
.
fail
(
"亮度值的范围在0到255之间!"
);
}
}
if
(
imgSetting
.
getBend
()
!=
null
)
{
if
(
imgSetting
.
getBend
()
<
0
||
imgSetting
.
getBend
()
>
1
)
{
return
ResultVo
.
fail
(
"弯曲置信度的范围在0到1之间!"
);
}
}
if
(
imgSetting
.
getId
()
==
null
)
{
imgSetting
.
setCreateTime
(
DateUtil
.
date
());
imgSetting
.
setUpdateTime
(
DateUtil
.
date
());
imgSettingDao
.
insert
(
imgSetting
);
}
else
{
imgSettingDao
.
updateById
(
imgSetting
);
}
return
ResultVo
.
success
(
imgSetting
);
}
}
imgproc-server/src/main/java/com/zq/imgproc/dao/ImageDetectionDao.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
dao
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
import
com.baomidou.mybatisplus.extension.plugins.pagination.Page
;
import
com.zq.imgproc.entity.ImageDetection
;
import
com.zq.imgproc.vo.DetectionPageReq
;
import
org.apache.ibatis.annotations.Param
;
import
org.springframework.stereotype.Repository
;
import
java.util.List
;
/**
* <p>
*
* </p>
*
* @author chenhao
* @since 2023/11/28
*/
@Repository
public
interface
ImageDetectionDao
extends
BaseMapper
<
ImageDetection
>
{
Page
<
ImageDetection
>
queryPageList
(
Page
<
ImageDetection
>
page
,
@Param
(
"req"
)
DetectionPageReq
req
);
/**
* 批量插入
*/
Integer
insertBatch
(
List
<
ImageDetection
>
list
);
}
imgproc-server/src/main/java/com/zq/imgproc/dao/ImgSettingDao.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
dao
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
import
com.zq.imgproc.entity.ImgSetting
;
import
org.springframework.stereotype.Repository
;
/**
* <p>
*
* </p>
*
* @author chenhao
* @since 2023/11/28
*/
@Repository
public
interface
ImgSettingDao
extends
BaseMapper
<
ImgSetting
>
{
}
imgproc-server/src/main/java/com/zq/imgproc/entity/ImageDetection.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
entity
;
import
com.baomidou.mybatisplus.annotation.IdType
;
import
com.baomidou.mybatisplus.annotation.TableField
;
import
com.baomidou.mybatisplus.annotation.TableId
;
import
com.baomidou.mybatisplus.annotation.TableName
;
import
com.fasterxml.jackson.annotation.JsonFormat
;
import
io.swagger.annotations.ApiModelProperty
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.io.Serializable
;
import
java.util.Date
;
/**
* <p>
*
* </p>
*
* @author chenhao
* @since 2023-11-28
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@TableName
(
"image_detection"
)
public
class
ImageDetection
implements
Serializable
{
private
static
final
long
serialVersionUID
=
1L
;
@ApiModelProperty
(
"数据ID"
)
@TableId
(
value
=
"id"
,
type
=
IdType
.
AUTO
)
private
Long
id
;
@ApiModelProperty
(
"用户ID"
)
@TableField
(
"user_id"
)
private
Long
userId
;
@ApiModelProperty
(
"用户名称"
)
@TableField
(
"nick_name"
)
private
String
nickName
;
@ApiModelProperty
(
"图片名称"
)
@TableField
(
"img_name"
)
private
String
imgName
;
@ApiModelProperty
(
"文件名称"
)
@TableField
(
"file_name"
)
private
String
fileName
;
@ApiModelProperty
(
"文件路径"
)
@TableField
(
"file_url"
)
private
String
fileUrl
;
@ApiModelProperty
(
"图片大小"
)
@TableField
(
"size"
)
private
Double
size
;
@ApiModelProperty
(
"水平分辨率"
)
@TableField
(
"width_resolution"
)
private
Integer
widthResolution
;
@ApiModelProperty
(
"垂直分辨率"
)
@TableField
(
"height_resolution"
)
private
Integer
heightResolution
;
@ApiModelProperty
(
"DPI"
)
@TableField
(
"dpi"
)
private
Integer
dpi
;
@ApiModelProperty
(
"图片清晰度"
)
@TableField
(
"clarity"
)
private
Double
clarity
;
@ApiModelProperty
(
"图片弯曲置信度"
)
@TableField
(
"bend"
)
private
Double
bend
;
@ApiModelProperty
(
"图片亮度起始范围"
)
@TableField
(
"brightness"
)
private
Integer
brightness
;
@ApiModelProperty
(
"图片偏离角度"
)
@TableField
(
"deskew_angel"
)
private
Integer
deskewAngel
;
@ApiModelProperty
(
"图片黑边数量"
)
@TableField
(
"black"
)
private
Integer
black
;
@ApiModelProperty
(
"是否合格,0不合格,1合格"
)
@TableField
(
"qualified"
)
private
Integer
qualified
;
@ApiModelProperty
(
"上传时间"
)
@JsonFormat
(
pattern
=
"yyyy-MM-dd HH:mm:ss"
,
timezone
=
"GMT+8"
)
private
Date
uploadTime
;
}
imgproc-server/src/main/java/com/zq/imgproc/entity/ImgSetting.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
entity
;
import
com.baomidou.mybatisplus.annotation.IdType
;
import
com.baomidou.mybatisplus.annotation.TableField
;
import
com.baomidou.mybatisplus.annotation.TableId
;
import
com.baomidou.mybatisplus.annotation.TableName
;
import
com.fasterxml.jackson.annotation.JsonFormat
;
import
io.swagger.annotations.ApiModelProperty
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.io.Serializable
;
import
java.util.Date
;
/**
* <p>
*
* </p>
*
* @author chenhao
* @since 2023/11/28
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@TableName
(
value
=
"img_setting"
)
public
class
ImgSetting
implements
Serializable
{
private
static
final
long
serialVersionUID
=
1L
;
@ApiModelProperty
(
"数据ID"
)
@TableId
(
value
=
"id"
,
type
=
IdType
.
AUTO
)
private
Long
id
;
@ApiModelProperty
(
"用户ID"
)
@TableField
(
"user_id"
)
private
Long
userId
;
@ApiModelProperty
(
"图片大小"
)
@TableField
(
"size"
)
private
Integer
size
;
@ApiModelProperty
(
"是否启用,0是禁用,1是启用"
)
@TableField
(
"size_enabled"
)
private
Integer
sizeEnabled
;
@ApiModelProperty
(
"图片DPI"
)
@TableField
(
"dpi"
)
private
Integer
dpi
;
@ApiModelProperty
(
"是否启用,0是禁用,1是启用"
)
@TableField
(
"dpi_enabled"
)
private
Integer
dpiEnabled
;
@ApiModelProperty
(
"图片清晰度"
)
@TableField
(
"clarity"
)
private
Double
clarity
;
@ApiModelProperty
(
"是否启用,0是禁用,1是启用"
)
@TableField
(
"clarity_enabled"
)
private
Integer
clarityEnabled
;
@ApiModelProperty
(
"图片亮度起始范围"
)
@TableField
(
"brightness_start"
)
private
Integer
brightnessStart
;
@ApiModelProperty
(
"图片亮度结束范围"
)
@TableField
(
"brightness_end"
)
private
Integer
brightnessEnd
;
@ApiModelProperty
(
"是否启用,0是禁用,1是启用"
)
@TableField
(
"brightness_enabled"
)
private
Integer
brightnessEnabled
;
@ApiModelProperty
(
"图片偏离角度"
)
@TableField
(
"deskew_angel"
)
private
Integer
deskewAngel
;
@ApiModelProperty
(
"是否启用,0是禁用,1是启用"
)
@TableField
(
"deskew_enabled"
)
private
Integer
deskewEnabled
;
@ApiModelProperty
(
"图片水平分辨率"
)
@TableField
(
"width_resolution"
)
private
Integer
widthResolution
;
@ApiModelProperty
(
"图片垂直分辨率"
)
@TableField
(
"height_resolution"
)
private
Integer
heightResolution
;
@ApiModelProperty
(
"是否启用,0是禁用,1是启用"
)
@TableField
(
"resolution_enabled"
)
private
Integer
resolutionEnabled
;
@ApiModelProperty
(
"黑边的数值"
)
@TableField
(
"black"
)
private
Integer
black
;
@ApiModelProperty
(
"是否启用,0是禁用,1是启用"
)
@TableField
(
"black_enabled"
)
private
Integer
blackEnabled
;
@ApiModelProperty
(
"弯曲的置信度"
)
@TableField
(
"bend"
)
private
Double
bend
;
@ApiModelProperty
(
"是否启用,0是禁用,1是启用"
)
@TableField
(
"bend_enabled"
)
private
Integer
bendEnabled
;
@JsonFormat
(
pattern
=
"yyyy-MM-dd HH:mm:ss"
,
timezone
=
"GMT+8"
)
private
Date
updateTime
;
@JsonFormat
(
pattern
=
"yyyy-MM-dd HH:mm:ss"
,
timezone
=
"GMT+8"
)
private
Date
createTime
;
}
imgproc-server/src/main/java/com/zq/imgproc/server/ImageDetectionService.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
server
;
import
cn.hutool.core.convert.Convert
;
import
cn.hutool.core.date.DateUtil
;
import
cn.hutool.core.io.FileUtil
;
import
com.baomidou.mybatisplus.core.toolkit.Wrappers
;
import
com.baomidou.mybatisplus.extension.plugins.pagination.Page
;
import
com.zq.common.utils.AssertUtils
;
import
com.zq.common.vo.PageVo
;
import
com.zq.common.vo.ResultVo
;
import
com.zq.imgproc.dao.ImageDetectionDao
;
import
com.zq.imgproc.dao.ImgSettingDao
;
import
com.zq.imgproc.entity.ImageDetection
;
import
com.zq.imgproc.entity.ImgSetting
;
import
com.zq.imgproc.utils.DecompressUtil
;
import
com.zq.imgproc.utils.Deskew
;
import
com.zq.imgproc.utils.ImageUtil
;
import
com.zq.imgproc.vo.DetectionPageReq
;
import
com.zq.imgproc.vo.ImgVO
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.opencv.core.Mat
;
import
org.opencv.imgcodecs.Imgcodecs
;
import
org.springframework.stereotype.Service
;
import
org.springframework.web.multipart.MultipartFile
;
import
java.io.File
;
import
java.math.BigDecimal
;
import
java.math.RoundingMode
;
import
java.util.ArrayList
;
import
java.util.List
;
/**
* <p>
*
* </p>
*
* @author chenhao
* @since 2023/11/28
*/
@Slf4j
@RequiredArgsConstructor
@Service
public
class
ImageDetectionService
{
private
final
ImgSettingDao
imgSettingDao
;
private
final
ImageDetectionDao
imageDetectionDao
;
public
ResultVo
<?>
detection
(
long
userId
,
String
nickName
,
MultipartFile
[]
file
)
throws
Exception
{
// 查询用户配置
ImgSetting
imgSetting
=
imgSettingDao
.
selectOne
(
Wrappers
.
lambdaQuery
(
ImgSetting
.
builder
().
userId
(
userId
).
build
())
);
if
(
imgSetting
==
null
)
{
return
ResultVo
.
fail
(
"查询不到用户的配置信息!"
);
}
// 解压文件
List
<
ImgVO
>
imgs
=
new
ArrayList
<>();
for
(
MultipartFile
one
:
file
)
{
if
(
DecompressUtil
.
isCompress
(
one
))
{
String
path
=
DecompressUtil
.
decompress
(
one
);
AssertUtils
.
hasText
(
path
,
"解压失败!"
);
imgs
.
addAll
(
DecompressUtil
.
loopFiles
(
path
,
one
.
getOriginalFilename
()));
}
else
{
String
url
=
ImageUtil
.
saveTempFile
(
one
);
imgs
.
add
(
ImgVO
.
builder
().
fileName
(
one
.
getOriginalFilename
()).
name
(
one
.
getOriginalFilename
()).
url
(
url
).
build
());
}
}
// 保存上传信息
List
<
ImageDetection
>
detections
=
new
ArrayList
<>();
File
image
;
for
(
ImgVO
img
:
imgs
)
{
image
=
FileUtil
.
file
(
img
.
getUrl
());
if
(!
image
.
exists
())
{
continue
;
}
// 图片检测
ImageDetection
detection
=
new
ImageDetection
();
// 设置上传信息
detection
.
setUserId
(
userId
);
detection
.
setNickName
(
nickName
);
detection
.
setUploadTime
(
DateUtil
.
date
());
// 设置文件信息
detection
.
setFileName
(
img
.
getName
());
detection
.
setImgName
(
img
.
getFileName
());
detection
.
setFileUrl
(
img
.
getUrl
());
detection
.
setSize
(
transformMb
(
image
.
length
()));
// 设置图片检测信息
Mat
src
=
Imgcodecs
.
imread
(
img
.
getUrl
());
// 检测图片的分辨率
detection
.
setWidthResolution
(
src
.
width
());
detection
.
setHeightResolution
(
src
.
height
());
// 检测图片的DPI
detection
.
setDpi
(
ImageUtil
.
getDpi
(
image
));
// 检测图片清晰度
BigDecimal
clarity
=
BigDecimal
.
valueOf
(
ImageUtil
.
tenengrad
(
src
));
detection
.
setClarity
(
clarity
.
setScale
(
2
,
RoundingMode
.
HALF_UP
).
doubleValue
());
// 检测图片的亮度
detection
.
setBrightness
(
Convert
.
toInt
(
ImageUtil
.
brightness
(
src
)));
// 检测图片倾斜角度
detection
.
setDeskewAngel
(
Math
.
abs
(
Deskew
.
getDeskewAngle
(
src
)));
// 检测图片的黑边
detection
.
setBlack
(
ImageUtil
.
blackDetection2
(
src
));
// 图片弯曲检测
// BendResult bendResult = BendUtil.getBendResult(img.getUrl());
// detection.setBend(bendResult.getConfidence());
detection
.
setBend
(
0.0
);
// 检查是否合格
detection
.
setQualified
(
check
(
detection
,
imgSetting
));
detections
.
add
(
detection
);
}
// 批量插入
imageDetectionDao
.
insertBatch
(
detections
);
return
ResultVo
.
success
(
detections
);
}
/**
* 检查图片是否合格
* 1. 亮度
* 2. 清晰度
* 3. 偏离度
* 4. 黑边
* 5. 弯曲
*/
private
Integer
check
(
ImageDetection
detection
,
ImgSetting
imgSetting
)
{
// 亮度
if
(
detection
.
getBrightness
()
<
imgSetting
.
getBrightnessStart
()
||
detection
.
getBrightness
()
>
imgSetting
.
getBrightnessEnd
())
{
return
0
;
}
// 清晰度
if
(
detection
.
getClarity
().
compareTo
(
imgSetting
.
getClarity
())
<
0
)
{
return
0
;
}
// 偏离度
if
(
detection
.
getDeskewAngel
()
>
imgSetting
.
getDeskewAngel
())
{
return
0
;
}
// 黑边
if
(
detection
.
getBlack
()
>
imgSetting
.
getBlack
())
{
return
0
;
}
// 弯曲度
if
(
detection
.
getBend
().
compareTo
(
imgSetting
.
getBend
())
>
0
)
{
return
0
;
}
return
1
;
}
/**
* 将字节数转换为MB
*/
private
double
transformMb
(
long
size
)
{
BigDecimal
sizeDecimal
=
BigDecimal
.
valueOf
(
size
);
BigDecimal
mb
=
BigDecimal
.
valueOf
(
1024
*
1024
);
return
sizeDecimal
.
divide
(
mb
,
2
,
RoundingMode
.
DOWN
).
doubleValue
();
}
public
PageVo
<
ImageDetection
>
selectPage
(
DetectionPageReq
req
)
{
Page
<
ImageDetection
>
ipage
=
Page
.
of
(
req
.
getPage
(),
req
.
getSize
());
imageDetectionDao
.
queryPageList
(
ipage
,
req
);
return
PageVo
.
ofReqVo
(
req
,
ipage
.
getRecords
(),
Convert
.
toInt
(
ipage
.
getTotal
()));
}
public
ImageDetection
selectOne
(
Long
id
)
{
return
imageDetectionDao
.
selectById
(
id
);
}
}
imgproc-server/src/main/java/com/zq/imgproc/server/ImgProcService.java
0 → 100644
View file @
003b7634
This diff is collapsed.
Click to expand it.
imgproc-server/src/main/java/com/zq/imgproc/utils/BendUtil.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
utils
;
import
cn.hutool.core.convert.Convert
;
import
cn.hutool.core.io.FileUtil
;
import
cn.hutool.http.HttpUtil
;
import
cn.hutool.json.JSONObject
;
import
cn.hutool.json.JSONUtil
;
import
com.zq.common.vo.ResultVo
;
import
com.zq.imgproc.vo.BendResult
;
import
lombok.extern.slf4j.Slf4j
;
import
java.util.HashMap
;
import
java.util.List
;
/**
* <p>
* 弯曲度检测
* </P>
*
* @author yww
* @since 2023/11/26
*/
@Slf4j
public
class
BendUtil
{
private
final
static
String
URL
=
"http://129.204.37.121:8001/api/det/bending"
;
private
final
static
String
WANPRO_URL
=
"http://172.28.1.223:8030/api/det/bending"
;
private
final
static
String
URL2
=
"http://147.1.3.244:8030/api/det/bending"
;
public
static
void
main
(
String
[]
args
)
{
System
.
out
.
println
(
getBendResult
(
"C:\\Users\\11419\\Desktop\\project\\company\\test\\9.png"
).
toString
());
}
public
static
BendResult
getBendResult
(
String
imgPath
)
{
// 设定参数
HashMap
<
String
,
Object
>
param
=
new
HashMap
<>();
param
.
put
(
"file"
,
FileUtil
.
file
(
imgPath
));
BendResult
res
=
null
;
try
{
String
result
=
HttpUtil
.
post
(
URL2
,
param
,
1000
*
20
);
res
=
parseResult
(
result
);
}
catch
(
Exception
e
)
{
log
.
error
(
"图片弯曲检测失败!"
,
e
);
}
if
(
res
==
null
)
{
res
=
BendResult
.
builder
().
confidence
(
0.0
).
build
();
}
return
res
;
}
/**
* 解析弯曲检测结果
*/
public
static
BendResult
parseResult
(
String
resultJson
)
{
BendResult
result
=
null
;
ResultVo
resultVo
=
JSONUtil
.
toBean
(
resultJson
,
ResultVo
.
class
);
if
(!
resultVo
.
isSuccess
())
{
log
.
warn
(
"弯曲度检测出错: {}"
,
resultVo
.
getErrMsg
());
return
null
;
}
JSONObject
results
=
JSONUtil
.
parseObj
(
Convert
.
toStr
(
resultVo
.
getData
()));
List
<
BendResult
>
bendResults
=
JSONUtil
.
toList
(
results
.
getStr
(
"results"
),
BendResult
.
class
);
if
(
bendResults
==
null
||
bendResults
.
isEmpty
())
{
return
null
;
}
double
max
=
-
1
;
for
(
BendResult
bendResult
:
bendResults
)
{
if
(
bendResult
.
getConfidence
()
==
null
)
{
continue
;
}
if
(
bendResult
.
getConfidence
()
>
max
)
{
result
=
bendResult
;
max
=
bendResult
.
getConfidence
();
}
}
return
result
;
}
}
imgproc-server/src/main/java/com/zq/imgproc/utils/DecompressUtil.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
utils
;
import
cn.hutool.core.io.FileUtil
;
import
cn.hutool.core.util.CharsetUtil
;
import
cn.hutool.core.util.StrUtil
;
import
cn.hutool.core.util.ZipUtil
;
import
cn.hutool.extra.compress.CompressUtil
;
import
cn.hutool.extra.compress.extractor.Extractor
;
import
cn.hutool.http.HttpUtil
;
import
com.zq.common.utils.UuidUtils
;
import
com.zq.imgproc.vo.ImgVO
;
import
org.apache.commons.compress.archivers.ArchiveStreamFactory
;
import
org.apache.commons.io.FileUtils
;
import
org.springframework.web.multipart.MultipartFile
;
import
java.io.File
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.nio.charset.Charset
;
import
java.nio.file.StandardCopyOption
;
import
java.text.SimpleDateFormat
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Date
;
import
java.util.List
;
/**
* <p>
*
* </p>
*
* @author chenhao
* @since 2023/3/7 14:29
*/
public
class
DecompressUtil
{
private
static
final
String
[]
IMG_EXTS
=
{
"png"
,
"jpg"
,
"jpeg"
,
"tif"
,
"bmp"
,
"heic"
};
private
static
final
String
[]
COMPRESS_EXTS
=
{
"zip"
,
"7z"
};
/**
* 压缩包解压
*
* @param file 压缩包文件
* @return 保存的文件夹路径
* @throws IOException IO异常
*/
public
static
String
decompress
(
MultipartFile
file
)
throws
IOException
{
String
ext
=
FileUtil
.
extName
(
file
.
getOriginalFilename
());
if
(
"7z"
.
equals
(
ext
))
{
return
decompress7z
(
file
);
}
else
if
(
"zip"
.
equals
(
ext
))
{
return
decompressZip
(
file
);
}
else
{
return
""
;
}
}
/**
* 7z压缩包解压
* @param file 压缩包文件
* @return 保存的文件夹路径
* @throws IOException IO异常
*/
public
static
String
decompress7z
(
MultipartFile
file
)
throws
IOException
{
// 文件路径要素
String
yyyyMMdd
=
new
SimpleDateFormat
(
"/yyyyMM/dd/"
).
format
(
new
Date
());
String
filePath
=
"/file/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
"/"
;
// 解压文件
InputStream
inputStream
=
file
.
getInputStream
();
Extractor
extractor
=
CompressUtil
.
createExtractor
(
CharsetUtil
.
defaultCharset
(),
ArchiveStreamFactory
.
SEVEN_Z
,
inputStream
);
extractor
.
extract
(
FileUtil
.
file
(
filePath
));
extractor
.
close
();
filePath
=
filePath
+
"/"
;
return
filePath
;
}
/**
* zip压缩包解压
* @param file 压缩包文件
* @return 保存的文件夹路径
* @throws IOException IO异常
*/
public
static
String
decompressZip
(
MultipartFile
file
)
throws
IOException
{
String
yyyyMMdd
=
new
SimpleDateFormat
(
"/yyyyMM/dd/"
).
format
(
new
Date
());
String
filePath
=
"/file/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
"/"
;
ZipUtil
.
unzip
(
file
.
getInputStream
(),
FileUtil
.
file
(
filePath
),
Charset
.
forName
(
"GBK"
));
filePath
=
filePath
+
"/"
;
return
filePath
;
}
/**
* 文件压缩成zip
*
* @param list 图片文件
* @return zip压缩文件
*/
public
static
String
compress
(
List
<
ImgVO
>
list
)
{
String
yyyyMMdd
=
new
SimpleDateFormat
(
"/yyyyMM/dd/"
).
format
(
new
Date
());
String
savePath
=
"/file/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
"/"
;
for
(
ImgVO
img
:
list
)
{
// 网上的文件需要下载
if
(
img
.
getUrl
().
startsWith
(
"http://ddns.gxmailu.com:18888"
))
{
HttpUtil
.
downloadFile
(
img
.
getUrl
(),
savePath
+
img
.
getFileName
());
}
else
{
FileUtil
.
copyFile
(
img
.
getUrl
(),
savePath
+
img
.
getFileName
(),
StandardCopyOption
.
COPY_ATTRIBUTES
);
}
}
String
filePath
=
"/file/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
".zip"
;
ZipUtil
.
zip
(
savePath
,
filePath
,
false
);
FileUtil
.
del
(
savePath
);
return
filePath
;
}
/**
* 遍历文件夹,返回图片文件
*
* @param path 文件及路径
* @return 图片文件列表
* @throws IOException IO异常
*/
public
static
List
<
ImgVO
>
loopFiles
(
String
path
,
String
name
)
throws
IOException
{
List
<
ImgVO
>
resList
=
new
ArrayList
<>();
List
<
File
>
fileList
=
FileUtil
.
loopFiles
(
path
);
String
yyyyMMdd
=
new
SimpleDateFormat
(
"/yyyyMM/dd/"
).
format
(
new
Date
());
String
savePath
=
"/file/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
"/"
;
int
index
=
1
;
for
(
File
file
:
fileList
)
{
String
ext
=
FileUtil
.
extName
(
file
);
if
(
StrUtil
.
isBlank
(
ext
)
||
Arrays
.
stream
(
IMG_EXTS
).
noneMatch
(
img
->
img
.
equalsIgnoreCase
(
ext
)))
{
continue
;
}
// 反转义
String
url
=
savePath
+
index
+
"."
+
ext
;
File
dest
=
new
File
(
url
);
FileUtils
.
writeByteArrayToFile
(
dest
,
FileUtil
.
readBytes
(
file
));
index
++;
resList
.
add
(
ImgVO
.
builder
().
fileName
(
file
.
getName
()).
url
(
url
).
name
(
name
).
build
());
}
return
resList
;
}
/**
* 文件类型判断
*
* @param file 压缩包文件
* @return 类型正确返回true
*/
public
static
boolean
isCompress
(
MultipartFile
file
)
{
String
ext
=
FileUtil
.
extName
(
file
.
getOriginalFilename
());
return
Arrays
.
stream
(
COMPRESS_EXTS
).
anyMatch
(
suffix
->
suffix
.
equalsIgnoreCase
(
ext
));
}
}
imgproc-server/src/main/java/com/zq/imgproc/utils/DemoUtil.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
utils
;
import
cn.hutool.core.codec.Base64
;
import
cn.hutool.core.io.FileUtil
;
import
cn.hutool.http.HttpRequest
;
import
cn.hutool.http.HttpResponse
;
import
cn.hutool.http.HttpUtil
;
import
cn.hutool.json.JSONObject
;
import
cn.hutool.json.JSONUtil
;
import
com.zq.imgproc.vo.DetectionVO
;
import
com.zq.imgproc.vo.OptimizationReq
;
import
com.zq.imgproc.vo.OptimizationVO
;
public
class
DemoUtil
{
final
static
String
URL
=
"localhost:8900/imgproc/v1/"
;
public
static
void
main
(
String
[]
args
)
{
imageOptimization
();
}
public
static
void
detection
()
{
String
testImg
=
"C:/Users/11419/Desktop/Deskew/TestImages/3.png"
;
String
resImg
=
"C:/Users/11419/Desktop/Deskew/TestImages/res.jpg"
;
String
url
=
URL
+
"detection"
;
OptimizationReq
req
=
new
OptimizationReq
();
req
.
setFilename
(
"3.png"
);
req
.
setFileContent
(
Base64
.
encode
(
FileUtil
.
file
(
testImg
)));
long
start
=
System
.
currentTimeMillis
();
HttpRequest
request
=
HttpUtil
.
createPost
(
url
)
.
body
(
JSONUtil
.
toJsonStr
(
req
));
try
(
HttpResponse
response
=
request
.
execute
())
{
System
.
out
.
println
(
System
.
currentTimeMillis
()
-
start
);
String
res
=
response
.
body
();
JSONObject
object
=
JSONUtil
.
parseObj
(
res
);
DetectionVO
detectionRes
=
object
.
get
(
"data"
,
DetectionVO
.
class
);
System
.
out
.
println
(
JSONUtil
.
toJsonStr
(
detectionRes
));
}
}
public
static
void
imageOptimization
()
{
String
testImg
=
"C:/Users/11419/Desktop/Deskew/TestImages/6.png"
;
String
resImg
=
"C:/Users/11419/Desktop/Deskew/TestImages/6res.png"
;
String
url
=
URL
+
"imageOptimization"
;
OptimizationReq
req
=
new
OptimizationReq
();
req
.
setFilename
(
"4.png"
);
req
.
setFileContent
(
Base64
.
encode
(
FileUtil
.
file
(
testImg
)));
long
start
=
System
.
currentTimeMillis
();
HttpRequest
request
=
HttpUtil
.
createPost
(
url
)
.
body
(
JSONUtil
.
toJsonStr
(
req
));
try
(
HttpResponse
response
=
request
.
execute
())
{
System
.
out
.
println
(
System
.
currentTimeMillis
()-
start
);
String
res
=
response
.
body
();
JSONObject
object
=
JSONUtil
.
parseObj
(
res
);
OptimizationVO
optimizationVO
=
object
.
get
(
"data"
,
OptimizationVO
.
class
);
FileUtil
.
writeBytes
(
Base64
.
decode
(
optimizationVO
.
getFileContent
()),
FileUtil
.
file
(
resImg
));
optimizationVO
.
setFileContent
(
null
);
System
.
out
.
println
(
JSONUtil
.
toJsonStr
(
optimizationVO
));
}
}
}
imgproc-server/src/main/java/com/zq/imgproc/utils/Deskew.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
utils
;
import
cn.hutool.core.convert.Convert
;
import
org.opencv.core.*
;
import
org.opencv.imgcodecs.Imgcodecs
;
import
org.opencv.imgproc.Imgproc
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
public
class
Deskew
{
public
static
void
main
(
String
[]
args
)
{
System
.
load
(
"D:/project/imgproc/lib/opencv_java460.dll"
);
Mat
image
=
Imgcodecs
.
imread
(
"C:/Users/11419/Desktop/Deskew/TestImages/4.png"
);
int
angle
=
getDeskewAngle
(
image
);
System
.
out
.
println
(
angle
);
Mat
roateMat
=
rotate
(
image
,
angle
);
Imgcodecs
.
imwrite
(
"C:/Users/11419/Desktop/Deskew/TestImages/4res.png"
,
roateMat
);
}
public
static
Integer
getDeskewAngle
(
Mat
src
)
{
// 图片灰度化
Mat
gray
=
src
.
clone
();
Imgproc
.
cvtColor
(
src
,
gray
,
Imgproc
.
COLOR_BGR2GRAY
);
// // 高斯模糊(?)
// @Cleanup
// UMat blur = gray.clone();
// GaussianBlur(gray, blur, new Size(9, 9), 0);
// // 二值化(?)
// @Cleanup
// UMat thresh = blur.clone();
// threshold(blur, thresh, 0, 255, THRESH_BINARY_INV + THRESH_OTSU);
Mat
kernel
=
Imgproc
.
getStructuringElement
(
Imgproc
.
MORPH_RECT
,
new
Size
(
5
,
5
));
// 图片膨胀
Mat
erode
=
gray
.
clone
();
Imgproc
.
erode
(
gray
,
erode
,
kernel
);
// 图片腐蚀
Mat
dilate
=
erode
.
clone
();
Imgproc
.
dilate
(
erode
,
dilate
,
kernel
);
// 边缘检测
Mat
canny
=
dilate
.
clone
();
Imgproc
.
Canny
(
dilate
,
canny
,
50
,
150
);
// 霍夫变换得到线条
Mat
lines
=
new
Mat
();
//累加器阈值参数,小于设置值不返回
int
threshold
=
90
;
//最低线段长度,低于设置值则不返回
double
minLineLength
=
100
;
//间距小于该值的线当成同一条线
double
maxLineGap
=
10
;
// 霍夫变换,通过步长为1,角度为PI/180来搜索可能的直线
Imgproc
.
HoughLinesP
(
canny
,
lines
,
1
,
Math
.
PI
/
180
,
threshold
,
minLineLength
,
maxLineGap
);
// Mat mat = canny.clone();
// Scalar color = new Scalar(0, 0, 255);
// for (int i = 0; i < lines.rows(); i++) {
// double[] line = lines.get(i, 0);
// Imgproc.line(mat, new Point(line[0], line[1]), new Point(line[2], line[3]), color,3, LINE_AA);
// }
// Imgcodecs.imwrite("C:\\Users\\11419\\Desktop\\test\\bend2res.jpg", mat);
// 计算倾斜角度
List
<
Integer
>
angelList
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
lines
.
rows
();
i
++)
{
double
[]
line
=
lines
.
get
(
i
,
0
);
int
k
=
calculateAngle
(
line
[
0
],
line
[
1
],
line
[
2
],
line
[
3
]);
angelList
.
add
(
k
);
}
if
(
angelList
.
isEmpty
())
{
return
0
;
}
gray
.
release
();
kernel
.
release
();
erode
.
release
();
dilate
.
release
();
canny
.
release
();
lines
.
release
();
// 可能还得需要考虑方差来决定选择平均数还是众数
return
most
(
angelList
);
}
/**
* 求数组众数
*
* @param angelList 数组
* @return 数组众数
*/
private
static
int
most
(
List
<
Integer
>
angelList
)
{
if
(
angelList
.
isEmpty
())
{
return
0
;
}
int
res
=
0
;
int
max
=
Integer
.
MIN_VALUE
;
Map
<
Integer
,
Integer
>
map
=
new
HashMap
<>();
for
(
int
i
:
angelList
)
{
map
.
put
(
i
,
map
.
getOrDefault
(
i
,
0
)
+
1
);
}
for
(
Integer
i
:
map
.
keySet
())
{
int
count
=
map
.
get
(
i
);
if
(
count
>
max
)
{
max
=
count
;
res
=
i
;
}
}
return
res
;
}
/**
* 计算直线的倾斜角
*/
private
static
int
calculateAngle
(
double
x1
,
double
y1
,
double
x2
,
double
y2
)
{
double
dx
=
x2
-
x1
;
double
dy
=
y2
-
y1
;
if
(
Math
.
abs
(
dx
)
<
1
e
-
4
)
{
return
90
;
}
else
if
(
Math
.
abs
(
dy
)
<
1
e
-
4
)
{
return
0
;
}
else
{
double
radians
=
Math
.
atan2
(
dy
,
dx
);
double
degrees
=
Math
.
toDegrees
(
radians
);
return
Convert
.
toInt
(
Math
.
round
(
degrees
));
}
}
/**
* 图片旋转
*
* @param image 输入图片
* @param angle 旋转角度
* @return 输出图片
*/
public
static
Mat
rotate
(
Mat
image
,
double
angle
)
{
int
w
=
image
.
cols
();
int
h
=
image
.
rows
();
if
(
angle
<
0
)
{
angle
=
360
+
angle
;
}
Point
center
=
new
Point
((
double
)
w
/
2
,
(
double
)
h
/
2
);
double
scale
=
1.0
;
Mat
rotationMatrix
=
Imgproc
.
getRotationMatrix2D
(
center
,
angle
,
scale
);
// 设置填充颜色为白色
Scalar
backgroundColor
=
new
Scalar
(
255
,
255
,
255
);
Mat
rotatedImage
=
new
Mat
();
Imgproc
.
warpAffine
(
image
,
rotatedImage
,
rotationMatrix
,
new
Size
(
w
,
h
),
Imgproc
.
INTER_LINEAR
,
Core
.
BORDER_CONSTANT
,
backgroundColor
);
rotationMatrix
.
release
();
return
rotatedImage
;
}
}
imgproc-server/src/main/java/com/zq/imgproc/utils/ImageCorrectionUtil.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
utils
;
import
cn.hutool.core.util.RuntimeUtil
;
import
com.drew.imaging.ImageMetadataReader
;
import
com.drew.metadata.Directory
;
import
com.drew.metadata.Metadata
;
import
com.drew.metadata.Tag
;
import
javax.imageio.ImageIO
;
import
java.awt.*
;
import
java.awt.image.BufferedImage
;
import
java.io.File
;
import
java.io.FileOutputStream
;
/**
* <p>
* 纠偏
* </p>
*
* @author chenhao
* @since 2023/3/8 10:23
*/
public
class
ImageCorrectionUtil
{
/**
* 纠正图片旋转
*
* @param srcImgPath 图片地址
*/
public
static
void
correctImg
(
String
srcImgPath
)
{
FileOutputStream
fos
=
null
;
try
{
// 原始图片
File
srcFile
=
new
File
(
srcImgPath
);
// 获取偏转角度
int
angle
=
getAngle
(
srcFile
);
if
(
angle
!=
90
&&
angle
!=
270
)
{
return
;
}
// 原始图片缓存
BufferedImage
srcImg
=
ImageIO
.
read
(
srcFile
);
// 宽高互换
// 原始宽度
int
imgWidth
=
srcImg
.
getHeight
();
// 原始高度
int
imgHeight
=
srcImg
.
getWidth
();
// 中心点位置
double
centerWidth
=
((
double
)
imgWidth
)
/
2
;
double
centerHeight
=
((
double
)
imgHeight
)
/
2
;
// 图片缓存
BufferedImage
targetImg
=
new
BufferedImage
(
imgWidth
,
imgHeight
,
BufferedImage
.
TYPE_INT_RGB
);
// 旋转对应角度
Graphics2D
g
=
targetImg
.
createGraphics
();
g
.
rotate
(
Math
.
toRadians
(
angle
),
centerWidth
,
centerHeight
);
g
.
drawImage
(
srcImg
,
(
imgWidth
-
srcImg
.
getWidth
())
/
2
,
(
imgHeight
-
srcImg
.
getHeight
())
/
2
,
null
);
g
.
rotate
(
Math
.
toRadians
(-
angle
),
centerWidth
,
centerHeight
);
g
.
dispose
();
// 输出图片
fos
=
new
FileOutputStream
(
srcFile
);
ImageIO
.
write
(
targetImg
,
"jpg"
,
fos
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
finally
{
if
(
fos
!=
null
)
{
try
{
fos
.
flush
();
fos
.
close
();
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
}
}
}
/**
* 获取图片旋转角度
*
* @param file 上传图片
* @return 图片旋转角度
*/
private
static
int
getAngle
(
File
file
)
throws
Exception
{
Metadata
metadata
=
ImageMetadataReader
.
readMetadata
(
file
);
for
(
Directory
directory
:
metadata
.
getDirectories
())
{
for
(
Tag
tag
:
directory
.
getTags
())
{
if
(
"Orientation"
.
equals
(
tag
.
getTagName
()))
{
String
orientation
=
tag
.
getDescription
();
if
(
orientation
.
contains
(
"90"
))
{
return
90
;
}
else
if
(
orientation
.
contains
(
"180"
))
{
return
180
;
}
else
if
(
orientation
.
contains
(
"270"
))
{
return
270
;
}
}
}
}
return
0
;
}
/**
* 调用deskew工具
* Usage:
* deskew [-o output] [-a angle] [-b color] [..] input
* input: Input image file
* Options:
* -o output: 输出图像文件路径(默认:out.png)
* -a angle: 最大期望倾斜角度(两个方向)(默认:10度)
* -b color: 背景颜色十六进制格式RRGGBB|LL|AARRGGBB(默认为黑色)
* Ext. options:
* -q filter: 用于旋转的重采样过滤器 (default: linear,
* values: nearest|linear|cubic|lanczos)
* -t a|treshold: 自动阈值或0..255的值 (default: a)
* -r rect: 仅在内容矩形中进行倾斜检测 (pixels):
* left,top,right,bottom (default: whole page)
* -f format: 输出像素格式 (values: b1|g8|rgb24|rgba32)
* -l angle: 如果倾斜角度较小,则跳过倾斜步骤 (default: 0.01)
* -g flags: Operational flags (any combination of):
* c - auto crop, d - detect only (no output to file)
* -s info: 信息转储 (any combination of):
* s - skew detection stats, p - program parameters, t - timings
* -c specs: 某些文件格式的输出压缩规格。可以定义几个规格-用逗号分隔。支持规格:
* jXX - JPEG compression quality, XX is in range [1,100(best)]
* tSCHEME - TIFF compression scheme: none|lzw|rle|deflate|jpeg|g4
* Supported file formats
* Input: BMP, JPG, PNG, JNG, GIF, DDS, TGA, PBM, PGM, PPM, PAM, PFM, TIF, PSD
* Output: BMP, JPG, PNG, JNG, GIF, DDS, TGA, PGM, PPM, PAM, PFM, TIF, PSD
*
* @return 调用结果
*/
public
static
String
deskew
(
String
src
,
String
dst
,
String
deskewUrl
,
boolean
deskewAngle
)
{
StringBuilder
str
=
new
StringBuilder
();
// 命令行位置
str
.
append
(
deskewUrl
).
append
(
" "
);
// 背景颜色
str
.
append
(
"-b"
).
append
(
" "
).
append
(
"FFFFFF"
).
append
(
" "
);
if
(
deskewAngle
)
{
// 图片旋转耗时很多,跳过图片旋转
str
.
append
(
"-l"
).
append
(
" "
).
append
(
"80"
).
append
(
" "
);
}
// 输出路径
str
.
append
(
"-o"
).
append
(
" "
).
append
(
dst
).
append
(
" "
);
// 输入路径
str
.
append
(
src
);
return
RuntimeUtil
.
execForStr
(
str
.
toString
());
}
public
static
String
deskew2
(
String
src
,
String
dst
,
String
deskewpyUrl
)
{
StringBuilder
str
=
new
StringBuilder
();
// python启动
str
.
append
(
"python"
).
append
(
" "
);
// python文件位置
str
.
append
(
deskewpyUrl
).
append
(
" "
);
// 输入文件
str
.
append
(
"-i"
).
append
(
" "
).
append
(
src
).
append
(
" "
);
// 输出文件
str
.
append
(
"-o"
).
append
(
" "
).
append
(
dst
).
append
(
" "
);
return
RuntimeUtil
.
execForStr
(
str
.
toString
());
}
public
static
void
main
(
String
[]
args
)
{
String
path1
=
"C:\\Users\\11419\\Desktop\\Deskew\\TestImages\\3.png"
;
String
path2
=
"C:\\Users\\11419\\Desktop\\Deskew\\TestImages\\res3.png"
;
String
du
=
"C:\\Users\\11419\\Desktop\\lib\\correct.py"
;
String
res
=
deskew2
(
path1
,
path2
,
du
);
System
.
out
.
println
(
res
);
}
}
imgproc-server/src/main/java/com/zq/imgproc/utils/ImageUtil.java
0 → 100644
View file @
003b7634
This diff is collapsed.
Click to expand it.
imgproc-server/src/main/java/com/zq/imgproc/utils/RemoveBlackUtil.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
utils
;
import
org.opencv.core.*
;
import
org.opencv.imgcodecs.Imgcodecs
;
import
org.opencv.imgproc.Imgproc
;
import
org.opencv.utils.Converters
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Random
;
/**
* <p>
* 去黑边
* </p>
*
* @author chenhao
* @since 2023/3/8 9:31
*/
public
class
RemoveBlackUtil
{
public
static
void
main
(
String
[]
args
)
{
String
testImg
=
"C:\\Users\\11419\\Desktop\\test\\a.jpg"
;
String
resImg
=
"C:\\Users\\11419\\Desktop\\test\\8.jpg"
;
System
.
load
(
"D:\\project\\imgproc\\lib\\opencv_java460.dll"
);
remove
(
testImg
,
resImg
);
}
public
static
void
remove
(
String
src
,
String
dst
)
{
Mat
img
=
Imgcodecs
.
imread
(
src
);
if
(
img
.
empty
()){
return
;
}
Mat
greyImg
=
img
.
clone
();
//1.彩色转灰色
Imgproc
.
cvtColor
(
img
,
greyImg
,
Imgproc
.
COLOR_BGR2GRAY
);
ImageUtil
.
saveImage
(
greyImg
,
"C:\\Users\\11419\\Desktop\\test\\1.jpg"
);
Mat
gaussianBlurImg
=
greyImg
.
clone
();
// 2.高斯滤波,降噪
Imgproc
.
GaussianBlur
(
greyImg
,
gaussianBlurImg
,
new
Size
(
3
,
3
),
0
);
ImageUtil
.
saveImage
(
greyImg
,
"C:\\Users\\11419\\Desktop\\test\\2.jpg"
);
// 3.Canny边缘检测
Mat
cannyImg
=
gaussianBlurImg
.
clone
();
Imgproc
.
Canny
(
gaussianBlurImg
,
cannyImg
,
50
,
200
);
ImageUtil
.
saveImage
(
cannyImg
,
"C:\\Users\\11419\\Desktop\\test\\3.jpg"
);
// 4.膨胀,连接边缘
Mat
dilateImg
=
cannyImg
.
clone
();
Imgproc
.
dilate
(
cannyImg
,
dilateImg
,
new
Mat
(),
new
Point
(-
1
,
-
1
),
3
,
1
,
new
Scalar
(
1
));
ImageUtil
.
saveImage
(
dilateImg
,
"C:\\Users\\11419\\Desktop\\test\\4.jpg"
);
//5.对边缘检测的结果图再进行轮廓提取
List
<
MatOfPoint
>
contours
=
new
ArrayList
<>();
List
<
MatOfPoint
>
drawContours
=
new
ArrayList
<>();
Mat
hierarchy
=
new
Mat
();
Imgproc
.
findContours
(
dilateImg
,
contours
,
hierarchy
,
Imgproc
.
RETR_EXTERNAL
,
Imgproc
.
CHAIN_APPROX_SIMPLE
);
Mat
linePic
=
Mat
.
zeros
(
dilateImg
.
rows
(),
dilateImg
.
cols
(),
CvType
.
CV_8UC3
);
//6.找出轮廓对应凸包的四边形拟合
List
<
MatOfPoint
>
squares
=
new
ArrayList
<>();
List
<
MatOfPoint
>
hulls
=
new
ArrayList
<>();
MatOfInt
hull
=
new
MatOfInt
();
MatOfPoint2f
approx
=
new
MatOfPoint2f
();
approx
.
convertTo
(
approx
,
CvType
.
CV_32F
);
for
(
MatOfPoint
contour
:
contours
)
{
// 边框的凸包
Imgproc
.
convexHull
(
contour
,
hull
);
// 用凸包计算出新的轮廓点
Point
[]
contourPoints
=
contour
.
toArray
();
int
[]
indices
=
hull
.
toArray
();
List
<
Point
>
newPoints
=
new
ArrayList
<>();
for
(
int
index
:
indices
)
{
newPoints
.
add
(
contourPoints
[
index
]);
}
MatOfPoint2f
contourHull
=
new
MatOfPoint2f
();
contourHull
.
fromList
(
newPoints
);
// 多边形拟合凸包边框(此时的拟合的精度较低)
Imgproc
.
approxPolyDP
(
contourHull
,
approx
,
Imgproc
.
arcLength
(
contourHull
,
true
)
*
0.02
,
true
);
MatOfPoint
mat
=
new
MatOfPoint
();
mat
.
fromArray
(
approx
.
toArray
());
drawContours
.
add
(
mat
);
// 筛选出面积大于某一阈值的,且四边形的各个角度都接近直角的凸四边形
MatOfPoint
approxf1
=
new
MatOfPoint
();
approx
.
convertTo
(
approxf1
,
CvType
.
CV_32S
);
if
(
approx
.
rows
()
==
4
&&
Math
.
abs
(
Imgproc
.
contourArea
(
approx
))
>
40000
&&
Imgproc
.
isContourConvex
(
approxf1
))
{
double
maxCosine
=
0
;
for
(
int
j
=
2
;
j
<
5
;
j
++)
{
double
cosine
=
Math
.
abs
(
getAngle
(
approxf1
.
toArray
()[
j
%
4
],
approxf1
.
toArray
()[
j
-
2
],
approxf1
.
toArray
()[
j
-
1
]));
maxCosine
=
Math
.
max
(
maxCosine
,
cosine
);
}
// 角度大概72度
if
(
maxCosine
<
0.3
)
{
MatOfPoint
tmp
=
new
MatOfPoint
();
contourHull
.
convertTo
(
tmp
,
CvType
.
CV_32S
);
squares
.
add
(
approxf1
);
hulls
.
add
(
tmp
);
}
}
}
//这里是把提取出来的轮廓通过不同颜色的线描述出来,具体效果可以自己去看
Random
r
=
new
Random
();
for
(
int
i
=
0
;
i
<
drawContours
.
size
();
i
++)
{
Imgproc
.
drawContours
(
linePic
,
drawContours
,
i
,
new
Scalar
(
r
.
nextInt
(
255
),
r
.
nextInt
(
255
),
r
.
nextInt
(
255
)));
}
ImageUtil
.
saveImage
(
linePic
,
"C:\\Users\\11419\\Desktop\\test\\5.jpg"
);
//7.找出最大的矩形
int
index
=
findLargestSquare
(
squares
);
MatOfPoint
largest_square
;
if
(
squares
.
size
()
>
0
){
largest_square
=
squares
.
get
(
index
);
}
else
{
System
.
out
.
println
(
"图片无法识别"
);
return
;
}
Mat
polyPic
=
Mat
.
zeros
(
img
.
size
(),
CvType
.
CV_8UC3
);
Imgproc
.
drawContours
(
polyPic
,
squares
,
index
,
new
Scalar
(
0
,
0
,
255
),
2
);
ImageUtil
.
saveImage
(
polyPic
,
"C:\\Users\\11419\\Desktop\\test\\6.jpg"
);
//存储矩形的四个凸点
hull
=
new
MatOfInt
();
Imgproc
.
convexHull
(
largest_square
,
hull
,
false
);
List
<
Integer
>
hullList
=
hull
.
toList
();
List
<
Point
>
polyContoursList
=
largest_square
.
toList
();
List
<
Point
>
hullPointList
=
new
ArrayList
<>();
for
(
Integer
integer
:
hullList
)
{
Imgproc
.
circle
(
polyPic
,
polyContoursList
.
get
(
integer
),
10
,
new
Scalar
(
r
.
nextInt
(
255
),
r
.
nextInt
(
255
),
r
.
nextInt
(
255
),
3
));
hullPointList
.
add
(
polyContoursList
.
get
(
integer
));
}
Core
.
addWeighted
(
polyPic
,
1
,
img
,
1
,
0
,
img
);
ImageUtil
.
saveImage
(
img
,
"C:\\Users\\11419\\Desktop\\test\\7.jpg"
);
List
<
Point
>
lastHullPointList
=
new
ArrayList
<>(
hullPointList
);
//dstPoints储存的是变换后各点的坐标,依次为左上,右上,右下, 左下
//srcPoints储存的是上面得到的四个角的坐标
Point
[]
dstPoints
=
{
new
Point
(
0
,
0
),
new
Point
(
img
.
cols
(),
0
),
new
Point
(
img
.
cols
(),
img
.
rows
()),
new
Point
(
0
,
img
.
rows
())};
Point
[]
srcPoints
=
new
Point
[
4
];
boolean
sorted
=
false
;
int
n
=
4
;
//对四个点进行排序 分出左上 右上 右下 左下
while
(!
sorted
&&
n
>
0
){
for
(
int
i
=
1
;
i
<
n
;
i
++){
sorted
=
true
;
if
(
lastHullPointList
.
get
(
i
-
1
).
x
>
lastHullPointList
.
get
(
i
).
x
){
Point
tempp1
=
lastHullPointList
.
get
(
i
);
Point
tempp2
=
lastHullPointList
.
get
(
i
-
1
);
lastHullPointList
.
set
(
i
,
tempp2
);
lastHullPointList
.
set
(
i
-
1
,
tempp1
);
sorted
=
false
;
}
}
n
--;
}
//即先对四个点的x坐标进行冒泡排序分出左右,再根据两对坐标的y值比较分出上下
if
(
lastHullPointList
.
get
(
0
).
y
<
lastHullPointList
.
get
(
1
).
y
){
srcPoints
[
0
]
=
lastHullPointList
.
get
(
0
);
srcPoints
[
3
]
=
lastHullPointList
.
get
(
1
);
}
else
{
srcPoints
[
0
]
=
lastHullPointList
.
get
(
1
);
srcPoints
[
3
]
=
lastHullPointList
.
get
(
0
);
}
if
(
lastHullPointList
.
get
(
2
).
y
<
lastHullPointList
.
get
(
3
).
y
){
srcPoints
[
1
]
=
lastHullPointList
.
get
(
2
);
srcPoints
[
2
]
=
lastHullPointList
.
get
(
3
);
}
else
{
srcPoints
[
1
]
=
lastHullPointList
.
get
(
3
);
srcPoints
[
2
]
=
lastHullPointList
.
get
(
2
);
}
List
<
Point
>
listSrcs
=
java
.
util
.
Arrays
.
asList
(
srcPoints
[
0
],
srcPoints
[
1
],
srcPoints
[
2
],
srcPoints
[
3
]);
Mat
srcPointsMat
=
Converters
.
vector_Point_to_Mat
(
listSrcs
,
CvType
.
CV_32F
);
List
<
Point
>
dstSrcs
=
java
.
util
.
Arrays
.
asList
(
dstPoints
[
0
],
dstPoints
[
1
],
dstPoints
[
2
],
dstPoints
[
3
]);
Mat
dstPointsMat
=
Converters
.
vector_Point_to_Mat
(
dstSrcs
,
CvType
.
CV_32F
);
//参数分别为输入输出图像、变换矩阵、大小。
//坐标变换后就得到了我们要的最终图像。
Mat
transMat
=
Imgproc
.
getPerspectiveTransform
(
srcPointsMat
,
dstPointsMat
);
//得到变换矩阵
Mat
outPic
=
new
Mat
();
Imgproc
.
warpPerspective
(
img
,
outPic
,
transMat
,
img
.
size
());
ImageUtil
.
saveImage
(
outPic
,
dst
);
}
// 根据三个点计算中间那个点的夹角 pt1 pt0 pt2
private
static
double
getAngle
(
Point
pt1
,
Point
pt2
,
Point
pt0
)
{
double
dx1
=
pt1
.
x
-
pt0
.
x
;
double
dy1
=
pt1
.
y
-
pt0
.
y
;
double
dx2
=
pt2
.
x
-
pt0
.
x
;
double
dy2
=
pt2
.
y
-
pt0
.
y
;
return
(
dx1
*
dx2
+
dy1
*
dy2
)/
Math
.
sqrt
((
dx1
*
dx1
+
dy1
*
dy1
)*(
dx2
*
dx2
+
dy2
*
dy2
)
+
1
e
-
10
);
}
// 找到最大的正方形轮廓
private
static
int
findLargestSquare
(
List
<
MatOfPoint
>
squares
)
{
if
(
squares
.
size
()
==
0
)
{
return
-
1
;
}
int
max_width
=
0
;
int
max_height
=
0
;
int
max_square_idx
=
0
;
int
currentIndex
=
0
;
for
(
MatOfPoint
square
:
squares
)
{
Rect
rectangle
=
Imgproc
.
boundingRect
(
square
);
if
(
rectangle
.
width
>=
max_width
&&
rectangle
.
height
>=
max_height
)
{
max_width
=
rectangle
.
width
;
max_height
=
rectangle
.
height
;
max_square_idx
=
currentIndex
;
}
currentIndex
++;
}
return
max_square_idx
;
}
}
imgproc-server/src/main/java/com/zq/imgproc/utils/RemoveBlackUtil2.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
utils
;
import
org.opencv.core.Mat
;
import
org.opencv.core.Rect
;
import
org.opencv.imgcodecs.Imgcodecs
;
import
org.opencv.imgproc.Imgproc
;
/**
* <p>
* 去黑边
* </p>
*
* @author chenhao
* @since 2023/3/10 15:01
*/
public
class
RemoveBlackUtil2
{
/**
* 去黑边"全黑"阈值
*/
private
static
final
Integer
BLACK_VALUE
=
100
;
public
static
void
remove
(
String
src
,
String
dst
)
{
Mat
mat
=
Imgcodecs
.
imread
(
src
);
Mat
res
=
removeBlackEdge
(
mat
);
ImageUtil
.
saveImage
(
res
,
dst
);
mat
.
release
();
res
.
release
();
}
/**
* 去除图片黑边,若无黑边,则原图返回。默认“全黑”阈值为 {@code BLACK_VALUE}
*
* @param srcMat 预去除黑边的Mat
* @return 去除黑边之后的Mat
*/
private
static
Mat
removeBlackEdge
(
Mat
srcMat
)
{
return
removeBlackEdge
(
srcMat
,
BLACK_VALUE
);
}
/**
* 去除图片黑边,若无黑边,则原图返回。
*
* @param blackValue 一般低于5的已经是很黑的颜色了
* @param srcMat 源Mat对象
* @return Mat对象
*/
private
static
Mat
removeBlackEdge
(
Mat
srcMat
,
int
blackValue
)
{
// 灰度化
Mat
grayMat
=
gray
(
srcMat
);
// 定义边界
int
topRow
=
0
;
int
leftCol
=
0
;
int
rightCol
=
grayMat
.
width
()
-
1
;
int
bottomRow
=
grayMat
.
height
()
-
1
;
// 上方黑边判断
for
(
int
row
=
0
;
row
<
grayMat
.
height
();
row
++)
{
if
(
ImageUtil
.
sum
(
grayMat
.
row
(
row
))
/
grayMat
.
width
()
<
blackValue
)
{
topRow
=
row
;
}
else
{
break
;
}
}
// 左边黑边判断
for
(
int
col
=
0
;
col
<
grayMat
.
width
();
col
++)
{
if
(
ImageUtil
.
sum
(
grayMat
.
col
(
col
))
/
grayMat
.
height
()
<
blackValue
)
{
leftCol
=
col
;
}
else
{
break
;
}
}
// 右边黑边判断
for
(
int
col
=
grayMat
.
width
()
-
1
;
col
>
0
;
col
--)
{
if
(
ImageUtil
.
sum
(
grayMat
.
col
(
col
))
/
grayMat
.
height
()
<
blackValue
)
{
rightCol
=
col
;
}
else
{
break
;
}
}
// 下方黑边判断
for
(
int
row
=
grayMat
.
height
()
-
1
;
row
>
0
;
row
--)
{
if
(
ImageUtil
.
sum
(
grayMat
.
row
(
row
))
/
grayMat
.
width
()
<
blackValue
)
{
bottomRow
=
row
;
}
else
{
break
;
}
}
int
x
=
leftCol
;
int
y
=
topRow
;
int
width
=
rightCol
-
leftCol
;
int
height
=
bottomRow
-
topRow
;
grayMat
.
release
();
if
(
leftCol
==
0
&&
rightCol
==
grayMat
.
width
()
-
1
&&
topRow
==
0
&&
bottomRow
==
grayMat
.
height
()
-
1
)
{
return
srcMat
;
}
return
cut
(
srcMat
,
x
,
y
,
width
,
height
);
}
/**
* 灰度处理 BGR灰度处理
*
* @param src 原图Mat
* @return Mat 灰度后的Mat
*/
private
static
Mat
gray
(
Mat
src
)
{
Mat
gray
=
new
Mat
();
Imgproc
.
cvtColor
(
src
,
gray
,
Imgproc
.
COLOR_BGR2GRAY
);
return
gray
;
}
/**
* 按照指定的尺寸截取Mat,坐标原点为左上角
*
* @param src 源Mat
* @param x x
* @param y y
* @param width width
* @param height height
* @return 截取后的Mat
*/
private
static
Mat
cut
(
Mat
src
,
int
x
,
int
y
,
int
width
,
int
height
)
{
if
(
x
<
0
)
{
x
=
0
;
}
if
(
y
<
0
)
{
y
=
0
;
}
if
(
width
>
src
.
width
())
{
width
=
src
.
width
();
}
if
(
height
>
src
.
height
())
{
height
=
src
.
height
();
}
// 截取尺寸
Rect
rect
=
new
Rect
(
x
,
y
,
width
,
height
);
return
new
Mat
(
src
,
rect
);
}
}
imgproc-server/src/main/java/com/zq/imgproc/utils/Test2.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
utils
;
import
cn.hutool.core.convert.Convert
;
import
cn.hutool.core.io.FileUtil
;
import
cn.hutool.json.JSONUtil
;
import
com.zq.imgproc.vo.DetectionVO
;
import
lombok.extern.slf4j.Slf4j
;
import
org.opencv.core.Core
;
import
org.opencv.core.Mat
;
import
org.opencv.core.Scalar
;
import
org.opencv.imgcodecs.Imgcodecs
;
import
java.math.BigDecimal
;
import
java.math.RoundingMode
;
/**
* <p>
*
* </p>
*
* @author chenhao
* @since 2023/11/20
*/
@Slf4j
public
class
Test2
{
public
static
void
main
(
String
[]
args
)
throws
Exception
{
System
.
load
(
"D:\\project\\imgproc\\lib\\opencv_java460.dll"
);
String
src
=
"C:\\Users\\11419\\Desktop\\test\\black1.png"
;
String
dst
=
"C:\\Users\\11419\\Desktop\\Deskew\\TestImages\\6res.png"
;
long
start
=
System
.
currentTimeMillis
();
DetectionVO
vo
=
new
DetectionVO
();
Mat
image
=
Imgcodecs
.
imread
(
src
);
log
.
info
(
"加载图片耗时为:--------------{}"
,
System
.
currentTimeMillis
()
-
start
);
start
=
System
.
currentTimeMillis
();
// 检测图片的分辨率
vo
.
setWidthResolution
(
image
.
width
());
vo
.
setHeightResolution
(
image
.
height
());
log
.
info
(
"检测图片分辨率耗时为:--------------{}"
,
System
.
currentTimeMillis
()
-
start
);
start
=
System
.
currentTimeMillis
();
// 检测图片的DPI
vo
.
setDpi
(
ImageUtil
.
getDpi
(
FileUtil
.
file
(
src
)));
log
.
info
(
"检测图片DPI耗时为:--------------{}"
,
System
.
currentTimeMillis
()
-
start
);
start
=
System
.
currentTimeMillis
();
// 检测图片清晰度
BigDecimal
clarity
=
BigDecimal
.
valueOf
(
ImageUtil
.
tenengrad
(
image
));
vo
.
setClarity
(
clarity
.
setScale
(
2
,
RoundingMode
.
HALF_UP
).
doubleValue
());
log
.
info
(
"检测图片清晰度耗时为:--------------{}"
,
System
.
currentTimeMillis
()
-
start
);
start
=
System
.
currentTimeMillis
();
// 检测图片的亮度
vo
.
setBrightness
(
Convert
.
toInt
(
ImageUtil
.
brightness
(
image
)));
log
.
info
(
"检测图片亮度耗时为:--------------{}"
,
System
.
currentTimeMillis
()
-
start
);
start
=
System
.
currentTimeMillis
();
// 检测图片倾斜角度
vo
.
setAngle
(
Deskew
.
getDeskewAngle
(
image
));
log
.
info
(
"检测图片倾斜角度耗时为:--------------{}"
,
System
.
currentTimeMillis
()
-
start
);
start
=
System
.
currentTimeMillis
();
// 检测图片的黑边
blackDetection2
(
image
);
blackDetection3
(
image
);
System
.
out
.
println
(
JSONUtil
.
toJsonStr
(
vo
));
}
/**
* 黑边检测
*
* @param src 图片矩阵
* @return true表示可能存在黑边
*/
public
static
boolean
blackDetection
(
Mat
src
)
{
int
BLACK_VALUE
=
50
;
int
width
=
src
.
width
();
int
height
=
src
.
height
();
// 定义初始边界
int
top
=
0
;
int
left
=
0
;
int
right
=
width
-
1
;
int
bottom
=
height
-
1
;
// 上方黑边判断
for
(
int
row
=
0
;
row
<
height
;
row
++)
{
if
(
ImageUtil
.
sum
(
src
.
row
(
row
))
/
width
<
BLACK_VALUE
)
{
top
=
row
;
}
else
{
break
;
}
}
// 左边黑边判断
for
(
int
col
=
0
;
col
<
width
;
col
++)
{
if
(
ImageUtil
.
sum
(
src
.
col
(
col
))
/
height
<
BLACK_VALUE
)
{
left
=
col
;
}
else
{
break
;
}
}
// 右边黑边判断
for
(
int
col
=
width
-
1
;
col
>
0
;
col
--)
{
if
(
ImageUtil
.
sum
(
src
.
col
(
col
))
/
height
<
BLACK_VALUE
)
{
right
=
col
;
}
else
{
break
;
}
}
// 下方黑边判断
for
(
int
row
=
height
-
1
;
row
>
0
;
row
--)
{
if
(
ImageUtil
.
sum
(
src
.
row
(
row
))
/
width
<
BLACK_VALUE
)
{
bottom
=
row
;
}
else
{
break
;
}
}
// 若是边界没有被更新,认为不存在黑边
return
top
!=
0
||
left
!=
0
||
right
!=
width
-
1
||
bottom
!=
height
-
1
;
}
public
static
void
blackDetection2
(
Mat
src
)
{
long
start
=
System
.
currentTimeMillis
();
int
BLACK_VALUE
=
30
;
int
width
=
src
.
width
();
int
height
=
src
.
height
();
int
rows
=
0
;
int
cols
=
0
;
// 上方黑边判断
for
(
int
row
=
0
;
row
<
height
;
row
++)
{
if
(
ImageUtil
.
sum
(
src
.
row
(
row
))
/
width
<
BLACK_VALUE
)
{
rows
++;
}
}
// 左边黑边判断
for
(
int
col
=
0
;
col
<
width
;
col
++)
{
if
(
ImageUtil
.
sum
(
src
.
col
(
col
))
/
height
<
BLACK_VALUE
)
{
cols
++;
}
}
log
.
info
(
"{}, {}, {}, {}"
,
"22222"
,
rows
,
cols
,
System
.
currentTimeMillis
()
-
start
);
}
public
static
void
blackDetection3
(
Mat
src
)
{
long
start
=
System
.
currentTimeMillis
();
int
BLACK_VALUE
=
30
;
int
width
=
src
.
width
();
int
height
=
src
.
height
();
int
rows
=
0
;
int
cols
=
0
;
int
limitRows
=
500
;
int
limitCols
=
500
;
for
(
int
row
=
0
;
row
<
height
;
row
++)
{
Scalar
mean
=
Core
.
mean
(
src
.
row
(
row
));
if
(
Convert
.
toInt
(
mean
.
val
[
0
])
<
BLACK_VALUE
)
{
rows
++;
}
}
for
(
int
col
=
0
;
col
<
width
;
col
++)
{
Scalar
mean
=
Core
.
mean
(
src
.
col
(
col
));
if
(
Convert
.
toInt
(
mean
.
val
[
0
])
<
BLACK_VALUE
)
{
cols
++;
}
}
log
.
info
(
"{}, {}, {}, {}"
,
"3333333"
,
rows
,
cols
,
System
.
currentTimeMillis
()
-
start
);
}
}
imgproc-server/src/main/java/com/zq/imgproc/utils/TestUtil.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
utils
;
import
cn.hutool.core.convert.Convert
;
import
cn.hutool.core.io.FileUtil
;
import
com.drew.imaging.ImageMetadataReader
;
import
com.drew.metadata.Directory
;
import
com.drew.metadata.Metadata
;
import
com.drew.metadata.Tag
;
import
com.zq.imgproc.vo.DetectionVO
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.imaging.ImageInfo
;
import
org.apache.commons.imaging.Imaging
;
import
org.opencv.core.Mat
;
import
org.opencv.imgcodecs.Imgcodecs
;
import
java.io.File
;
@Slf4j
public
class
TestUtil
{
public
static
void
main
(
String
[]
args
)
throws
Exception
{
System
.
load
(
"D:/project/imgproc/lib/opencv_java460.dll"
);
String
src
=
"C:\\Users\\11419\\Desktop\\4.png"
;
String
dst
=
"C:\\Users\\11419\\Desktop\\res.png"
;
// deskew(src, dst);
RemoveBlackUtil2
.
remove
(
src
,
dst
);
// bright(src, dst);
// im(src, dst);
}
public
static
void
deskew
(
String
src
,
String
dst
)
{
Mat
mat
=
Imgcodecs
.
imread
(
src
);
double
skewAngle
=
Deskew
.
getDeskewAngle
(
mat
);
Mat
rotateMat
=
Deskew
.
rotate
(
mat
,
skewAngle
);
Imgcodecs
.
imwrite
(
dst
,
rotateMat
);
}
public
static
void
removeBlack
(
String
src
,
String
dst
)
{
RemoveBlackUtil2
.
remove
(
src
,
dst
);
}
public
static
void
bright
(
String
src
,
String
dst
)
{
double
brightness
=
ImageUtil
.
brightness
(
src
);
System
.
out
.
println
(
brightness
);
// 亮度异常执行亮度矫正
if
(
brightness
<
100
||
brightness
>
500
)
{
// 计算亮度调整值
double
alpha
=
300
/
brightness
;
// 执行亮度调整
Mat
grayImage
=
Imgcodecs
.
imread
(
src
);
Mat
adjustedImage
=
new
Mat
();
grayImage
.
convertTo
(
adjustedImage
,
-
1
,
alpha
,
0
);
// 保存调整后的图像
Imgcodecs
.
imwrite
(
dst
,
adjustedImage
);
}
}
public
static
void
im
(
String
src
,
String
dst
)
{
double
laplacianScore
=
ImageUtil
.
imageSharpnessDetector
(
src
);
System
.
out
.
println
(
laplacianScore
);
if
(
laplacianScore
<
500
)
{
Mat
unsharpMaskingMat
=
ImageUtil
.
unsharpMasking
(
src
);
// 保存调整后的图像
Imgcodecs
.
imwrite
(
dst
,
unsharpMaskingMat
);
}
}
public
static
DetectionVO
detection
(
String
src
)
throws
Exception
{
DetectionVO
res
=
new
DetectionVO
();
Mat
image
=
Imgcodecs
.
imread
(
src
);
// 检测图片的分辨率
res
.
setWidthResolution
(
image
.
width
());
res
.
setHeightResolution
(
image
.
height
());
// 检测图片的DPI
res
.
setDpi
(
getDpi
(
FileUtil
.
file
(
src
)));
// 检测图片清晰度
res
.
setClarity
(
ImageUtil
.
imageSharpnessDetector
(
image
));
// 检测图片的亮度
res
.
setBrightness
(
ImageUtil
.
brightness
(
image
));
// 检测图片倾斜角度
res
.
setAngle
(
Deskew
.
getDeskewAngle
(
image
));
// 检测图片的黑边
res
.
setBlack
(
blackDetection
(
image
));
return
res
;
}
/**
* 获取图片DPI
*
* @param file 图片文件
* @return [水平DPI,垂直DPI]
*/
private
static
Integer
getDpi
(
File
file
)
throws
Exception
{
int
res
;
ImageInfo
imageInfo
=
Imaging
.
getImageInfo
(
file
);
res
=
imageInfo
.
getPhysicalWidthDpi
();
if
(
res
==
-
1
)
{
Metadata
metadata
=
ImageMetadataReader
.
readMetadata
(
file
);
for
(
Directory
directory
:
metadata
.
getDirectories
())
{
for
(
Tag
tag
:
directory
.
getTags
())
{
if
(
"X Resolution"
.
equals
(
tag
.
getTagName
()))
{
res
=
Convert
.
toInt
(
tag
.
getDescription
());
}
}
}
}
return
res
;
}
/**
* 黑边像素阈值
*/
private
static
final
Integer
THRESHOLD
=
30
;
/**
* 黑边检测
*
* @param src 图片矩阵
* @return true表示可能存在黑边
*/
public
static
boolean
blackDetection
(
Mat
src
)
{
int
width
=
src
.
width
();
int
height
=
src
.
height
();
// 定义初始边界
int
top
=
0
;
int
left
=
0
;
int
right
=
width
-
1
;
int
bottom
=
height
-
1
;
// 上方黑边判断
for
(
int
row
=
0
;
row
<
height
;
row
++)
{
if
(
ImageUtil
.
sum
(
src
.
row
(
row
))
/
width
<
THRESHOLD
)
{
top
=
row
;
}
else
{
break
;
}
}
// 左边黑边判断
for
(
int
col
=
0
;
col
<
width
;
col
++)
{
if
(
ImageUtil
.
sum
(
src
.
col
(
col
))
/
height
<
THRESHOLD
)
{
left
=
col
;
}
else
{
break
;
}
}
// 右边黑边判断
for
(
int
col
=
width
-
1
;
col
>
0
;
col
--)
{
if
(
ImageUtil
.
sum
(
src
.
col
(
col
))
/
height
<
THRESHOLD
)
{
right
=
col
;
}
else
{
break
;
}
}
// 下方黑边判断
for
(
int
row
=
height
-
1
;
row
>
0
;
row
--)
{
if
(
ImageUtil
.
sum
(
src
.
row
(
row
))
/
width
<
THRESHOLD
)
{
bottom
=
row
;
}
else
{
break
;
}
}
// 若是边界没有被更新,认为不存在黑边
return
top
!=
0
||
left
!=
0
||
right
!=
width
-
1
||
bottom
!=
height
-
1
;
}
}
imgproc-server/src/main/java/com/zq/imgproc/utils/UploadUtils.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
utils
;
import
cn.hutool.core.io.FileUtil
;
import
com.zq.common.exception.BusinessException
;
import
com.zq.common.utils.UuidUtils
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.web.multipart.MultipartFile
;
import
java.io.File
;
import
java.io.IOException
;
import
java.text.SimpleDateFormat
;
import
java.util.Date
;
import
java.util.Objects
;
/**
* @author wilmiam
* @since 2021-07-09 18:05
*/
@Slf4j
public
class
UploadUtils
{
private
final
static
String
DATE_FORMAT
=
"/yyyyMM/dd/"
;
/**
* 保存临时文件
*
* @return 保存地址
*/
public
static
String
saveTempFile
(
MultipartFile
file
,
String
systemName
)
{
try
{
String
originalFilename
=
file
.
getOriginalFilename
();
//取文件扩展名
String
ext
=
Objects
.
requireNonNull
(
originalFilename
).
substring
(
originalFilename
.
lastIndexOf
(
"."
)
+
1
);
//生成新文件名
String
name
=
UuidUtils
.
uuidNoDash
()
+
"."
+
ext
;
String
yyyyMMdd
=
new
SimpleDateFormat
(
DATE_FORMAT
).
format
(
new
Date
());
File
dest
=
new
File
(
"/data/temp/"
+
systemName
+
yyyyMMdd
+
name
);
FileUtil
.
writeBytes
(
file
.
getBytes
(),
dest
);
return
"/data/temp/"
+
systemName
+
yyyyMMdd
+
name
;
}
catch
(
IOException
e
)
{
log
.
error
(
"文件保存失败:{}"
,
e
.
getMessage
());
throw
new
BusinessException
(
"文件保存失败"
);
}
}
}
imgproc-server/src/main/java/com/zq/imgproc/vo/BendResult.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
vo
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.util.List
;
/**
* <p>
* 弯曲检测结果
* </P>
*
* @author chenhao
* @since 2023/11/26
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
BendResult
{
/**
* 标签名称
*/
String
label
;
/**
* 置信度
*/
Double
confidence
;
/**
* 弯曲位置
*/
List
<
Double
>
coord
;
}
imgproc-server/src/main/java/com/zq/imgproc/vo/CompressReq.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
vo
;
import
lombok.Data
;
import
java.util.List
;
/**
* <p>
* 压缩请求
* </p>
*
* @author chenhao
* @since 2023/3/9 17:35
*/
@Data
public
class
CompressReq
{
String
name
;
List
<
ImgVO
>
pathList
;
}
imgproc-server/src/main/java/com/zq/imgproc/vo/DetectionDTO.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
vo
;
import
com.alibaba.excel.annotation.ExcelProperty
;
import
lombok.Data
;
import
lombok.EqualsAndHashCode
;
/**
* <p>
*
* </p>
*
* @author chenhao
* @since 2023/11/24
*/
@Data
@EqualsAndHashCode
public
class
DetectionDTO
{
@ExcelProperty
(
"文件名称"
)
private
String
filename
;
@ExcelProperty
(
"分辨率"
)
private
String
resolution
;
@ExcelProperty
(
"DPI"
)
private
Integer
dpi
;
@ExcelProperty
(
"平均亮度值"
)
private
double
brightness
;
@ExcelProperty
(
"清晰度值"
)
private
double
clarity
;
@ExcelProperty
(
"倾斜角度"
)
private
double
angle
;
@ExcelProperty
(
"弯曲置信度"
)
private
double
bend
;
@ExcelProperty
(
"黑边情况"
)
private
String
black
;
}
imgproc-server/src/main/java/com/zq/imgproc/vo/DetectionPageReq.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
vo
;
import
com.zq.common.vo.PageReqVo
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.NoArgsConstructor
;
/**
* <p>
*
* </p>
*
* @author chenhao
* @since 2023/11/28
*/
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
DetectionPageReq
extends
PageReqVo
{
/**
* 用户名称
*/
String
nickName
;
/**
* 图片名称
*/
String
imgName
;
/**
* 文件名称
*/
String
fileName
;
/**
* 上传日期起始
*/
String
startTime
;
/**
* 上传日期结束
*/
String
endTime
;
public
String
getNickName
()
{
return
nickName
;
}
public
void
setNickName
(
String
nickName
)
{
this
.
nickName
=
nickName
;
}
public
String
getImgName
()
{
return
imgName
;
}
public
void
setImgName
(
String
imgName
)
{
this
.
imgName
=
imgName
;
}
public
String
getFileName
()
{
return
fileName
;
}
public
void
setFileName
(
String
fileName
)
{
this
.
fileName
=
fileName
;
}
public
String
getStartTime
()
{
return
startTime
;
}
public
void
setStartTime
(
String
startTime
)
{
this
.
startTime
=
startTime
;
}
public
String
getEndTime
()
{
return
endTime
;
}
public
void
setEndTime
(
String
endTime
)
{
this
.
endTime
=
endTime
;
}
}
imgproc-server/src/main/java/com/zq/imgproc/vo/DetectionResVo.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
vo
;
import
io.swagger.annotations.ApiModelProperty
;
import
lombok.AllArgsConstructor
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
/**
* <p>
* 图片返回结果封装类
* </p>
*
* @author chenhao
* @since 2022/10/27 11:25
*/
@NoArgsConstructor
@AllArgsConstructor
@Data
public
class
DetectionResVo
{
@ApiModelProperty
(
"图片的水平分辨率"
)
private
Integer
widthResolution
;
@ApiModelProperty
(
"图片的垂直分辨率"
)
private
Integer
heightResolution
;
@ApiModelProperty
(
"图片的DPI"
)
private
Integer
dpi
;
@ApiModelProperty
(
"图片的亮度情况,1表示亮度正常,2表示过亮,3表示过暗"
)
private
Integer
brightness
;
@ApiModelProperty
(
"图片的清晰度,true表示清晰,false表示模糊"
)
private
Boolean
clarity
;
@ApiModelProperty
(
"图片的倾斜角度"
)
private
double
angle
;
@ApiModelProperty
(
"图片的黑边检测,true表示可能存在黑边,false表示不存在黑边"
)
private
Boolean
black
;
}
imgproc-server/src/main/java/com/zq/imgproc/vo/DetectionVO.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
vo
;
import
io.swagger.annotations.ApiModelProperty
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
/**
* <p>
* 检测结果
* </P>
*
* @author chenhao
* @since 2023/11/26
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
DetectionVO
{
@ApiModelProperty
(
"图片的水平分辨率"
)
private
Integer
widthResolution
;
@ApiModelProperty
(
"图片的垂直分辨率"
)
private
Integer
heightResolution
;
@ApiModelProperty
(
"图片的DPI"
)
private
Integer
dpi
;
@ApiModelProperty
(
"平均亮度值"
)
private
double
brightness
;
@ApiModelProperty
(
"图片的清晰度指标,值越大越清晰"
)
private
double
clarity
;
@ApiModelProperty
(
"图片的倾斜角度"
)
private
double
angle
;
@ApiModelProperty
(
"图片弯曲检测置信度"
)
private
double
bend
;
@ApiModelProperty
(
"图片的黑边检测,true表示可能存在黑边,false表示不存在黑边"
)
private
Boolean
black
;
}
imgproc-server/src/main/java/com/zq/imgproc/vo/ImgVO.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
vo
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
/**
* <p>
*
* </p>
*
* @author chenhao
* @since 2023/3/7 16:01
*/
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public
class
ImgVO
{
String
id
;
String
fileName
;
String
url
;
DetectionVO
detectionRes
;
String
name
;
}
imgproc-server/src/main/java/com/zq/imgproc/vo/OptimizationReq.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
vo
;
import
lombok.Data
;
/**
* <p>
*
* </p>
*
* @author yww
* @since 2023/4/20
*/
@Data
public
class
OptimizationReq
{
private
String
fileContent
;
private
String
filename
;
}
imgproc-server/src/main/java/com/zq/imgproc/vo/OptimizationVO.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
vo
;
import
io.swagger.annotations.ApiModelProperty
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
/**
* <p>
* 图片优化结果类
* </p>
*
* @author chenhao
* @since 2023/4/20
*/
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public
class
OptimizationVO
{
@ApiModelProperty
(
"base64图片"
)
private
String
fileContent
;
@ApiModelProperty
(
"文件名称"
)
private
String
filename
;
@ApiModelProperty
(
"是否经过亮度调整"
)
private
boolean
isBrightness
;
@ApiModelProperty
(
"图片原始平均亮度值"
)
private
double
originalBrightnessVal
;
@ApiModelProperty
(
"图片修正后的平均亮度值"
)
private
double
brightnessVal
;
@ApiModelProperty
(
"是否经过清晰度调整"
)
private
boolean
isClarity
;
@ApiModelProperty
(
"图片原始清晰度值"
)
private
double
originalClarityVal
;
@ApiModelProperty
(
"图片清晰度调整过后的清晰度值"
)
private
double
clarityVal
;
@ApiModelProperty
(
"是否经过黑边处理"
)
private
boolean
isRemoveBlack
;
@ApiModelProperty
(
"图片纠偏的角度,纠偏出错返回-1"
)
private
double
deskewAngel
;
@ApiModelProperty
(
"图片是否经过弯曲矫正"
)
private
boolean
isCorrect
;
}
imgproc-server/src/main/java/com/zq/imgproc/vo/RotateReq.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
vo
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.util.List
;
/**
* <p>
* 图片旋转
* </p>
*
* @author chenhao
* @since 2023/3/10 17:32
*/
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public
class
RotateReq
{
/**
* 旋转角度
*/
Integer
degree
;
List
<
ImgVO
>
pathList
;
}
imgproc-server/src/main/java/com/zq/imgproc/vo/SettingVO.java
0 → 100644
View file @
003b7634
package
com
.
zq
.
imgproc
.
vo
;
import
io.swagger.annotations.ApiModelProperty
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
/**
* <p>
* 亮度和清晰度指标设置
* </p>
*
* @author chenhao
* @since 2023/3/10 17:03
*/
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public
class
SettingVO
{
@ApiModelProperty
(
"亮度值起始范围"
)
private
double
startValue
;
@ApiModelProperty
(
"亮度值结束范围"
)
private
double
endValue
;
@ApiModelProperty
(
"图片的清晰度指标,值越大越清晰"
)
private
double
clarity
;
}
imgproc-server/src/main/resources/application.yml
View file @
003b7634
...
@@ -78,7 +78,17 @@ mybatis-plus:
...
@@ -78,7 +78,17 @@ mybatis-plus:
ip
:
ip
:
local-parsing
:
true
local-parsing
:
true
#imgconfig:
# opencv: /opt/services/tianjin-backend/lib/opencv_java460.so
# deskew: /opt/services/tianjin-backend/lib/Deskew/Bin/deskew
# deskewpy: /opt/services/tianjin-backend/lib/correct.py
#imgconfig:
# opencv: /opt/tianjin/lib/opencv_java460.so
# deskew: /opt/tianjin/lib/Deskew/Bin/deskew
# deskewpy: /opt/tianjin/lib/correct.py
imgconfig
:
imgconfig
:
opencv
:
/opt/services/tianjin-backend/lib/opencv_java460.so
opencv
:
D:/project/image-backend/config/lib/opencv_java460.dll
deskew
:
/opt/services/tianjin-backend/lib/Deskew/Bin/deskew
deskew
:
C:/Users/11419/Desktop/Deskew/Bin/deskew.exe
deskewpy
:
/opt/services/tianjin-backend
/lib/correct.py
deskewpy
:
D:/project/imgproc
/lib/correct.py
imgproc-server/src/main/resources/mapper/ImageDetectionMapper.xml
0 → 100644
View file @
003b7634
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace=
"com.zq.imgproc.dao.ImageDetectionDao"
>
<select
id=
"queryPageList"
resultType=
"com.zq.imgproc.entity.ImageDetection"
>
SELECT *
FROM image_detection AS detection
<where>
<if
test=
"req.nickName != null and req.nickName != ''"
>
AND detection.nick_name like concat('%', #{req.nickName}, '%')
</if>
<if
test=
"req.imgName != null and req.imgName != ''"
>
AND detection.img_name like concat('%', #{req.imgName}, '%')
</if>
<if
test=
"req.fileName != null and req.fileName != ''"
>
AND detection.file_name like concat('%', #{req.fileName}, '%')
</if>
<if
test=
"req.startTime != null and req.startTime != ''"
>
AND detection.upload_time
>
= #{req.startTime}
</if>
<if
test=
"req.endTime != null and req.endTime != ''"
>
AND detection.upload_time
<
= #{req.endTime}
</if>
</where>
</select>
<insert
id=
"insertBatch"
parameterType=
"java.util.List"
>
insert into image_detection (user_id, nick_name, img_name, file_name, file_url,
size, width_resolution, height_resolution, dpi, clarity, bend, brightness,
deskew_angel, black, qualified, upload_time)
values
<foreach
collection=
"list"
item=
"item"
separator=
","
>
(#{item.userId}, #{item.nickName}, #{item.imgName}, #{item.fileName},
#{item.fileUrl}, #{item.size}, #{item.widthResolution}, #{item.heightResolution},
#{item.dpi}, #{item.clarity}, #{item.bend}, #{item.brightness},
#{item.deskewAngel}, #{item.black}, #{item.qualified}, #{item.uploadTime})
</foreach>
</insert>
</mapper>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment