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
a0252026
Commit
a0252026
authored
Nov 28, 2023
by
陈皓
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
init
parent
7f1d964c
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
39 changed files
with
144 additions
and
3110 deletions
+144
-3110
file-server/src/main/resources/bootstrap.yml
+1
-1
gateway-server/src/main/resources/application.yml
+4
-0
gateway-server/src/main/resources/bootstrap.yml
+1
-1
imgproc-server/pom.xml
+46
-80
imgproc-server/src/main/java/com/zq/imgproc/ImgprocApplication.java
+6
-2
imgproc-server/src/main/java/com/zq/imgproc/config/InitConfig.java
+0
-26
imgproc-server/src/main/java/com/zq/imgproc/constant/Threshold.java
+0
-45
imgproc-server/src/main/java/com/zq/imgproc/controller/ApiController.java
+0
-162
imgproc-server/src/main/java/com/zq/imgproc/controller/FileController.java
+0
-51
imgproc-server/src/main/java/com/zq/imgproc/controller/ImgProcController.java
+0
-211
imgproc-server/src/main/java/com/zq/imgproc/exception/BusinessException.java
+0
-32
imgproc-server/src/main/java/com/zq/imgproc/server/ImgProcService.java
+0
-0
imgproc-server/src/main/java/com/zq/imgproc/utils/AssertUtils.java
+0
-279
imgproc-server/src/main/java/com/zq/imgproc/utils/BendUtil.java
+0
-82
imgproc-server/src/main/java/com/zq/imgproc/utils/DecompressUtil.java
+0
-154
imgproc-server/src/main/java/com/zq/imgproc/utils/DemoUtil.java
+0
-64
imgproc-server/src/main/java/com/zq/imgproc/utils/Deskew.java
+0
-165
imgproc-server/src/main/java/com/zq/imgproc/utils/ImageCorrectionUtil.java
+0
-168
imgproc-server/src/main/java/com/zq/imgproc/utils/ImageUtil.java
+0
-0
imgproc-server/src/main/java/com/zq/imgproc/utils/RemoveBlackUtil.java
+0
-210
imgproc-server/src/main/java/com/zq/imgproc/utils/RemoveBlackUtil2.java
+0
-142
imgproc-server/src/main/java/com/zq/imgproc/utils/ResultVo.java
+0
-89
imgproc-server/src/main/java/com/zq/imgproc/utils/Test2.java
+0
-170
imgproc-server/src/main/java/com/zq/imgproc/utils/TestUtil.java
+0
-166
imgproc-server/src/main/java/com/zq/imgproc/utils/UploadUtils.java
+0
-45
imgproc-server/src/main/java/com/zq/imgproc/utils/UuidUtils.java
+0
-61
imgproc-server/src/main/java/com/zq/imgproc/utils/ValidateUtil.java
+0
-320
imgproc-server/src/main/java/com/zq/imgproc/vo/BendResult.java
+0
-39
imgproc-server/src/main/java/com/zq/imgproc/vo/CompressReq.java
+0
-22
imgproc-server/src/main/java/com/zq/imgproc/vo/DetectionDTO.java
+0
-43
imgproc-server/src/main/java/com/zq/imgproc/vo/DetectionResVo.java
+0
-42
imgproc-server/src/main/java/com/zq/imgproc/vo/DetectionVO.java
+0
-47
imgproc-server/src/main/java/com/zq/imgproc/vo/ImgVO.java
+0
-30
imgproc-server/src/main/java/com/zq/imgproc/vo/OptimizationReq.java
+0
-20
imgproc-server/src/main/java/com/zq/imgproc/vo/OptimizationVO.java
+0
-56
imgproc-server/src/main/java/com/zq/imgproc/vo/RotateReq.java
+0
-31
imgproc-server/src/main/java/com/zq/imgproc/vo/SettingVO.java
+0
-32
imgproc-server/src/main/resources/application.yml
+68
-18
imgproc-server/src/main/resources/bootstrap.yml
+18
-4
No files found.
file-server/src/main/resources/bootstrap.yml
View file @
a0252026
...
...
@@ -9,7 +9,7 @@ spring:
enabled
:
true
service-id
:
CONFIG-SERVER
username
:
admin
password
:
123456
password
:
GXfy2022
eureka
:
instance
:
...
...
gateway-server/src/main/resources/application.yml
View file @
a0252026
...
...
@@ -37,4 +37,8 @@ spring:
uri
:
lb://USER-SERVER
predicates
:
-
Path=/user/**
-
id
:
imgproc
uri
:
lb://IMGPROC-SERVER
predicates
:
-
Path=/imgproc/**
gateway-server/src/main/resources/bootstrap.yml
View file @
a0252026
...
...
@@ -9,7 +9,7 @@ spring:
enabled
:
true
service-id
:
CONFIG-SERVER
username
:
admin
password
:
123456
password
:
GXfy2022
eureka
:
instance
:
...
...
imgproc-server/pom.xml
View file @
a0252026
...
...
@@ -2,30 +2,42 @@
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>
4.0.0
</modelVersion>
<parent>
<groupId>
com.zq
</groupId>
<artifactId>
image-backend
</artifactId>
<version>
1.0.0
</version>
</parent>
<modelVersion>
4.0.0
</modelVersion>
<artifactId>
imgproc-server
</artifactId>
<version>
1.0.0
</version>
<name>
imgproc-server
</name>
<description>
imgproc-server
</description>
<properties>
<java.version>
1.8
</java.version>
<maven.compiler.source>
8
</maven.compiler.source>
<maven.compiler.target>
8
</maven.compiler.target>
<project.build.sourceEncoding>
UTF-8
</project.build.sourceEncoding>
<project.reporting.outputEncoding>
UTF-8
</project.reporting.outputEncoding>
<spring-boot.version>
2.4.2
</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>
com.zq
</groupId>
<artifactId>
img-common-utils
</artifactId>
<version>
1.0.0
</version>
</dependency>
<dependency>
<groupId>
com.zq
</groupId>
<artifactId>
logging-server
</artifactId>
<version>
1.0.0
</version>
</dependency>
<dependency>
<groupId>
org.springframework.cloud
</groupId>
<artifactId>
spring-cloud-starter-netflix-eureka-client
</artifactId>
</dependency>
<!--Spring boot 安全框架-->
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-security
</artifactId>
</dependency>
<!-- 连接配置中心 -->
<dependency>
<groupId>
org.springframework.cloud
</groupId>
<artifactId>
spring-cloud-starter-config
</artifactId>
...
...
@@ -41,86 +53,33 @@
<artifactId>
spring-boot-starter-test
</artifactId>
<scope>
test
</scope>
</dependency>
<!-- 远程调用cloud feign -->
<dependency>
<groupId>
org.apache.commons
</groupId>
<artifactId>
commons-io
</artifactId>
<version>
1.3.2
</version>
</dependency>
<!-- OpenCv(Linux) -->
<!-- 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>
<groupId>
org.springframework.cloud
</groupId>
<artifactId>
spring-cloud-starter-openfeign
</artifactId>
</dependency>
<!--Spring boot Redis-->
<dependency>
<groupId>
org.tukaani
</groupId>
<artifactId>
xz
</artifactId>
<version>
1.9
</version>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-data-redis
</artifactId>
</dependency>
<!--Mybatis plus-->
<dependency>
<groupId>
c
n.hutool
</groupId>
<artifactId>
hutool-all
</artifactId>
<version>
5.8.19
</version>
<groupId>
c
om.baomidou
</groupId>
<artifactId>
mybatis-plus-boot-starter
</artifactId>
<version>
${mybatis.plus.version}
</version>
</dependency>
<!-- druid数据源驱动 -->
<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>
<artifactId>
druid-spring-boot-starter
</artifactId>
<version>
${alibaba.druid.version}
</version>
</dependency>
<!-- mysql -->
<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>
<groupId>
mysql
</groupId>
<artifactId>
mysql-connector-java
</artifactId>
<scope>
runtime
</scope>
</dependency>
</dependencies>
...
...
@@ -129,16 +88,22 @@
<plugin>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-maven-plugin
</artifactId>
<configuration>
<includeSystemScope>
true
</includeSystemScope>
</configuration>
</plugin>
</plugins>
<!-- 使用@profiles.active@需要添加以下内容 -->
<resources>
<resource>
<directory>
src/main/resources
</directory>
<excludes>
<exclude>
**/*.jar
</exclude>
</excludes>
<!--开启过滤,用指定的参数替换directory下的文件中的参数-->
<filtering>
true
</filtering>
</resource>
</resources>
</build>
</project>
</project>
\ No newline at end of file
imgproc-server/src/main/java/com/zq/imgproc/ImgprocApplication.java
View file @
a0252026
package
com
.
zq
.
imgproc
;
import
org.mybatis.spring.annotation.MapperScan
;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.autoconfigure.SpringBootApplication
;
import
org.springframework.cloud.client.discovery.EnableDiscoveryClient
;
import
org.springframework.cloud.openfeign.EnableFeignClients
;
/**
* @author
wilmiam
* @author
chenhao
* @since 2022/10/13 11:11
*/
@EnableFeignClients
@MapperScan
({
"com.zq.imgproc.dao"
,
"com.zq.logging.mapper"
})
@EnableDiscoveryClient
@SpringBootApplication
@SpringBootApplication
(
scanBasePackages
=
{
"com.zq.imgproc"
,
"com.zq.logging"
,
"com.zq.common.config"
})
public
class
ImgprocApplication
{
public
static
void
main
(
String
[]
args
)
{
...
...
imgproc-server/src/main/java/com/zq/imgproc/config/InitConfig.java
deleted
100644 → 0
View file @
7f1d964c
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 wilmiam
* @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/constant/Threshold.java
deleted
100644 → 0
View file @
7f1d964c
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
deleted
100644 → 0
View file @
7f1d964c
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.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
(
"测试"
)
@PostMapping
(
"/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/FileController.java
deleted
100644 → 0
View file @
7f1d964c
package
com
.
zq
.
imgproc
.
controller
;
import
cn.hutool.core.util.URLUtil
;
import
com.zq.imgproc.utils.AssertUtils
;
import
io.swagger.annotations.Api
;
import
org.springframework.core.io.FileSystemResource
;
import
org.springframework.core.io.Resource
;
import
org.springframework.http.ContentDisposition
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.web.bind.annotation.CrossOrigin
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
javax.servlet.http.HttpServletRequest
;
import
java.io.File
;
/**
* <p>
*
* </p>
*
* @author zq
* @since 2023/11/15
*/
@Api
(
tags
=
"访问文件"
)
@RestController
@CrossOrigin
@RequestMapping
(
"/"
)
public
class
FileController
{
@GetMapping
(
value
=
"/file/**"
)
public
ResponseEntity
<
Resource
>
archive
(
HttpServletRequest
request
)
{
String
requestURI
=
request
.
getRequestURI
();
requestURI
=
URLUtil
.
decode
(
requestURI
);
File
file
=
new
File
(
requestURI
);
AssertUtils
.
isTrue
(
file
.
exists
(),
"访问文件不存在"
);
String
contentDisposition
=
ContentDisposition
.
builder
(
"attachment"
)
.
filename
(
requestURI
)
.
build
().
toString
();
return
ResponseEntity
.
ok
()
.
header
(
HttpHeaders
.
CONTENT_DISPOSITION
,
contentDisposition
)
.
contentType
(
MediaType
.
APPLICATION_OCTET_STREAM
)
.
body
(
new
FileSystemResource
(
file
));
}
}
imgproc-server/src/main/java/com/zq/imgproc/controller/ImgProcController.java
deleted
100644 → 0
View file @
7f1d964c
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.imgproc.constant.Threshold
;
import
com.zq.imgproc.server.ImgProcService
;
import
com.zq.imgproc.utils.AssertUtils
;
import
com.zq.imgproc.utils.DecompressUtil
;
import
com.zq.imgproc.utils.ImageUtil
;
import
com.zq.imgproc.utils.ResultVo
;
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.IOException
;
import
java.io.InputStream
;
import
java.nio.charset.StandardCharsets
;
import
java.time.Duration
;
import
java.util.ArrayList
;
import
java.util.List
;
/**
* <p>
* 图片检测接口
* </p>
*
* @author chenhao
* @since 2022/10/24 14:58
*/
@Api
(
tags
=
"图片检测接口"
)
@RequestMapping
(
"/imgproc"
)
@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
(
"文件解压"
)
@PostMapping
(
"/decompress"
)
public
ResultVo
<?>
decompress
(
@RequestPart
MultipartFile
[]
file
)
throws
Exception
{
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
));
}
else
{
String
url
=
ImageUtil
.
saveTempFile
(
one
);
imgs
.
add
(
ImgVO
.
builder
().
fileName
(
one
.
getOriginalFilename
()).
url
(
url
).
build
());
}
}
return
ResultVo
.
success
(
imgs
);
}
@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
(
"获取配置"
)
@GetMapping
(
"/getSetting"
)
public
ResultVo
<?>
getSetting
()
{
Double
temp1
=
cache
.
getIfPresent
(
Threshold
.
START_VALUE
.
getKey
());
Double
temp2
=
cache
.
getIfPresent
(
Threshold
.
END_VALUE
.
getKey
());
Double
temp3
=
cache
.
getIfPresent
(
Threshold
.
CLARITY
.
getKey
());
double
start
=
temp1
==
null
?
Threshold
.
START_VALUE
.
getValue
()
:
temp1
;
double
end
=
temp2
==
null
?
Threshold
.
END_VALUE
.
getValue
()
:
temp2
;
double
clarity
=
temp3
==
null
?
Threshold
.
CLARITY
.
getValue
()
:
temp3
;
return
ResultVo
.
success
(
SettingVO
.
builder
().
startValue
(
start
).
endValue
(
end
).
clarity
(
clarity
).
build
());
}
@ApiOperation
(
"设置配置"
)
@PostMapping
(
"/setSetting"
)
public
ResultVo
<?>
setSetting
(
@RequestBody
SettingVO
setting
)
{
if
(
setting
==
null
)
{
return
ResultVo
.
fail
(
"配置不能为空!"
);
}
cache
.
put
(
Threshold
.
START_VALUE
.
getKey
(),
setting
.
getStartValue
());
cache
.
put
(
Threshold
.
END_VALUE
.
getKey
(),
setting
.
getEndValue
());
cache
.
put
(
Threshold
.
CLARITY
.
getKey
(),
setting
.
getClarity
());
return
ResultVo
.
success
();
}
@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/exception/BusinessException.java
deleted
100644 → 0
View file @
7f1d964c
package
com
.
zq
.
imgproc
.
exception
;
/**
* 业务错误
*
* @author wilmiam
* @since 2021-07-09 17:58
*/
public
class
BusinessException
extends
RuntimeException
{
private
int
code
=
400
;
public
BusinessException
(
String
message
)
{
super
(
message
);
}
public
BusinessException
(
int
code
,
String
message
)
{
super
(
message
);
this
.
code
=
code
;
}
public
BusinessException
(
int
code
,
String
message
,
Throwable
cause
)
{
super
(
message
,
cause
);
this
.
code
=
code
;
}
public
int
getCode
()
{
return
code
;
}
}
\ No newline at end of file
imgproc-server/src/main/java/com/zq/imgproc/server/ImgProcService.java
deleted
100644 → 0
View file @
7f1d964c
This diff is collapsed.
Click to expand it.
imgproc-server/src/main/java/com/zq/imgproc/utils/AssertUtils.java
deleted
100644 → 0
View file @
7f1d964c
package
com
.
zq
.
imgproc
.
utils
;
import
cn.hutool.core.util.StrUtil
;
import
com.zq.imgproc.exception.BusinessException
;
import
java.util.Arrays
;
import
java.util.Collection
;
import
java.util.Map
;
/**
* 断言验证帮助类
*
* @author wilmiam
* @since 2018-04-03
*/
@SuppressWarnings
(
"all"
)
public
final
class
AssertUtils
{
private
static
final
String
[]
IMG_EXTS
=
{
"png"
,
"jpg"
,
"jpeg"
};
/**
* Don't let anyone instantiate this class
*/
private
AssertUtils
()
{
}
/**
* 判断给定的文件名后缀是否为图片
*
* @param ext 文件名后缀, 不带点
* @param errMsg 错误信息
*/
public
static
void
isImgExt
(
String
ext
,
String
errMsg
)
{
isImgExt
(
ext
,
400
,
errMsg
);
}
/**
* 判断给定的文件名后缀是否为图片
*
* @param ext 文件名后缀, 不带点
* @param errCode 断言失败的错误代码
* @param errMsg 错误信息
*/
public
static
void
isImgExt
(
String
ext
,
int
errCode
,
String
errMsg
)
{
if
(
StrUtil
.
isBlank
(
ext
)
||
Arrays
.
stream
(
IMG_EXTS
).
noneMatch
(
img
->
img
.
equalsIgnoreCase
(
ext
)))
{
throw
new
BusinessException
(
errCode
,
errMsg
);
}
}
/**
* UnifiedExceptionHandler
* 判断一个布尔表达式, 若表达式为{@code true}则抛出指定错误信息的{@code BusinessException}.
*
* @param expression 布尔表达式
* @param message 断言失败时的错误信息
* @throws BusinessException
*/
public
static
void
notTrue
(
boolean
expression
,
String
message
)
throws
BusinessException
{
notTrue
(
expression
,
400
,
message
);
}
/**
* 判断一个布尔表达式, 若表达式为{@code true}则抛出指定错误信息的{@code BusinessException}.
*
* @param expression 布尔表达式
* @param errCode 断言失败时的错误代码
* @param message 断言失败时的错误信息
* @throws BusinessException
*/
public
static
void
notTrue
(
boolean
expression
,
int
errCode
,
String
message
)
throws
BusinessException
{
if
(
expression
)
{
throw
new
BusinessException
(
errCode
,
message
);
}
}
/**
* 判断一个布尔表达式, 若表达式为{@code false}则抛出指定错误信息的{@code BusinessException}.
*
* @param expression 布尔表达式
* @param message 断言失败时的错误信息
* @throws BusinessException
*/
public
static
void
isTrue
(
boolean
expression
,
String
message
)
throws
BusinessException
{
isTrue
(
expression
,
400
,
message
);
}
/**
* 判断一个布尔表达式, 若表达式为{@code false}则抛出指定错误信息的{@code BusinessException}.
*
* @param expression 布尔表达式
* @param errCode 断言失败时的错误代码
* @param message 断言失败时的错误信息
* @throws BusinessException
*/
public
static
void
isTrue
(
boolean
expression
,
int
errCode
,
String
message
)
throws
BusinessException
{
if
(!
expression
)
{
throw
new
BusinessException
(
errCode
,
message
);
}
}
/**
* 如果对象为{@code null}, 则抛出异常
*
* @param object 要判断的对象
* @throws BusinessException
*/
public
static
void
notNull
(
Object
object
)
throws
BusinessException
{
notNull
(
object
,
"不能处理空对象"
);
}
/**
* 如果对象为{@code null}, 则抛出异常
*
* @param object 要判断的对象
* @param message 断言失败时的错误信息
* @throws BusinessException
*/
public
static
void
notNull
(
Object
object
,
String
message
)
throws
BusinessException
{
notNull
(
object
,
400
,
message
);
}
/**
* 如果对象为{@code null}, 则抛出异常
*
* @param object 要判断的对象
* @param errCode 断言失败时的错误代码
* @param errMsg 断言失败时的错误信息
* @throws BusinessException
*/
public
static
void
notNull
(
Object
object
,
int
errCode
,
String
errMsg
)
throws
BusinessException
{
if
(
object
==
null
)
{
throw
new
BusinessException
(
errCode
,
errMsg
);
}
}
/**
* 如果字符串为{@code null}、空字符串或仅包含空白字符, 则抛出异常
*
* @param text 要进行检查的字符串
* @throws BusinessException
*/
public
static
void
hasText
(
String
text
)
throws
BusinessException
{
hasText
(
text
,
400
,
"参数不能为空字符串"
);
}
/**
* 如果字符串为{@code null}、空字符串或仅包含空白字符, 则抛出异常
*
* @param text 要进行检查的字符串
* @param message 断言失败时的错误信息
* @throws BusinessException
*/
public
static
void
hasText
(
String
text
,
String
message
)
throws
BusinessException
{
hasText
(
text
,
400
,
message
);
}
/**
* 如果字符串为{@code null}、空字符串或仅包含空白字符, 则抛出异常
*
* @param text 要进行检查的字符串
* @param errCode 断言失败时的错误代码
* @param errMsg 错误信息
* @throws BusinessException
*/
public
static
void
hasText
(
String
text
,
int
errCode
,
String
errMsg
)
throws
BusinessException
{
if
(
StrUtil
.
isBlank
(
text
))
{
throw
new
BusinessException
(
errCode
,
errMsg
);
}
}
/**
* 如果数组为{@code null}或长度为0, 则抛出异常
*
* @param array 要进行检查的数组
* @param message 断言失败时的错误信息
* @param <T> 数组的数据类型
* @throws BusinessException
*/
public
static
<
T
>
void
notEmpty
(
T
[]
array
,
String
message
)
throws
BusinessException
{
notEmpty
(
array
,
400
,
message
);
}
/**
* 如果数组为{@code null}或长度为0, 则抛出异常
*
* @param array 要进行检查的数组
* @param errCode 断言失败时的错误代码
* @param errMsg 错误信息
* @param <T> 数组的数据类型
* @throws BusinessException
*/
public
static
<
T
>
void
notEmpty
(
T
[]
array
,
int
errCode
,
String
errMsg
)
throws
BusinessException
{
if
(
array
==
null
||
array
.
length
==
0
)
{
throw
new
BusinessException
(
errCode
,
errMsg
);
}
}
/**
* 如果数组里包含有{@code null}的元素, 则抛出异常. 注意: 若数组本身为{@code null}则不会进行处理, 直接返回
*
* @param array 要进行检查的数组
* @param message 断言失败时的错误信息
* @param <T> 数组的数据类型
* @throws BusinessException
*/
public
static
<
T
>
void
noNullElements
(
T
[]
array
,
String
message
)
throws
BusinessException
{
noNullElements
(
array
,
400
,
message
);
}
/**
* 如果数组里包含有{@code null}的元素, 则抛出异常. 注意: 若数组本身为{@code null}则不会进行处理, 直接返回
*
* @param array 要进行检查的数组
* @param errCode 断言失败时的错误代码
* @param errMsg 错误信息
* @param <T> 数组的数据类型
* @throws BusinessException
*/
public
static
<
T
>
void
noNullElements
(
T
[]
array
,
int
errCode
,
String
errMsg
)
throws
BusinessException
{
if
(
array
!=
null
)
{
for
(
T
element
:
array
)
{
if
(
element
==
null
)
{
throw
new
BusinessException
(
errCode
,
errMsg
);
}
}
}
}
/**
* 如果集合为{@code null},或者不包含任何元素,则抛出异常
*
* @param collection 要进行检查的集合
* @param message 断言失败时的错误信息
* @throws BusinessException
*/
public
static
void
notEmpty
(
Collection
<?>
collection
,
String
message
)
throws
BusinessException
{
notEmpty
(
collection
,
400
,
message
);
}
/**
* 如果集合为{@code null},或者不包含任何元素,则抛出异常
*
* @param collection 要进行检查的集合
* @param errCode 断言失败时的错误代码
* @param errMsg 错误信息
* @throws BusinessException
*/
public
static
void
notEmpty
(
Collection
<?>
collection
,
int
errCode
,
String
errMsg
)
throws
BusinessException
{
if
(
collection
==
null
||
collection
.
isEmpty
())
{
throw
new
BusinessException
(
errCode
,
errMsg
);
}
}
/**
* 如果键值对为{@code null},或者不包含任何键值,则抛出异常
*
* @param map 要进行检查的键值对
* @param message 断言失败时的错误信息
* @throws BusinessException
*/
public
static
void
notEmpty
(
Map
<?,
?>
map
,
String
message
)
throws
BusinessException
{
notEmpty
(
map
,
400
,
message
);
}
/**
* 如果键值对为{@code null},或者不包含任何键值,则抛出异常
*
* @param map 要进行检查的键值对
* @param errCode 断言失败时的错误代码
* @param errMsg 错误信息
* @throws BusinessException
*/
public
static
void
notEmpty
(
Map
<?,
?>
map
,
int
errCode
,
String
errMsg
)
throws
BusinessException
{
if
(
map
==
null
||
map
.
isEmpty
())
{
throw
new
BusinessException
(
errCode
,
errMsg
);
}
}
}
imgproc-server/src/main/java/com/zq/imgproc/utils/BendUtil.java
deleted
100644 → 0
View file @
7f1d964c
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.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
deleted
100644 → 0
View file @
7f1d964c
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.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
)
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
).
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
deleted
100644 → 0
View file @
7f1d964c
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
deleted
100644 → 0
View file @
7f1d964c
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
;
import
static
org
.
opencv
.
imgproc
.
Imgproc
.
LINE_AA
;
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
deleted
100644 → 0
View file @
7f1d964c
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
deleted
100644 → 0
View file @
7f1d964c
This diff is collapsed.
Click to expand it.
imgproc-server/src/main/java/com/zq/imgproc/utils/RemoveBlackUtil.java
deleted
100644 → 0
View file @
7f1d964c
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
deleted
100644 → 0
View file @
7f1d964c
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/ResultVo.java
deleted
100644 → 0
View file @
7f1d964c
package
com
.
zq
.
imgproc
.
utils
;
import
com.fasterxml.jackson.annotation.JsonIgnoreProperties
;
import
com.fasterxml.jackson.annotation.JsonInclude
;
import
io.swagger.annotations.ApiModel
;
import
io.swagger.annotations.ApiModelProperty
;
import
java.io.Serializable
;
/**
* 统一的接口响应信息
*
* @author wilmiam
* @since 2021-07-09 17:45
*/
@ApiModel
(
"API响应消息"
)
@JsonInclude
(
JsonInclude
.
Include
.
NON_NULL
)
@JsonIgnoreProperties
(
ignoreUnknown
=
true
)
public
class
ResultVo
<
T
>
implements
Serializable
{
@ApiModelProperty
(
value
=
"成功标记"
,
example
=
"true"
)
private
boolean
success
;
@ApiModelProperty
(
"错误码"
)
@JsonInclude
(
JsonInclude
.
Include
.
NON_DEFAULT
)
private
int
errCode
;
@ApiModelProperty
(
"错误信息"
)
private
String
errMsg
;
@ApiModelProperty
(
"响应的数据"
)
private
T
data
;
public
static
ResultVo
success
()
{
return
success
(
null
);
}
public
static
<
E
>
ResultVo
<
E
>
success
(
E
data
)
{
ResultVo
<
E
>
result
=
new
ResultVo
<>();
result
.
setSuccess
(
true
);
result
.
setData
(
data
);
return
result
;
}
public
static
ResultVo
fail
(
String
errMsg
)
{
return
fail
(
500
,
errMsg
);
}
public
static
ResultVo
fail
(
int
errCode
,
String
errMsg
)
{
ResultVo
result
=
new
ResultVo
<>();
result
.
setSuccess
(
false
);
result
.
setErrCode
(
errCode
);
result
.
setErrMsg
(
errMsg
);
return
result
;
}
public
boolean
isSuccess
()
{
return
success
;
}
public
void
setSuccess
(
boolean
success
)
{
this
.
success
=
success
;
}
public
int
getErrCode
()
{
return
errCode
;
}
public
void
setErrCode
(
int
errCode
)
{
this
.
errCode
=
errCode
;
}
public
String
getErrMsg
()
{
return
errMsg
;
}
public
void
setErrMsg
(
String
errMsg
)
{
this
.
errMsg
=
errMsg
;
}
public
T
getData
()
{
return
data
;
}
public
void
setData
(
T
data
)
{
this
.
data
=
data
;
}
}
imgproc-server/src/main/java/com/zq/imgproc/utils/Test2.java
deleted
100644 → 0
View file @
7f1d964c
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
deleted
100644 → 0
View file @
7f1d964c
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
deleted
100644 → 0
View file @
7f1d964c
package
com
.
zq
.
imgproc
.
utils
;
import
cn.hutool.core.io.FileUtil
;
import
com.zq.imgproc.exception.BusinessException
;
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/utils/UuidUtils.java
deleted
100644 → 0
View file @
7f1d964c
package
com
.
zq
.
imgproc
.
utils
;
import
java.util.UUID
;
/**
* Utility class that handles the uuid stuff.
*
* @author wilmiam
* @since 2021-07-09 18:05
*/
public
class
UuidUtils
{
private
static
final
String
URN_UUID_REGEX
=
"^[a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12}$"
;
private
static
final
String
NODASH_UUID_REGEX
=
"^[a-f0-9]{32}$"
;
/**
* Don't let anyone instantiate this class
*/
private
UuidUtils
()
{
}
/**
* 返回一个随机的带有分隔符"-"的36位UUID字符串
*
* @return
*/
public
static
String
uuid
()
{
return
UUID
.
randomUUID
().
toString
();
}
/**
* 返回一个随机的没有分隔符"-"的32位UUID字符串
*
* @return
*/
public
static
String
uuidNoDash
()
{
return
uuid
().
replaceAll
(
"-"
,
""
);
}
/**
* 判断一个字符串是否是一个UUID字符串
*
* @param str 要进行判断的字符串
* @return
*/
public
static
boolean
isUuid
(
String
str
)
{
return
ValidateUtil
.
isNotBlank
(
str
)
&&
str
.
matches
(
URN_UUID_REGEX
);
}
/**
* 判断一个字符串是否是一个没有分隔符的uuid字符串
*
* @param str 要进行判断的字符串
* @return
*/
public
static
boolean
isNoDashUuid
(
String
str
)
{
return
ValidateUtil
.
isNotBlank
(
str
)
&&
str
.
matches
(
NODASH_UUID_REGEX
);
}
}
imgproc-server/src/main/java/com/zq/imgproc/utils/ValidateUtil.java
deleted
100644 → 0
View file @
7f1d964c
This diff is collapsed.
Click to expand it.
imgproc-server/src/main/java/com/zq/imgproc/vo/BendResult.java
deleted
100644 → 0
View file @
7f1d964c
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
deleted
100644 → 0
View file @
7f1d964c
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
deleted
100644 → 0
View file @
7f1d964c
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/DetectionResVo.java
deleted
100644 → 0
View file @
7f1d964c
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
deleted
100644 → 0
View file @
7f1d964c
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
deleted
100644 → 0
View file @
7f1d964c
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
;
}
imgproc-server/src/main/java/com/zq/imgproc/vo/OptimizationReq.java
deleted
100644 → 0
View file @
7f1d964c
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
deleted
100644 → 0
View file @
7f1d964c
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
deleted
100644 → 0
View file @
7f1d964c
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
deleted
100644 → 0
View file @
7f1d964c
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 @
a0252026
server
:
port
:
8900
port
:
9999
# 配置数据源
spring
:
application
:
name
:
IMGPROC-SERVER
jackson
:
date-format
:
yyyy-MM-dd HH:mm:ss
time-zone
:
GMT+8
mvc
:
format
:
date-time
:
yyyy-MM-dd HH:mm:ss
servlet
:
multipart
:
max-file-size
:
100MB
max-request-size
:
150MB
freemarker
:
check-template-location
:
false
redis
:
# 数据库索引
database
:
0
host
:
${redis.url}
port
:
${redis.port}
password
:
# 连接超时时间
timeout
:
5000
datasource
:
druid
:
db-type
:
com.alibaba.druid.pool.DruidDataSource
driver-class-name
:
${db.cloud.driver-class-name}
username
:
${db.cloud.username}
password
:
${db.cloud.password}
url
:
${db.cloud.url.cloud}
# 初始连接数
initial-size
:
5
# 最小连接数
min-idle
:
10
# 最大连接数
max-active
:
20
# 超时时间(以秒数为单位)
remove-abandoned-timeout
:
180
# 获取连接超时时间
max-wait
:
5000
# 连接有效性检测时间
time-between-eviction-runs-millis
:
60000
# 连接在池中最小生存的时间
min-evictable-idle-time-millis
:
300000
# 连接在池中最大生存的时间
max-evictable-idle-time-millis
:
900000
# 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除
test-while-idle
:
true
# 指明是否在从池中取出连接前进行检验,如果检验失败, 则从池中去除连接并尝试取出另一个
test-on-borrow
:
true
# 是否在归还到池中前进行检验
test-on-return
:
false
# 检测连接是否有效
validation-query
:
select 1
# 配置监控统计
webStatFilter
:
enabled
:
true
stat-view-servlet
:
enabled
:
true
url-pattern
:
/admin/druid/*
reset-enable
:
false
allow
:
"
"
filter
:
stat
:
enabled
:
true
# 记录慢SQL
log-slow-sql
:
true
slow-sql-millis
:
1000
merge-sql
:
true
wall
:
config
:
multi-statement-allow
:
true
# mybatis plus 配置
mybatis-plus
:
global-config
:
db-config
:
where-strategy
:
not_empty
update-strategy
:
not_empty
# IP 本地解析
ip
:
...
...
@@ -22,13 +82,3 @@ 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:
# opencv: D:/project/imgproc/lib/opencv_java460.dll
# deskew: C:/Users/11419/Desktop/Deskew/Bin/deskew.exe
# deskewpy: D:/project/imgproc/lib/correct.py
imgproc-server/src/main/resources/bootstrap.yml
View file @
a0252026
...
...
@@ -8,13 +8,27 @@ spring:
discovery
:
enabled
:
true
service-id
:
CONFIG-SERVER
username
:
admin
password
:
123456
eureka
:
instance
:
prefer-ip-address
:
true
lease-renewal-interval-in-seconds
:
2
#
每间隔1s,向服务端发送一次心跳,证明自己依然"存活"
lease-expiration-duration-in-seconds
:
6
#告诉服务端
,如果我2s之内没有给你发心跳,就代表我"死"了,将我踢出掉。
lease-renewal-interval-in-seconds
:
2
#
向服务端发送心跳间隔
lease-expiration-duration-in-seconds
:
6
#告诉服务端
多少秒没收到心跳将我踢出掉
instance-id
:
${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
client
:
service-url
:
defaultZone
:
@
eureka.server.url@
registry-fetch-interval-seconds
:
2
#从服务端注册表中获取注册信息的时间间隔
serviceUrl
:
defaultZone
:
@
register.url@
feign
:
client
:
config
:
default
:
connect-timeout
:
2000
#连接超时时间
read-timeout
:
10000
#读超时时间
ribbon
:
# ribbon服务列表刷新间隔(单位ms)
ServerListRefreshInterval
:
2000
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