mirror of
https://gitee.com/mymagicpower/AIAS.git
synced 2024-11-29 18:58:16 +08:00
上传框选一键抠图 web 应用。
This commit is contained in:
parent
40743b88a6
commit
1f06836599
3
.gitignore
vendored
3
.gitignore
vendored
@ -77,3 +77,6 @@ archive/1_image_sdks/seg_sam2_sdk/target/
|
||||
0_tutorials/python/sam2_export/sam2-hiera-tiny/sam2-hiera-tiny_all.pt
|
||||
0_tutorials/python/sam2_export/sam2-hiera-tiny/serving.properties
|
||||
6_web_app/image_seg_sam2/ocr_backend/target/
|
||||
6_web_app/image_seg_sam2/sam2_backend/target/
|
||||
6_web_app/image_seg_sam2/sam2_ui/node_modules/
|
||||
6_web_app/iocr/ocr_backend/target/
|
||||
|
105
6_web_app/image_seg_sam2/README.md
Normal file
105
6_web_app/image_seg_sam2/README.md
Normal file
@ -0,0 +1,105 @@
|
||||
### 官网:
|
||||
[官网链接](https://www.aias.top/)
|
||||
|
||||
### 下载模型,放置于models目录
|
||||
- 链接: https://pan.baidu.com/s/1m4NAiKTDdhcTWROdkwofFg?pwd=in39
|
||||
-
|
||||
|
||||
### 框选一键抠图
|
||||
一键抠图是一种图像处理技术,旨在自动将图像中的前景对象从背景中分离出来。它可以帮助用户快速、准确地实现抠图效果,无需手动绘制边界或进行复杂的图像编辑操作。
|
||||
一键抠图的原理通常基于计算机视觉和机器学习技术。它使用深度神经网络模型,通过训练大量的图像样本,学习如何识别和分离前景对象和背景。这些模型能够理解图像中的像素信息和上下文,并根据学习到的知识进行像素级别的分割。
|
||||
|
||||
![Screenshot](https://aias-home.oss-cn-beijing.aliyuncs.com/assets/seg_all.png)
|
||||
|
||||
使用一键抠图可以带来许多实际用途,包括但不限于以下几个方面:
|
||||
1. 图像编辑:一键抠图可以用于图像编辑软件中,帮助用户轻松地将前景对象从一个图像中提取出来,并将其放置到另一个图像或背景中,实现合成效果。
|
||||
2. 广告设计:在广告设计中,一键抠图可以用于创建吸引人的广告素材。通过将产品或主题从原始照片中抠出,可以更好地突出产品或主题,并与其他元素进行组合。
|
||||
3. 虚拟背景:一键抠图可以用于视频会议或虚拟现实应用中,帮助用户实现虚拟背景效果。通过将用户的前景对象从实际背景中抠出,可以将其放置在虚拟环境中,提供更丰富的交互体验。
|
||||
4. 图像分析:一键抠图可以用于图像分析和计算机视觉任务中。通过将前景对象与背景分离,可以更好地理解和分析图像中的不同元素,如目标检测、图像分类、图像分割等。
|
||||
|
||||
SAM2(Segment Anything Model 2)是由Meta公司发布的先进图像和视频分割模型。它是Segment Anything Model(SAM)的升级版本,
|
||||
SAM是Meta的FAIR实验室之前发布的一款用于图像分割的基础模型,能够在给定提示的情况下生成高质量的对象掩模。
|
||||
SAM2模型的主要特点是其通用性和灵活性,它能够处理各种复杂的图像和视频分割任务,无论是简单的对象识别还是复杂的场景理解,SAM2都能提供准确的结果。
|
||||
这使得它在许多实际应用场景中都非常有用,例如在医疗影像分析、自动驾驶、安防监控等领域都有着广泛的应用前景。
|
||||
|
||||
当前版本包含了下面功能:
|
||||
- 1. 框选一键抠图
|
||||
- 2. 支持CPU,GPU
|
||||
|
||||
|
||||
|
||||
### 1. 前端部署
|
||||
|
||||
#### 1.1 直接运行:
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
#### 1.2 构建dist安装包:
|
||||
```bash
|
||||
npm run build:prod
|
||||
```
|
||||
|
||||
#### 1.3 nginx部署运行(mac环境部署管理前端为例):
|
||||
```bash
|
||||
cd /usr/local/etc/nginx/
|
||||
vi /usr/local/etc/nginx/nginx.conf
|
||||
# 编辑nginx.conf
|
||||
|
||||
server {
|
||||
listen 8080;
|
||||
server_name localhost;
|
||||
|
||||
location / {
|
||||
root /Users/calvin/sam2_ui/dist/;
|
||||
index index.html index.htm;
|
||||
}
|
||||
......
|
||||
|
||||
# 重新加载配置:
|
||||
sudo nginx -s reload
|
||||
|
||||
# 部署应用后,重启:
|
||||
cd /usr/local/Cellar/nginx/1.19.6/bin
|
||||
|
||||
# 快速停止
|
||||
sudo nginx -s stop
|
||||
|
||||
# 启动
|
||||
sudo nginx
|
||||
```
|
||||
|
||||
### 2. 后端jar部署
|
||||
#### 环境要求:
|
||||
- 系统JDK 1.8+,建议11
|
||||
|
||||
### 3. 运行程序:
|
||||
运行编译后的jar:
|
||||
```bash
|
||||
# 运行程序
|
||||
nohup java -Dfile.encoding=utf-8 -jar xxxxx.jar > log.txt 2>&1 &
|
||||
```
|
||||
|
||||
### 4. 打开浏览器
|
||||
- 输入地址: http://localhost:8089
|
||||
|
||||
|
||||
#### 1. 框选一键抠图
|
||||
![Screenshot](https://aias-home.oss-cn-beijing.aliyuncs.com/products/image_seg_sam2/sam2_seg1.jpg)
|
||||
|
||||
#### 2. 人体一键抠图
|
||||
![Screenshot](https://aias-home.oss-cn-beijing.aliyuncs.com/products/image_seg_sam2/sam2_seg2.jpg)
|
||||
|
||||
|
||||
|
||||
|
||||
#### 帮助文档:
|
||||
- https://aias.top/guides.html
|
||||
- 1.性能优化常见问题:
|
||||
- https://aias.top/AIAS/guides/performance.html
|
||||
- 2.引擎配置(包括CPU,GPU在线自动加载,及本地配置):
|
||||
- https://aias.top/AIAS/guides/engine_config.html
|
||||
- 3.模型加载方式(在线自动加载,及本地配置):
|
||||
- https://aias.top/AIAS/guides/load_model.html
|
||||
- 4.Windows环境常见问题:
|
||||
- https://aias.top/AIAS/guides/windows.html
|
105
6_web_app/image_seg_sam2/README_EN.md
Normal file
105
6_web_app/image_seg_sam2/README_EN.md
Normal file
@ -0,0 +1,105 @@
|
||||
### 官网:
|
||||
[官网链接](https://www.aias.top/)
|
||||
|
||||
### 下载模型,放置于models目录
|
||||
- 链接: https://pan.baidu.com/s/1m4NAiKTDdhcTWROdkwofFg?pwd=in39
|
||||
-
|
||||
|
||||
### 框选一键抠图
|
||||
一键抠图是一种图像处理技术,旨在自动将图像中的前景对象从背景中分离出来。它可以帮助用户快速、准确地实现抠图效果,无需手动绘制边界或进行复杂的图像编辑操作。
|
||||
一键抠图的原理通常基于计算机视觉和机器学习技术。它使用深度神经网络模型,通过训练大量的图像样本,学习如何识别和分离前景对象和背景。这些模型能够理解图像中的像素信息和上下文,并根据学习到的知识进行像素级别的分割。
|
||||
|
||||
![Screenshot](https://aias-home.oss-cn-beijing.aliyuncs.com/assets/seg_all.png)
|
||||
|
||||
使用一键抠图可以带来许多实际用途,包括但不限于以下几个方面:
|
||||
1. 图像编辑:一键抠图可以用于图像编辑软件中,帮助用户轻松地将前景对象从一个图像中提取出来,并将其放置到另一个图像或背景中,实现合成效果。
|
||||
2. 广告设计:在广告设计中,一键抠图可以用于创建吸引人的广告素材。通过将产品或主题从原始照片中抠出,可以更好地突出产品或主题,并与其他元素进行组合。
|
||||
3. 虚拟背景:一键抠图可以用于视频会议或虚拟现实应用中,帮助用户实现虚拟背景效果。通过将用户的前景对象从实际背景中抠出,可以将其放置在虚拟环境中,提供更丰富的交互体验。
|
||||
4. 图像分析:一键抠图可以用于图像分析和计算机视觉任务中。通过将前景对象与背景分离,可以更好地理解和分析图像中的不同元素,如目标检测、图像分类、图像分割等。
|
||||
|
||||
SAM2(Segment Anything Model 2)是由Meta公司发布的先进图像和视频分割模型。它是Segment Anything Model(SAM)的升级版本,
|
||||
SAM是Meta的FAIR实验室之前发布的一款用于图像分割的基础模型,能够在给定提示的情况下生成高质量的对象掩模。
|
||||
SAM2模型的主要特点是其通用性和灵活性,它能够处理各种复杂的图像和视频分割任务,无论是简单的对象识别还是复杂的场景理解,SAM2都能提供准确的结果。
|
||||
这使得它在许多实际应用场景中都非常有用,例如在医疗影像分析、自动驾驶、安防监控等领域都有着广泛的应用前景。
|
||||
|
||||
当前版本包含了下面功能:
|
||||
- 1. 框选一键抠图
|
||||
- 2. 支持CPU,GPU
|
||||
|
||||
|
||||
|
||||
### 1. 前端部署
|
||||
|
||||
#### 1.1 直接运行:
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
#### 1.2 构建dist安装包:
|
||||
```bash
|
||||
npm run build:prod
|
||||
```
|
||||
|
||||
#### 1.3 nginx部署运行(mac环境部署管理前端为例):
|
||||
```bash
|
||||
cd /usr/local/etc/nginx/
|
||||
vi /usr/local/etc/nginx/nginx.conf
|
||||
# 编辑nginx.conf
|
||||
|
||||
server {
|
||||
listen 8080;
|
||||
server_name localhost;
|
||||
|
||||
location / {
|
||||
root /Users/calvin/sam2_ui/dist/;
|
||||
index index.html index.htm;
|
||||
}
|
||||
......
|
||||
|
||||
# 重新加载配置:
|
||||
sudo nginx -s reload
|
||||
|
||||
# 部署应用后,重启:
|
||||
cd /usr/local/Cellar/nginx/1.19.6/bin
|
||||
|
||||
# 快速停止
|
||||
sudo nginx -s stop
|
||||
|
||||
# 启动
|
||||
sudo nginx
|
||||
```
|
||||
|
||||
### 2. 后端jar部署
|
||||
#### 环境要求:
|
||||
- 系统JDK 1.8+,建议11
|
||||
|
||||
### 3. 运行程序:
|
||||
运行编译后的jar:
|
||||
```bash
|
||||
# 运行程序
|
||||
nohup java -Dfile.encoding=utf-8 -jar xxxxx.jar > log.txt 2>&1 &
|
||||
```
|
||||
|
||||
### 4. 打开浏览器
|
||||
- 输入地址: http://localhost:8089
|
||||
|
||||
|
||||
#### 1. 框选一键抠图
|
||||
![Screenshot](https://aias-home.oss-cn-beijing.aliyuncs.com/products/image_seg_sam2/sam2_seg1.jpg)
|
||||
|
||||
#### 2. 人体一键抠图
|
||||
![Screenshot](https://aias-home.oss-cn-beijing.aliyuncs.com/products/image_seg_sam2/sam2_seg2.jpg)
|
||||
|
||||
|
||||
|
||||
|
||||
#### 帮助文档:
|
||||
- https://aias.top/guides.html
|
||||
- 1.性能优化常见问题:
|
||||
- https://aias.top/AIAS/guides/performance.html
|
||||
- 2.引擎配置(包括CPU,GPU在线自动加载,及本地配置):
|
||||
- https://aias.top/AIAS/guides/engine_config.html
|
||||
- 3.模型加载方式(在线自动加载,及本地配置):
|
||||
- https://aias.top/AIAS/guides/load_model.html
|
||||
- 4.Windows环境常见问题:
|
||||
- https://aias.top/AIAS/guides/windows.html
|
BIN
6_web_app/image_seg_sam2/sam2_backend/build/output/img_seg.png
Normal file
BIN
6_web_app/image_seg_sam2/sam2_backend/build/output/img_seg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 149 KiB |
BIN
6_web_app/image_seg_sam2/sam2_backend/build/output/sam2.png
Normal file
BIN
6_web_app/image_seg_sam2/sam2_backend/build/output/sam2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 MiB |
218
6_web_app/image_seg_sam2/sam2_backend/pom.xml
Normal file
218
6_web_app/image_seg_sam2/sam2_backend/pom.xml
Normal file
@ -0,0 +1,218 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.1.9.RELEASE</version>
|
||||
</parent>
|
||||
<groupId>aias</groupId>
|
||||
<artifactId>sam2_backend</artifactId>
|
||||
<version>0.30.0</version>
|
||||
<name>sam2_backend</name>
|
||||
<description>AIAS Sam2 Project</description>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<jna.version>5.14.0</jna.version>
|
||||
<fastjson.version>2.0.40</fastjson.version>
|
||||
<swagger.version>2.9.2</swagger.version>
|
||||
<djl.version>0.30.0</djl.version>
|
||||
<javacv.version>1.5.8</javacv.version>
|
||||
<javacv.ffmpeg.version>5.1.2-1.5.8</javacv.ffmpeg.version>
|
||||
<javacpp.platform.macosx-x86_64>macosx-x86_64</javacpp.platform.macosx-x86_64>
|
||||
<javacpp.platform.linux-x86>linux-x86</javacpp.platform.linux-x86>
|
||||
<javacpp.platform.linux-x86_64>linux-x86_64</javacpp.platform.linux-x86_64>
|
||||
<javacpp.platform.windows-x86>windows-x86</javacpp.platform.windows-x86>
|
||||
<javacpp.platform.windows-x86_64>windows-x86_64</javacpp.platform.windows-x86_64>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-commons</artifactId>
|
||||
<version>2.1.2.RELEASE</version>
|
||||
</dependency>
|
||||
<!-- apache commons -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.8.1</version>
|
||||
</dependency>
|
||||
<!-- Gson -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j-impl</artifactId>
|
||||
<version>2.15.0</version>
|
||||
</dependency>
|
||||
<!-- DJL -->
|
||||
<dependency>
|
||||
<groupId>ai.djl</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.djl</groupId>
|
||||
<artifactId>basicdataset</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.djl</groupId>
|
||||
<artifactId>model-zoo</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.java.dev.jna</groupId>
|
||||
<artifactId>jna</artifactId>
|
||||
<version>${jna.version}</version> <!-- overrides default spring boot version to comply with DJL -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ai.djl.pytorch</groupId>
|
||||
<artifactId>pytorch-engine</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- ONNX -->
|
||||
<dependency>
|
||||
<groupId>ai.djl.onnxruntime</groupId>
|
||||
<artifactId>onnxruntime-engine</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ai.djl.opencv</groupId>
|
||||
<artifactId>opencv</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<!-- java cv -->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacv-platform</artifactId>
|
||||
<version>1.5.7</version>
|
||||
</dependency>
|
||||
|
||||
<!--lombok-->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.24</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.http-client</groupId>
|
||||
<artifactId>google-http-client</artifactId>
|
||||
<version>1.19.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<artifactId>commons-cli</artifactId>
|
||||
<version>1.4</version>
|
||||
</dependency>
|
||||
|
||||
<!-- fastjson -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-spring-boot-starter</artifactId>
|
||||
<version>2.0.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Swagger UI 相关 -->
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger2</artifactId>
|
||||
<version>${swagger.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-models</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger-ui</artifactId>
|
||||
<version>${swagger.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>1.5.21</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-models</artifactId>
|
||||
<version>1.5.21</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.12.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
<version>3.2.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>4.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>1.6.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<mainClass>top.aias.seg.MainApplication</mainClass>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
250
6_web_app/image_seg_sam2/sam2_backend/pom_linux.xml
Normal file
250
6_web_app/image_seg_sam2/sam2_backend/pom_linux.xml
Normal file
@ -0,0 +1,250 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.1.9.RELEASE</version>
|
||||
</parent>
|
||||
<groupId>aias</groupId>
|
||||
<artifactId>sam2_backend</artifactId>
|
||||
<version>0.30.0</version>
|
||||
<name>sam2_backend</name>
|
||||
<description>AIAS Sam2 Project</description>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<jna.version>5.14.0</jna.version>
|
||||
<fastjson.version>2.0.40</fastjson.version>
|
||||
<swagger.version>2.9.2</swagger.version>
|
||||
<djl.version>0.30.0</djl.version>
|
||||
<javacv.version>1.5.8</javacv.version>
|
||||
<javacv.ffmpeg.version>5.1.2-1.5.8</javacv.ffmpeg.version>
|
||||
<javacpp.platform.macosx-x86_64>macosx-x86_64</javacpp.platform.macosx-x86_64>
|
||||
<javacpp.platform.linux-x86>linux-x86</javacpp.platform.linux-x86>
|
||||
<javacpp.platform.linux-x86_64>linux-x86_64</javacpp.platform.linux-x86_64>
|
||||
<javacpp.platform.windows-x86>windows-x86</javacpp.platform.windows-x86>
|
||||
<javacpp.platform.windows-x86_64>windows-x86_64</javacpp.platform.windows-x86_64>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-commons</artifactId>
|
||||
<version>2.1.2.RELEASE</version>
|
||||
</dependency>
|
||||
<!-- apache commons -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.8.1</version>
|
||||
</dependency>
|
||||
<!-- Gson -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j-impl</artifactId>
|
||||
<version>2.15.0</version>
|
||||
</dependency>
|
||||
<!-- DJL -->
|
||||
<dependency>
|
||||
<groupId>ai.djl</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.djl</groupId>
|
||||
<artifactId>basicdataset</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.djl</groupId>
|
||||
<artifactId>model-zoo</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.java.dev.jna</groupId>
|
||||
<artifactId>jna</artifactId>
|
||||
<version>${jna.version}</version> <!-- overrides default spring boot version to comply with DJL -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ai.djl.pytorch</groupId>
|
||||
<artifactId>pytorch-engine</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- ONNX -->
|
||||
<dependency>
|
||||
<groupId>ai.djl.onnxruntime</groupId>
|
||||
<artifactId>onnxruntime-engine</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.djl.opencv</groupId>
|
||||
<artifactId>opencv</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<!-- java cv -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.bytedeco</groupId>-->
|
||||
<!-- <artifactId>javacv-platform</artifactId>-->
|
||||
<!-- <version>1.5.7</version>-->
|
||||
<!-- </dependency>-->
|
||||
<!--javacv截取视频帧-->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacv</artifactId>
|
||||
<version>${javacv.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--Linux平台-->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacpp</artifactId>
|
||||
<version>${javacv.version}</version>
|
||||
<classifier>${javacpp.platform.linux-x86}</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>ffmpeg</artifactId>
|
||||
<version>${javacv.ffmpeg.version}</version>
|
||||
<classifier>${javacpp.platform.linux-x86}</classifier>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacpp</artifactId>
|
||||
<version>${javacv.version}</version>
|
||||
<classifier>${javacpp.platform.linux-x86_64}</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>ffmpeg</artifactId>
|
||||
<version>${javacv.ffmpeg.version}</version>
|
||||
<classifier>${javacpp.platform.linux-x86_64}</classifier>
|
||||
</dependency>
|
||||
|
||||
<!--lombok-->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.24</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.http-client</groupId>
|
||||
<artifactId>google-http-client</artifactId>
|
||||
<version>1.19.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<artifactId>commons-cli</artifactId>
|
||||
<version>1.4</version>
|
||||
</dependency>
|
||||
|
||||
<!-- fastjson -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-spring-boot-starter</artifactId>
|
||||
<version>2.0.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Swagger UI 相关 -->
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger2</artifactId>
|
||||
<version>${swagger.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-models</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger-ui</artifactId>
|
||||
<version>${swagger.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>1.5.21</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-models</artifactId>
|
||||
<version>1.5.21</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.12.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
<version>3.2.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>4.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>1.6.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<mainClass>top.aias.seg.MainApplication</mainClass>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
237
6_web_app/image_seg_sam2/sam2_backend/pom_mac.xml
Normal file
237
6_web_app/image_seg_sam2/sam2_backend/pom_mac.xml
Normal file
@ -0,0 +1,237 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.1.9.RELEASE</version>
|
||||
</parent>
|
||||
<groupId>aias</groupId>
|
||||
<artifactId>sam2_backend</artifactId>
|
||||
<version>0.30.0</version>
|
||||
<name>sam2_backend</name>
|
||||
<description>AIAS Sam2 Project</description>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<jna.version>5.14.0</jna.version>
|
||||
<fastjson.version>2.0.40</fastjson.version>
|
||||
<swagger.version>2.9.2</swagger.version>
|
||||
<djl.version>0.30.0</djl.version>
|
||||
<javacv.version>1.5.8</javacv.version>
|
||||
<javacv.ffmpeg.version>5.1.2-1.5.8</javacv.ffmpeg.version>
|
||||
<javacpp.platform.macosx-x86_64>macosx-x86_64</javacpp.platform.macosx-x86_64>
|
||||
<javacpp.platform.linux-x86>linux-x86</javacpp.platform.linux-x86>
|
||||
<javacpp.platform.linux-x86_64>linux-x86_64</javacpp.platform.linux-x86_64>
|
||||
<javacpp.platform.windows-x86>windows-x86</javacpp.platform.windows-x86>
|
||||
<javacpp.platform.windows-x86_64>windows-x86_64</javacpp.platform.windows-x86_64>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-commons</artifactId>
|
||||
<version>2.1.2.RELEASE</version>
|
||||
</dependency>
|
||||
<!-- apache commons -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.8.1</version>
|
||||
</dependency>
|
||||
<!-- Gson -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j-impl</artifactId>
|
||||
<version>2.15.0</version>
|
||||
</dependency>
|
||||
<!-- DJL -->
|
||||
<dependency>
|
||||
<groupId>ai.djl</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.djl</groupId>
|
||||
<artifactId>basicdataset</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.djl</groupId>
|
||||
<artifactId>model-zoo</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.java.dev.jna</groupId>
|
||||
<artifactId>jna</artifactId>
|
||||
<version>${jna.version}</version> <!-- overrides default spring boot version to comply with DJL -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ai.djl.pytorch</groupId>
|
||||
<artifactId>pytorch-engine</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- ONNX -->
|
||||
<dependency>
|
||||
<groupId>ai.djl.onnxruntime</groupId>
|
||||
<artifactId>onnxruntime-engine</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.djl.opencv</groupId>
|
||||
<artifactId>opencv</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<!-- java cv -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.bytedeco</groupId>-->
|
||||
<!-- <artifactId>javacv-platform</artifactId>-->
|
||||
<!-- <version>1.5.7</version>-->
|
||||
<!-- </dependency>-->
|
||||
<!--javacv截取视频帧-->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacv</artifactId>
|
||||
<version>${javacv.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--MacOS平台-->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacpp</artifactId>
|
||||
<version>${javacv.version}</version>
|
||||
<classifier>${javacpp.platform.macosx-x86_64}</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>ffmpeg</artifactId>
|
||||
<version>${javacv.ffmpeg.version}</version>
|
||||
<classifier>${javacpp.platform.macosx-x86_64}</classifier>
|
||||
</dependency>
|
||||
|
||||
<!--lombok-->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.24</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.http-client</groupId>
|
||||
<artifactId>google-http-client</artifactId>
|
||||
<version>1.19.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<artifactId>commons-cli</artifactId>
|
||||
<version>1.4</version>
|
||||
</dependency>
|
||||
|
||||
<!-- fastjson -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-spring-boot-starter</artifactId>
|
||||
<version>2.0.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Swagger UI 相关 -->
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger2</artifactId>
|
||||
<version>${swagger.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-models</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger-ui</artifactId>
|
||||
<version>${swagger.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>1.5.21</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-models</artifactId>
|
||||
<version>1.5.21</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.12.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
<version>3.2.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>4.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>1.6.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<mainClass>top.aias.seg.MainApplication</mainClass>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
250
6_web_app/image_seg_sam2/sam2_backend/pom_win.xml
Normal file
250
6_web_app/image_seg_sam2/sam2_backend/pom_win.xml
Normal file
@ -0,0 +1,250 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.1.9.RELEASE</version>
|
||||
</parent>
|
||||
<groupId>aias</groupId>
|
||||
<artifactId>sam2_backend</artifactId>
|
||||
<version>0.30.0</version>
|
||||
<name>sam2_backend</name>
|
||||
<description>AIAS Sam2 Project</description>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<jna.version>5.14.0</jna.version>
|
||||
<fastjson.version>2.0.40</fastjson.version>
|
||||
<swagger.version>2.9.2</swagger.version>
|
||||
<djl.version>0.30.0</djl.version>
|
||||
<javacv.version>1.5.8</javacv.version>
|
||||
<javacv.ffmpeg.version>5.1.2-1.5.8</javacv.ffmpeg.version>
|
||||
<javacpp.platform.macosx-x86_64>macosx-x86_64</javacpp.platform.macosx-x86_64>
|
||||
<javacpp.platform.linux-x86>linux-x86</javacpp.platform.linux-x86>
|
||||
<javacpp.platform.linux-x86_64>linux-x86_64</javacpp.platform.linux-x86_64>
|
||||
<javacpp.platform.windows-x86>windows-x86</javacpp.platform.windows-x86>
|
||||
<javacpp.platform.windows-x86_64>windows-x86_64</javacpp.platform.windows-x86_64>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-commons</artifactId>
|
||||
<version>2.1.2.RELEASE</version>
|
||||
</dependency>
|
||||
<!-- apache commons -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.8.1</version>
|
||||
</dependency>
|
||||
<!-- Gson -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j-impl</artifactId>
|
||||
<version>2.15.0</version>
|
||||
</dependency>
|
||||
<!-- DJL -->
|
||||
<dependency>
|
||||
<groupId>ai.djl</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.djl</groupId>
|
||||
<artifactId>basicdataset</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.djl</groupId>
|
||||
<artifactId>model-zoo</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.java.dev.jna</groupId>
|
||||
<artifactId>jna</artifactId>
|
||||
<version>${jna.version}</version> <!-- overrides default spring boot version to comply with DJL -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ai.djl.pytorch</groupId>
|
||||
<artifactId>pytorch-engine</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- ONNX -->
|
||||
<dependency>
|
||||
<groupId>ai.djl.onnxruntime</groupId>
|
||||
<artifactId>onnxruntime-engine</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.djl.opencv</groupId>
|
||||
<artifactId>opencv</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<!-- java cv -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.bytedeco</groupId>-->
|
||||
<!-- <artifactId>javacv-platform</artifactId>-->
|
||||
<!-- <version>1.5.7</version>-->
|
||||
<!-- </dependency>-->
|
||||
<!--javacv截取视频帧-->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacv</artifactId>
|
||||
<version>${javacv.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--Windows平台-->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacpp</artifactId>
|
||||
<version>${javacv.version}</version>
|
||||
<classifier>${javacpp.platform.windows-x86}</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>ffmpeg</artifactId>
|
||||
<version>${javacv.ffmpeg.version}</version>
|
||||
<classifier>${javacpp.platform.windows-x86}</classifier>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacpp</artifactId>
|
||||
<version>${javacv.version}</version>
|
||||
<classifier>${javacpp.platform.windows-x86_64}</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>ffmpeg</artifactId>
|
||||
<version>${javacv.ffmpeg.version}</version>
|
||||
<classifier>${javacpp.platform.windows-x86_64}</classifier>
|
||||
</dependency>
|
||||
|
||||
<!--lombok-->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.24</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.http-client</groupId>
|
||||
<artifactId>google-http-client</artifactId>
|
||||
<version>1.19.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<artifactId>commons-cli</artifactId>
|
||||
<version>1.4</version>
|
||||
</dependency>
|
||||
|
||||
<!-- fastjson -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-spring-boot-starter</artifactId>
|
||||
<version>2.0.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Swagger UI 相关 -->
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger2</artifactId>
|
||||
<version>${swagger.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-models</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger-ui</artifactId>
|
||||
<version>${swagger.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>1.5.21</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-models</artifactId>
|
||||
<version>1.5.21</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.12.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
<version>3.2.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>4.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>1.6.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<mainClass>top.aias.seg.MainApplication</mainClass>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
8
6_web_app/image_seg_sam2/sam2_backend/sam2_backend.iml
Normal file
8
6_web_app/image_seg_sam2/sam2_backend/sam2_backend.iml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="Spring" name="Spring">
|
||||
<configuration />
|
||||
</facet>
|
||||
</component>
|
||||
</module>
|
@ -0,0 +1,3 @@
|
||||
Manifest-Version: 1.0
|
||||
Main-Class: top.aias.seg.MainApplication
|
||||
|
@ -0,0 +1,19 @@
|
||||
package top.aias.seg;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* 入口主程序
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class MainApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(MainApplication.class, args);
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package top.aias.seg.bean;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
/**
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
@Data
|
||||
public class DataBean {
|
||||
private String value;
|
||||
private List<Point> points;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package top.aias.seg.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
/**
|
||||
* 图片对象
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
@Data
|
||||
public class ImageBean {
|
||||
private String uid;
|
||||
private String name;
|
||||
private String imageName;
|
||||
List<LabelBean> labelData;
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package top.aias.seg.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
/**
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
@Data
|
||||
public class LabelBean {
|
||||
private int index;
|
||||
private int active;
|
||||
private String type;
|
||||
private String value;
|
||||
private String field;
|
||||
private List<Point> points;
|
||||
private ai.djl.modality.cv.output.Point centerPoint;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package top.aias.seg.bean;
|
||||
|
||||
import lombok.Data;
|
||||
/**
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
@Data
|
||||
public class LabelDTO {
|
||||
private String uid;
|
||||
private LabelBean labelData;
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package top.aias.seg.bean;
|
||||
|
||||
import lombok.Data;
|
||||
/**
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
@Data
|
||||
public class Point {
|
||||
private int x;
|
||||
private int y;
|
||||
|
||||
public Point() {
|
||||
}
|
||||
|
||||
public Point(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package top.aias.seg.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
/**
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
@Data
|
||||
public class ResultBean<T> implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private int code;
|
||||
private String value;
|
||||
private Map<String, Object> data = new HashMap<String, Object>();
|
||||
|
||||
public static ResultBean success() {
|
||||
ResultBean rb = new ResultBean();
|
||||
rb.setCode(0);
|
||||
rb.setValue("Success");
|
||||
return rb;
|
||||
}
|
||||
|
||||
public static ResultBean failure() {
|
||||
ResultBean msg = new ResultBean();
|
||||
msg.setCode(-1);
|
||||
msg.setValue("Failure");
|
||||
return msg;
|
||||
}
|
||||
|
||||
public ResultBean() {
|
||||
|
||||
}
|
||||
|
||||
public ResultBean add(String key, Object value) {
|
||||
this.getData().put(key, value);
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,308 @@
|
||||
/*
|
||||
* Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
|
||||
* with the License. A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0/
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file 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 top.aias.seg.bean;
|
||||
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.ImageFactory;
|
||||
import ai.djl.modality.cv.output.Point;
|
||||
import ai.djl.modality.cv.output.Rectangle;
|
||||
import ai.djl.ndarray.NDList;
|
||||
import ai.djl.util.JsonUtils;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A class represents the segment anything input.
|
||||
*/
|
||||
public final class Sam2Input {
|
||||
|
||||
private Image image;
|
||||
private Point[] points;
|
||||
private int[] labels;
|
||||
private boolean visualize;
|
||||
private NDList embeddings;
|
||||
|
||||
/**
|
||||
* Constructs a {@code Sam2Input} instance.
|
||||
*
|
||||
* @param image the image
|
||||
* @param points the locations on the image
|
||||
* @param labels the labels for the locations (0: background, 1: foreground)
|
||||
*/
|
||||
public Sam2Input(Image image, Point[] points, int[] labels) {
|
||||
this(image, points, labels, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code Sam2Input} instance.
|
||||
*
|
||||
* @param image the image
|
||||
* @param points the locations on the image
|
||||
* @param labels the labels for the locations (0: background, 1: foreground)
|
||||
* @param visualize true if output visualized image
|
||||
*/
|
||||
public Sam2Input(Image image, Point[] points, int[] labels, boolean visualize) {
|
||||
this.image = image;
|
||||
this.points = points;
|
||||
this.labels = labels;
|
||||
this.visualize = visualize;
|
||||
}
|
||||
|
||||
public NDList getEmbeddings() {
|
||||
return embeddings;
|
||||
}
|
||||
|
||||
public void setEmbeddings(NDList embeddings) {
|
||||
this.embeddings = embeddings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the image.
|
||||
*
|
||||
* @return the image
|
||||
*/
|
||||
public Image getImage() {
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if output visualized image.
|
||||
*
|
||||
* @return {@code true} if output visualized image
|
||||
*/
|
||||
public boolean isVisualize() {
|
||||
return visualize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the locations.
|
||||
*
|
||||
* @return the locations
|
||||
*/
|
||||
public List<Point> getPoints() {
|
||||
List<Point> list = new ArrayList<>();
|
||||
for (int i = 0; i < labels.length; ++i) {
|
||||
if (labels[i] < 2) {
|
||||
list.add(points[i]);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the box.
|
||||
*
|
||||
* @return the box
|
||||
*/
|
||||
public List<Rectangle> getBoxes() {
|
||||
List<Rectangle> list = new ArrayList<>();
|
||||
for (int i = 0; i < labels.length; ++i) {
|
||||
if (labels[i] == 2) {
|
||||
double width = points[i + 1].getX() - points[i].getX();
|
||||
double height = points[i + 1].getY() - points[i].getY();
|
||||
list.add(new Rectangle(points[i], width, height));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public float[] toLocationArray(int width, int height) {
|
||||
float[] ret = new float[points.length * 2];
|
||||
int i = 0;
|
||||
for (Point point : points) {
|
||||
ret[i++] = (float) point.getX() / width * 1024;
|
||||
ret[i++] = (float) point.getY() / height * 1024;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public float[][] getLabels() {
|
||||
float[][] buf = new float[1][labels.length];
|
||||
for (int i = 0; i < labels.length; ++i) {
|
||||
buf[0][i] = labels[i];
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code Sam2Input} instance from json string.
|
||||
*
|
||||
* @param input the json input
|
||||
* @return a {@code Sam2Input} instance
|
||||
* @throws IOException if failed to load the image
|
||||
*/
|
||||
public static Sam2Input fromJson(String input) throws IOException {
|
||||
Prompt prompt = JsonUtils.GSON.fromJson(input, Prompt.class);
|
||||
if (prompt.image == null) {
|
||||
throw new IllegalArgumentException("Missing image_url value");
|
||||
}
|
||||
if (prompt.prompt == null || prompt.prompt.length == 0) {
|
||||
throw new IllegalArgumentException("Missing prompt value");
|
||||
}
|
||||
Image image = ImageFactory.getInstance().fromUrl(prompt.image);
|
||||
Builder builder = builder(image);
|
||||
if (prompt.visualize) {
|
||||
builder.visualize();
|
||||
}
|
||||
for (Location location : prompt.prompt) {
|
||||
int[] data = location.data;
|
||||
if ("point".equals(location.type)) {
|
||||
builder.addPoint(data[0], data[1], location.label);
|
||||
} else if ("rectangle".equals(location.type)) {
|
||||
builder.addBox(data[0], data[1], data[2], data[3]);
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a builder to build a {@code Sam2Input} with the image.
|
||||
*
|
||||
* @param image the image
|
||||
* @return a new builder
|
||||
*/
|
||||
public static Builder builder(Image image) {
|
||||
return new Builder(image);
|
||||
}
|
||||
|
||||
/**
|
||||
* The builder for {@code Sam2Input}.
|
||||
*/
|
||||
public static final class Builder {
|
||||
|
||||
private Image image;
|
||||
private List<Point> points;
|
||||
private List<Integer> labels;
|
||||
private boolean visualize;
|
||||
|
||||
Builder(Image image) {
|
||||
this.image = image;
|
||||
points = new ArrayList<>();
|
||||
labels = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a point to the {@code Sam2Input}.
|
||||
*
|
||||
* @param x the X coordinate
|
||||
* @param y the Y coordinate
|
||||
* @return the builder
|
||||
*/
|
||||
public Builder addPoint(int x, int y) {
|
||||
return addPoint(x, y, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a point to the {@code Sam2Input}.
|
||||
*
|
||||
* @param x the X coordinate
|
||||
* @param y the Y coordinate
|
||||
* @param label the label of the point, 0 for background, 1 for foreground
|
||||
* @return the builder
|
||||
*/
|
||||
public Builder addPoint(int x, int y, int label) {
|
||||
return addPoint(new Point(x, y), label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a point to the {@code Sam2Input}.
|
||||
*
|
||||
* @param point the point on image
|
||||
* @param label the label of the point, 0 for background, 1 for foreground
|
||||
* @return the builder
|
||||
*/
|
||||
public Builder addPoint(Point point, int label) {
|
||||
points.add(point);
|
||||
labels.add(label);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a box area to the {@code Sam2Input}.
|
||||
*
|
||||
* @param x the left coordinate
|
||||
* @param y the top coordinate
|
||||
* @param right the right coordinate
|
||||
* @param bottom the bottom coordinate
|
||||
* @return the builder
|
||||
*/
|
||||
public Builder addBox(int x, int y, int right, int bottom) {
|
||||
addPoint(new Point(x, y), 2);
|
||||
addPoint(new Point(right, bottom), 3);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the visualize for the {@code Sam2Input}.
|
||||
*
|
||||
* @return the builder
|
||||
*/
|
||||
public Builder visualize() {
|
||||
visualize = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the {@code Sam2Input}.
|
||||
*
|
||||
* @return the new {@code Sam2Input}
|
||||
*/
|
||||
public Sam2Input build() {
|
||||
Point[] location = points.toArray(new Point[0]);
|
||||
int[] array = labels.stream().mapToInt(Integer::intValue).toArray();
|
||||
return new Sam2Input(image, location, array, visualize);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Location {
|
||||
String type;
|
||||
int[] data;
|
||||
int label;
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void setData(int[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public void setLabel(int label) {
|
||||
this.label = label;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Prompt {
|
||||
|
||||
@SerializedName("image_url")
|
||||
String image;
|
||||
|
||||
Location[] prompt;
|
||||
boolean visualize;
|
||||
|
||||
public void setImage(String image) {
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
public void setPrompt(Location[] prompt) {
|
||||
this.prompt = prompt;
|
||||
}
|
||||
|
||||
public void setVisualize(boolean visualize) {
|
||||
this.visualize = visualize;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package top.aias.seg.configuration;
|
||||
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.alibaba.fastjson.support.config.FastJsonConfig;
|
||||
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
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 java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 配置类
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
public class ConfigAdapter implements WebMvcConfigurer {
|
||||
|
||||
// file configuration
|
||||
private final FileProperties properties;
|
||||
|
||||
public ConfigAdapter(FileProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CorsFilter corsFilter() {
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
config.setAllowCredentials(true);
|
||||
config.addAllowedOrigin("*");
|
||||
config.addAllowedHeader("*");
|
||||
config.addAllowedMethod("*");
|
||||
source.registerCorsConfiguration("/**", config);
|
||||
return new CorsFilter(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
FileProperties.ElPath path = properties.getPath();
|
||||
String pathUtl = "file:" + path.getPath().replace("\\", "/");
|
||||
registry.addResourceHandler("/file/**").addResourceLocations(pathUtl).setCachePeriod(0);
|
||||
registry.addResourceHandler("/file/tables/**").addResourceLocations(pathUtl + "tables/").setCachePeriod(0);
|
||||
registry.addResourceHandler("/file/images/**").addResourceLocations(pathUtl + "images/").setCachePeriod(0);
|
||||
registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/").setCachePeriod(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
|
||||
// 使用 fastjson 序列化,会导致 @JsonIgnore 失效,可以使用 @JSONField(serialize = false) 替换
|
||||
// Use fastjson serialization, which will cause @JsonIgnore to be invalid, can be replaced with @JSONField (serialize = false)
|
||||
FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
|
||||
List<MediaType> supportMediaTypeList = new ArrayList<>();
|
||||
supportMediaTypeList.add(MediaType.APPLICATION_JSON_UTF8);
|
||||
supportMediaTypeList.add(MediaType.TEXT_HTML);
|
||||
FastJsonConfig config = new FastJsonConfig();
|
||||
config.setDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
config.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);
|
||||
fastJsonHttpMessageConverter.setFastJsonConfig(config);
|
||||
fastJsonHttpMessageConverter.setSupportedMediaTypes(supportMediaTypeList);
|
||||
fastJsonHttpMessageConverter.setDefaultCharset(StandardCharsets.UTF_8);
|
||||
|
||||
converters.add(fastJsonHttpMessageConverter);
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package top.aias.seg.configuration;
|
||||
|
||||
import lombok.Data;
|
||||
import top.aias.seg.utils.Constants;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 文件配置
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "file")
|
||||
public class FileProperties {
|
||||
|
||||
/**
|
||||
* File size limitation
|
||||
*/
|
||||
private Long maxSize;
|
||||
|
||||
private ElPath mac;
|
||||
|
||||
private ElPath linux;
|
||||
|
||||
private ElPath windows;
|
||||
|
||||
public ElPath getPath() {
|
||||
String os = System.getProperty("os.name");
|
||||
if (os.toLowerCase().startsWith(Constants.WIN)) {
|
||||
return windows;
|
||||
} else if (os.toLowerCase().startsWith(Constants.MAC)) {
|
||||
return mac;
|
||||
}
|
||||
return linux;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class ElPath {
|
||||
|
||||
private String path;
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package top.aias.seg.configuration;
|
||||
|
||||
import ai.djl.MalformedModelException;
|
||||
import ai.djl.repository.zoo.ModelNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import top.aias.seg.model.Sam2DecoderModel;
|
||||
import top.aias.seg.model.Sam2EncoderModel;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 模型配置
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
@Configuration
|
||||
public class ModelConfiguration {
|
||||
@Value("${model.sam2.encoder}")
|
||||
private String encoder;
|
||||
|
||||
@Value("${model.sam2.decoder}")
|
||||
private String decoder;
|
||||
@Value("${model.poolSize}")
|
||||
private int poolSize;
|
||||
|
||||
@Bean
|
||||
public Sam2EncoderModel sam2EncoderModel() throws IOException, ModelNotFoundException, MalformedModelException {
|
||||
Sam2EncoderModel sam2EncoderModel = new Sam2EncoderModel();
|
||||
sam2EncoderModel.init(encoder, poolSize);
|
||||
return sam2EncoderModel;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Sam2DecoderModel sam2DecoderModel() throws IOException, ModelNotFoundException, MalformedModelException {
|
||||
Sam2DecoderModel sam2DecoderModel = new Sam2DecoderModel();
|
||||
sam2DecoderModel.init(decoder, poolSize);
|
||||
return sam2DecoderModel;
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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 top.aias.seg.configuration;
|
||||
|
||||
import com.fasterxml.classmate.TypeResolver;
|
||||
import com.google.common.base.Predicates;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.ParameterBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.schema.AlternateTypeRule;
|
||||
import springfox.documentation.schema.AlternateTypeRuleConvention;
|
||||
import springfox.documentation.service.ApiInfo;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.collect.Lists.newArrayList;
|
||||
import static springfox.documentation.schema.AlternateTypeRules.newRule;
|
||||
|
||||
/**
|
||||
* api doc.html
|
||||
* @author Calvin
|
||||
* @date Oct 19, 2021
|
||||
*/
|
||||
@Configuration
|
||||
@EnableSwagger2
|
||||
public class SwaggerConfig {
|
||||
|
||||
|
||||
@Value("${swagger.enabled}")
|
||||
private Boolean enabled;
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("all")
|
||||
public Docket createRestApi() {
|
||||
ParameterBuilder ticketPar = new ParameterBuilder();
|
||||
return new Docket(DocumentationType.SWAGGER_2)
|
||||
.enable(enabled)
|
||||
.apiInfo(apiInfo())
|
||||
.select()
|
||||
.paths(Predicates.not(PathSelectors.regex("/error.*")))
|
||||
.build();
|
||||
}
|
||||
|
||||
private ApiInfo apiInfo() {
|
||||
return new ApiInfoBuilder()
|
||||
.description("")
|
||||
.title("API Doc")
|
||||
.version("1.0")
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Pageable转换展示在swagger中
|
||||
* Convert Pageable for display in Swagger
|
||||
*/
|
||||
@Configuration
|
||||
class SwaggerDataConfig {
|
||||
|
||||
@Bean
|
||||
public AlternateTypeRuleConvention pageableConvention(final TypeResolver resolver) {
|
||||
return new AlternateTypeRuleConvention() {
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Ordered.HIGHEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AlternateTypeRule> rules() {
|
||||
return newArrayList(newRule(resolver.resolve(Pageable.class), resolver.resolve(Page.class)));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ApiModel
|
||||
@Data
|
||||
private static class Page {
|
||||
@ApiModelProperty("Page number (0..N)")
|
||||
private Integer page;
|
||||
|
||||
@ApiModelProperty("Number of items per page")
|
||||
private Integer size;
|
||||
|
||||
@ApiModelProperty("Sort criteria in the following format: property[,asc|desc]. Default sort order is ascending. Multiple sort conditions are supported, such as id,asc")
|
||||
private List<String> sort;
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package top.aias.seg.controller;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import top.aias.seg.bean.LabelDTO;
|
||||
import top.aias.seg.bean.ResultBean;
|
||||
import top.aias.seg.bean.ImageBean;
|
||||
import top.aias.seg.configuration.FileProperties;
|
||||
import top.aias.seg.service.ImageService;
|
||||
import top.aias.seg.utils.FileUtils;
|
||||
import top.aias.seg.utils.UUIDUtils;
|
||||
|
||||
/**
|
||||
* 框选抠图
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
@Api(tags = "框选抠图")
|
||||
@RestController
|
||||
@Configuration
|
||||
@RequestMapping("/infer")
|
||||
public class InferController {
|
||||
private Logger logger = LoggerFactory.getLogger(InferController.class);
|
||||
|
||||
@Autowired
|
||||
private ImageService imageService;
|
||||
|
||||
/**
|
||||
* 文件配置
|
||||
* File Configuration
|
||||
*/
|
||||
@Autowired
|
||||
private FileProperties properties;
|
||||
|
||||
@ApiOperation(value = "识别框选区")
|
||||
@PostMapping(value = "/getLabelData", produces = "application/json;charset=utf-8")
|
||||
public ResultBean getLabelData(@RequestBody LabelDTO labelDTO) {
|
||||
try {
|
||||
String base64Img = imageService.getLabelData(labelDTO.getUid(), labelDTO.getLabelData());
|
||||
// logger.info("LabelData: " + base64Img);
|
||||
return ResultBean.success().add("result", "data:imageName/png;base64," + base64Img);
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
return ResultBean.failure().add("message", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ApiOperation(value = "上传图片")
|
||||
@PostMapping(value = "/uploadImage")
|
||||
public ResultBean uploadImage(@RequestParam(value = "imageFile") MultipartFile imageFile) {
|
||||
try {
|
||||
// 要上传的目标文件存放路径
|
||||
// Target file storage path to be uploaded
|
||||
FileProperties.ElPath path = properties.getPath();
|
||||
String imagePath = path.getPath().replace("\\", "/") + "images/";
|
||||
FileUtils.checkAndCreatePath(imagePath);
|
||||
String templatePath = path.getPath().replace("\\", "/") + "templates/";
|
||||
FileUtils.checkAndCreatePath(templatePath);
|
||||
|
||||
ImageBean imageBean = new ImageBean();
|
||||
String uid = UUIDUtils.getUUID();
|
||||
imageBean.setUid(uid);
|
||||
//image/jpg' || 'image/jpeg' || 'image/png'
|
||||
String suffix = FileUtils.getSuffix(imageFile.getOriginalFilename());
|
||||
if (!suffix.equalsIgnoreCase(".jpg") &&
|
||||
!suffix.equalsIgnoreCase(".jpeg") &&
|
||||
!suffix.equalsIgnoreCase(".png") &&
|
||||
!suffix.equalsIgnoreCase(".bmp")) {
|
||||
return ResultBean.failure().add("errors", "图片格式应为: jpg, jpeg, png 或者 bmp!");
|
||||
}
|
||||
String imageName = FileUtils.getFileName(imageFile.getOriginalFilename());
|
||||
imageBean.setImageName(imageName);
|
||||
imageBean.setName("");
|
||||
|
||||
if (FileUtils.upload(imageFile, imagePath, imageName)) {
|
||||
imageService.addImageInfo(imageBean);
|
||||
return ResultBean.success().add("result", imageBean);
|
||||
} else {
|
||||
return ResultBean.failure();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
return ResultBean.failure().add("message", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package top.aias.seg.model;
|
||||
|
||||
import ai.djl.Device;
|
||||
import ai.djl.MalformedModelException;
|
||||
import ai.djl.ModelException;
|
||||
import ai.djl.inference.Predictor;
|
||||
import ai.djl.modality.cv.output.DetectedObjects;
|
||||
import ai.djl.repository.zoo.Criteria;
|
||||
import ai.djl.repository.zoo.ModelNotFoundException;
|
||||
import ai.djl.repository.zoo.ZooModel;
|
||||
import ai.djl.training.util.ProgressBar;
|
||||
import ai.djl.translate.TranslateException;
|
||||
import top.aias.seg.bean.Sam2Input;
|
||||
import top.aias.seg.model.pool.DecoderPool;
|
||||
import top.aias.seg.translator.Sam2DecoderTranslator;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
public final class Sam2DecoderModel implements AutoCloseable {
|
||||
private ZooModel<Sam2Input, DetectedObjects> model;
|
||||
private DecoderPool segPool;
|
||||
|
||||
// public Sam2DecoderModel(String modelUri, int poolSize) throws ModelException, IOException {
|
||||
// init(modelUri, poolSize);
|
||||
// }
|
||||
|
||||
public void init(String modelUri, int poolSize) throws MalformedModelException, ModelNotFoundException, IOException {
|
||||
this.model = criteria(modelUri).loadModel();
|
||||
this.segPool = new DecoderPool(model, poolSize);
|
||||
}
|
||||
|
||||
public DetectedObjects predict(Sam2Input input) throws TranslateException {
|
||||
Predictor<Sam2Input, DetectedObjects> predictor = segPool.getPredictor();
|
||||
DetectedObjects detection = predictor.predict(input);
|
||||
segPool.releasePredictor(predictor);
|
||||
return detection;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
this.model.close();
|
||||
this.segPool.close();
|
||||
}
|
||||
|
||||
private Criteria<Sam2Input, DetectedObjects> criteria(String modelUri) {
|
||||
Criteria<Sam2Input, DetectedObjects> criteria =
|
||||
Criteria.builder()
|
||||
.setTypes(Sam2Input.class, DetectedObjects.class)
|
||||
// .optDevice(device)
|
||||
.optModelPath(Paths.get(modelUri))
|
||||
.optEngine("OnnxRuntime")
|
||||
.optTranslator(new Sam2DecoderTranslator())
|
||||
.optProgress(new ProgressBar())
|
||||
.build();
|
||||
return criteria;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package top.aias.seg.model;
|
||||
|
||||
import ai.djl.Device;
|
||||
import ai.djl.MalformedModelException;
|
||||
import ai.djl.ModelException;
|
||||
import ai.djl.inference.Predictor;
|
||||
import ai.djl.ndarray.NDList;
|
||||
import ai.djl.repository.zoo.Criteria;
|
||||
import ai.djl.repository.zoo.ModelNotFoundException;
|
||||
import ai.djl.repository.zoo.ZooModel;
|
||||
import ai.djl.training.util.ProgressBar;
|
||||
import ai.djl.translate.TranslateException;
|
||||
import top.aias.seg.bean.Sam2Input;
|
||||
import top.aias.seg.model.pool.EncoderPool;
|
||||
import top.aias.seg.translator.Sam2EncoderTranslator;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* sam2-hiera-large.onnx:sam2大模型。
|
||||
* sam2-hiera-tiny.onnx:sam2的轻量级版本。
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
public final class Sam2EncoderModel implements AutoCloseable {
|
||||
private ZooModel<Sam2Input, NDList> model;
|
||||
private EncoderPool encoderPool;
|
||||
|
||||
// public Sam2EncoderModel(String modelPath, String modelName, int poolSize, Device device) throws ModelException, IOException {
|
||||
// init(modelPath, modelName, poolSize, device);
|
||||
// }
|
||||
|
||||
public void init(String modelUri, int poolSize) throws MalformedModelException, ModelNotFoundException, IOException {
|
||||
this.model = criteria(modelUri).loadModel();
|
||||
this.encoderPool = new EncoderPool(model, poolSize);
|
||||
}
|
||||
|
||||
public NDList predict(Sam2Input input) throws TranslateException {
|
||||
Predictor<Sam2Input, NDList> predictor = encoderPool.getPredictor();
|
||||
NDList detection = predictor.predict(input);
|
||||
encoderPool.releasePredictor(predictor);
|
||||
return detection;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
this.model.close();
|
||||
this.encoderPool.close();
|
||||
}
|
||||
|
||||
private Criteria<Sam2Input, NDList> criteria(String modelUri) {
|
||||
|
||||
Criteria<Sam2Input, NDList> criteria =
|
||||
Criteria.builder()
|
||||
.setTypes(Sam2Input.class, NDList.class)
|
||||
// .optDevice(device)
|
||||
.optModelPath(Paths.get(modelUri))
|
||||
.optEngine("OnnxRuntime")
|
||||
.optTranslator(new Sam2EncoderTranslator())
|
||||
.optProgress(new ProgressBar())
|
||||
.build();
|
||||
return criteria;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package top.aias.seg.model.pool;// 导入需要的包
|
||||
|
||||
import ai.djl.inference.Predictor;
|
||||
import ai.djl.modality.cv.output.DetectedObjects;
|
||||
import ai.djl.repository.zoo.ZooModel;
|
||||
import top.aias.seg.bean.Sam2Input;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* 图像分割连接池
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
public class DecoderPool {
|
||||
private int poolSize;
|
||||
private ZooModel<Sam2Input, DetectedObjects> model;
|
||||
private ArrayList<Predictor<Sam2Input, DetectedObjects>> predictorList = new ArrayList<>();
|
||||
|
||||
|
||||
public DecoderPool(ZooModel<Sam2Input, DetectedObjects> model, int poolSize) {
|
||||
this.poolSize = poolSize;
|
||||
this.model = model;
|
||||
|
||||
for (int i = 0; i < poolSize; i++) {
|
||||
Predictor<Sam2Input, DetectedObjects> detector = model.newPredictor();
|
||||
predictorList.add(detector);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized Predictor<Sam2Input, DetectedObjects> getPredictor() {
|
||||
while (predictorList.isEmpty()) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
Predictor<Sam2Input, DetectedObjects> predictor = predictorList.remove(0);
|
||||
return predictor;
|
||||
}
|
||||
|
||||
public synchronized void releasePredictor(Predictor<Sam2Input, DetectedObjects> predictor) {
|
||||
predictorList.add(predictor);
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
for (Predictor<Sam2Input, DetectedObjects> predictor : predictorList) {
|
||||
predictor.close();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package top.aias.seg.model.pool;// 导入需要的包
|
||||
|
||||
import ai.djl.inference.Predictor;
|
||||
import ai.djl.ndarray.NDList;
|
||||
import ai.djl.repository.zoo.ZooModel;
|
||||
import top.aias.seg.bean.Sam2Input;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* 图像分割连接池
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
public class EncoderPool {
|
||||
private int poolSize;
|
||||
private ZooModel<Sam2Input, NDList> model;
|
||||
private ArrayList<Predictor<Sam2Input, NDList>> predictorList = new ArrayList<>();
|
||||
|
||||
|
||||
public EncoderPool(ZooModel<Sam2Input, NDList> model, int poolSize) {
|
||||
this.poolSize = poolSize;
|
||||
this.model = model;
|
||||
|
||||
for (int i = 0; i < poolSize; i++) {
|
||||
Predictor<Sam2Input, NDList> detector = model.newPredictor();
|
||||
predictorList.add(detector);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized Predictor<Sam2Input, NDList> getPredictor() {
|
||||
while (predictorList.isEmpty()) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
Predictor<Sam2Input, NDList> predictor = predictorList.remove(0);
|
||||
return predictor;
|
||||
}
|
||||
|
||||
public synchronized void releasePredictor(Predictor<Sam2Input, NDList> predictor) {
|
||||
predictorList.add(predictor);
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
for (Predictor<Sam2Input, NDList> predictor : predictorList) {
|
||||
predictor.close();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package top.aias.seg.service;
|
||||
|
||||
import ai.djl.translate.TranslateException;
|
||||
import top.aias.seg.bean.LabelBean;
|
||||
import top.aias.seg.bean.ImageBean;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 识别接口
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
public interface ImageService {
|
||||
List<ImageBean> getDataList();
|
||||
|
||||
ImageBean getImageInfo(String uid) throws IOException;
|
||||
|
||||
void addImageInfo(ImageBean templateBean) throws IOException;
|
||||
|
||||
String getLabelData(String uid, LabelBean labelData) throws IOException, TranslateException;
|
||||
}
|
@ -0,0 +1,228 @@
|
||||
package top.aias.seg.service.impl;
|
||||
|
||||
import ai.djl.Device;
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.ImageFactory;
|
||||
import ai.djl.modality.cv.output.BoundingBox;
|
||||
import ai.djl.modality.cv.output.DetectedObjects;
|
||||
import ai.djl.modality.cv.output.Mask;
|
||||
import ai.djl.modality.cv.output.Rectangle;
|
||||
import ai.djl.ndarray.NDArray;
|
||||
import ai.djl.ndarray.NDList;
|
||||
import ai.djl.ndarray.NDManager;
|
||||
import ai.djl.opencv.OpenCVImageFactory;
|
||||
import ai.djl.translate.TranslateException;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.opencv.core.Mat;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import top.aias.seg.bean.LabelBean;
|
||||
import top.aias.seg.bean.Sam2Input;
|
||||
import top.aias.seg.bean.ImageBean;
|
||||
import top.aias.seg.configuration.FileProperties;
|
||||
import top.aias.seg.model.Sam2DecoderModel;
|
||||
import top.aias.seg.model.Sam2EncoderModel;
|
||||
import top.aias.seg.service.ImageService;
|
||||
import top.aias.seg.utils.FileUtils;
|
||||
import top.aias.seg.utils.ImageUtils;
|
||||
import top.aias.seg.utils.OpenCVUtils;
|
||||
import top.aias.seg.utils.PointUtils;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 识别服务
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
@Service
|
||||
public class ImageServiceImpl implements ImageService {
|
||||
private static final String TEMPLATE_LIST_FILE = "templates.json";
|
||||
private Logger logger = LoggerFactory.getLogger(ImageServiceImpl.class);
|
||||
|
||||
/**
|
||||
* file configuration
|
||||
*/
|
||||
@Autowired
|
||||
private FileProperties properties;
|
||||
|
||||
/**
|
||||
* sam2 encoder model
|
||||
*/
|
||||
@Autowired
|
||||
private Sam2EncoderModel sam2EncoderModel;
|
||||
|
||||
/**
|
||||
* sam2 decoder model
|
||||
*/
|
||||
@Autowired
|
||||
private Sam2DecoderModel sam2DecoderModel;
|
||||
|
||||
public List<ImageBean> getDataList() {
|
||||
List<ImageBean> templateList = null;
|
||||
FileProperties.ElPath path = properties.getPath();
|
||||
String fileRelativePath = path.getPath().replace("\\", "/");
|
||||
String json = null;
|
||||
try {
|
||||
json = FileUtils.readFile(fileRelativePath, TEMPLATE_LIST_FILE);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (!StringUtils.isBlank(json)) {
|
||||
templateList = new Gson().fromJson(json, new TypeToken<List<ImageBean>>() {
|
||||
}.getType());
|
||||
} else {
|
||||
templateList = new ArrayList<>();
|
||||
}
|
||||
return templateList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取图片信息
|
||||
* Get Image
|
||||
*
|
||||
* @param uid
|
||||
*/
|
||||
public ImageBean getImageInfo(String uid) throws IOException {
|
||||
ImageBean template = null;
|
||||
FileProperties.ElPath path = properties.getPath();
|
||||
String fileRelativePath = path.getPath().replace("\\", "/") + "templates/";
|
||||
String json = FileUtils.readFile(fileRelativePath, uid + ".json");
|
||||
if (!StringUtils.isBlank(json)) {
|
||||
template = new Gson().fromJson(json, new TypeToken<ImageBean>() {
|
||||
}.getType());
|
||||
}
|
||||
return template;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 新增图片
|
||||
* Add Image
|
||||
*
|
||||
* @param templateBean
|
||||
*/
|
||||
public synchronized void addImageInfo(ImageBean templateBean) throws IOException {
|
||||
List<ImageBean> dataList = getDataList();
|
||||
templateBean.setLabelData(null);
|
||||
dataList.add(templateBean);
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
String json = gson.toJson(dataList);
|
||||
FileProperties.ElPath path = properties.getPath();
|
||||
// 保存列表数据
|
||||
// Save list data
|
||||
String fileRelativePath = path.getPath().replace("\\", "/");
|
||||
FileUtils.saveFile(fileRelativePath, TEMPLATE_LIST_FILE, json);
|
||||
// 保存图片数据
|
||||
// Save image data
|
||||
json = gson.toJson(templateBean);
|
||||
FileUtils.saveFile(fileRelativePath + "templates/", templateBean.getUid() + ".json", json);
|
||||
}
|
||||
|
||||
public String getLabelData(String uid, LabelBean labelData) throws IOException, TranslateException {
|
||||
ImageBean template = getImageInfo(uid);
|
||||
FileProperties.ElPath path = properties.getPath();
|
||||
String fileRelativePath = path.getPath().replace("\\", "/");
|
||||
Path imageFile = Paths.get(fileRelativePath + "images/" + template.getImageName());
|
||||
Image image = OpenCVImageFactory.getInstance().fromFile(imageFile);
|
||||
int[] rect = PointUtils.rectXYWH(labelData.getPoints());
|
||||
|
||||
int x = rect[0];
|
||||
int y = rect[1];
|
||||
int right = x + rect[2];
|
||||
int bottom = y + rect[3];
|
||||
int centerX = (x + right) / 2;
|
||||
int centerY = (y + bottom) / 2;
|
||||
Sam2Input input = Sam2Input.builder(image).addPoint(centerX, centerY).addBox(x, y, right, bottom).build();
|
||||
try (NDManager manager = NDManager.newBaseManager(Device.cpu(), "PyTorch");) {
|
||||
NDList embeddings = sam2EncoderModel.predict(input);
|
||||
embeddings.attach(manager);
|
||||
input.setEmbeddings(embeddings);
|
||||
DetectedObjects detection = sam2DecoderModel.predict(input);
|
||||
// 抠图
|
||||
String mattingBase64Img = matting(manager, input, detection, false);
|
||||
|
||||
// 显示遮罩层
|
||||
String maskBase64Img = showMask(input, detection);
|
||||
logger.info("{}", detection);
|
||||
|
||||
return mattingBase64Img;
|
||||
}
|
||||
}
|
||||
|
||||
private String showMask(Sam2Input input, DetectedObjects detection) throws IOException {
|
||||
Image img = input.getImage();
|
||||
img.drawBoundingBoxes(detection, 0.8f);
|
||||
img.drawMarks(input.getPoints());
|
||||
for (Rectangle rect : input.getBoxes()) {
|
||||
OpenCVUtils.drawRectangle((Mat) img.getWrappedImage(), rect, 0xff0000, 6);
|
||||
}
|
||||
|
||||
BufferedImage bufferedImage = OpenCVUtils.mat2Image((Mat) img.getWrappedImage());
|
||||
bufferedImage = ImageUtils.removeBg(bufferedImage);
|
||||
String base64Img = ImageUtils.toBase64(bufferedImage, "jpg");
|
||||
|
||||
Path outputDir = Paths.get("build/output");
|
||||
Files.createDirectories(outputDir);
|
||||
Path imagePath = outputDir.resolve("sam2.png");
|
||||
img.save(Files.newOutputStream(imagePath), "png");
|
||||
|
||||
return base64Img;
|
||||
}
|
||||
|
||||
private String matting(NDManager manager, Sam2Input input, DetectedObjects detection, boolean gaussianBlur) throws IOException {
|
||||
Image img = input.getImage();
|
||||
List<DetectedObjects.DetectedObject> list = detection.items();
|
||||
if (list.size() == 0)
|
||||
return null;
|
||||
|
||||
DetectedObjects.DetectedObject result = list.get(0);
|
||||
BoundingBox box = result.getBoundingBox();
|
||||
if (box instanceof Mask) {
|
||||
Mask mask = (Mask) box;
|
||||
float[][] probDist = mask.getProbDist();
|
||||
NDArray oriImgArray = img.toNDArray(manager, Image.Flag.COLOR);
|
||||
oriImgArray = oriImgArray.transpose(2, 0, 1);
|
||||
NDArray pred = manager.create(probDist);
|
||||
|
||||
if (gaussianBlur) {
|
||||
pred = OpenCVUtils.gaussianBlur(manager, pred);
|
||||
}
|
||||
pred = pred.expandDims(0);
|
||||
pred = pred.concat(pred, 0).concat(pred, 0);
|
||||
|
||||
// 黑色为 0, 白色 255
|
||||
oriImgArray = oriImgArray.mul(pred);
|
||||
Image newImg = ImageFactory.getInstance().fromNDArray(oriImgArray);
|
||||
|
||||
Rectangle rect = input.getBoxes().get(0);
|
||||
newImg = newImg.getSubImage((int) rect.getX(), (int) rect.getY(), (int) rect.getWidth(), (int) rect.getWidth());
|
||||
|
||||
BufferedImage bufferedImage = OpenCVUtils.mat2Image((Mat) newImg.getWrappedImage());
|
||||
bufferedImage = ImageUtils.removeBg(bufferedImage);
|
||||
|
||||
String base64Img = ImageUtils.toBase64(bufferedImage, "png");
|
||||
|
||||
Path outputDir = Paths.get("build/output");
|
||||
Files.createDirectories(outputDir);
|
||||
ImageUtils.saveImage(bufferedImage, "img_seg.png", outputDir.toString());
|
||||
|
||||
return base64Img;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package top.aias.seg.translator;
|
||||
|
||||
import ai.djl.Device;
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.output.BoundingBox;
|
||||
import ai.djl.modality.cv.output.DetectedObjects;
|
||||
import ai.djl.modality.cv.output.Mask;
|
||||
import ai.djl.ndarray.NDArray;
|
||||
import ai.djl.ndarray.NDList;
|
||||
import ai.djl.ndarray.NDManager;
|
||||
import ai.djl.ndarray.types.DataType;
|
||||
import ai.djl.ndarray.types.Shape;
|
||||
import ai.djl.translate.NoBatchifyTranslator;
|
||||
import ai.djl.translate.TranslatorContext;
|
||||
import top.aias.seg.bean.Sam2Input;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
/**
|
||||
* sam2 解码前后处理
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
public class Sam2DecoderTranslator implements NoBatchifyTranslator<Sam2Input, DetectedObjects> {
|
||||
public Sam2DecoderTranslator() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public NDList processInput(TranslatorContext ctx, Sam2Input input) {
|
||||
Image image = input.getImage();
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
ctx.setAttachment("width", width);
|
||||
ctx.setAttachment("height", height);
|
||||
|
||||
float[] buf = input.toLocationArray(width, height);
|
||||
|
||||
NDManager manager = ctx.getNDManager();
|
||||
NDArray locations = manager.create(buf, new Shape(1, buf.length / 2, 2));
|
||||
NDArray labels = manager.create(input.getLabels());
|
||||
|
||||
NDList embeddings = input.getEmbeddings();
|
||||
|
||||
NDArray mask = manager.zeros(new Shape(1, 1, 256, 256));
|
||||
NDArray hasMask = manager.zeros(new Shape(1));
|
||||
return new NDList(
|
||||
embeddings.get(2),
|
||||
embeddings.get(0),
|
||||
embeddings.get(1),
|
||||
locations,
|
||||
labels,
|
||||
mask,
|
||||
hasMask);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public DetectedObjects processOutput(TranslatorContext ctx, NDList list) {
|
||||
try (NDManager manager = NDManager.newBaseManager(Device.cpu(), "PyTorch")) {
|
||||
NDArray logits = list.get(0);
|
||||
NDArray scores = list.get(1);
|
||||
logits.attach(manager);
|
||||
scores.attach(manager);
|
||||
scores = scores.squeeze(0);
|
||||
long best = scores.argMax().getLong();
|
||||
|
||||
int width = (Integer) ctx.getAttachment("width");
|
||||
int height = (Integer) ctx.getAttachment("height");
|
||||
|
||||
long[] size = {height, width};
|
||||
int mode = Image.Interpolation.BILINEAR.ordinal();
|
||||
logits = logits.getNDArrayInternal().interpolation(size, mode, false);
|
||||
NDArray masks = logits.gt(0f).squeeze(0);
|
||||
|
||||
float[][] dist = Mask.toMask(masks.get(best).toType(DataType.FLOAT32, true));
|
||||
Mask mask = new Mask(0, 0, width, height, dist, true);
|
||||
double probability = scores.getFloat(best);
|
||||
|
||||
List<String> classes = Collections.singletonList("");
|
||||
List<Double> probabilities = Collections.singletonList(probability);
|
||||
List<BoundingBox> boxes = Collections.singletonList(mask);
|
||||
|
||||
return new DetectedObjects(classes, probabilities, boxes);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package top.aias.seg.translator;
|
||||
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.transform.Normalize;
|
||||
import ai.djl.modality.cv.transform.Resize;
|
||||
import ai.djl.modality.cv.transform.ToTensor;
|
||||
import ai.djl.ndarray.NDArray;
|
||||
import ai.djl.ndarray.NDList;
|
||||
import ai.djl.ndarray.NDManager;
|
||||
import ai.djl.translate.NoBatchifyTranslator;
|
||||
import ai.djl.translate.Pipeline;
|
||||
import ai.djl.translate.TranslatorContext;
|
||||
import top.aias.seg.bean.Sam2Input;
|
||||
|
||||
/**
|
||||
* sam2 编码器前后处理
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
public class Sam2EncoderTranslator implements NoBatchifyTranslator<Sam2Input, NDList> {
|
||||
|
||||
private static final float[] MEAN = {0.485f, 0.456f, 0.406f};
|
||||
private static final float[] STD = {0.229f, 0.224f, 0.225f};
|
||||
|
||||
private Pipeline pipeline;
|
||||
|
||||
public Sam2EncoderTranslator() {
|
||||
pipeline = new Pipeline();
|
||||
pipeline.add(new Resize(1024, 1024));
|
||||
pipeline.add(new ToTensor());
|
||||
pipeline.add(new Normalize(MEAN, STD));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NDList processInput(TranslatorContext ctx, Sam2Input input) {
|
||||
Image image = input.getImage();
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
ctx.setAttachment("width", width);
|
||||
ctx.setAttachment("height", height);
|
||||
|
||||
NDManager manager = ctx.getNDManager();
|
||||
NDArray array = image.toNDArray(manager, Image.Flag.COLOR);
|
||||
array = pipeline.transform(new NDList(array)).get(0).expandDims(0);
|
||||
|
||||
return new NDList(array);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NDList processOutput(TranslatorContext ctx, NDList list) {
|
||||
NDArray logits = list.get(0);
|
||||
|
||||
list.detach();
|
||||
return list;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package top.aias.seg.utils;
|
||||
|
||||
/**
|
||||
* 配置常量
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
public class Constants {
|
||||
/**
|
||||
* win systems
|
||||
*/
|
||||
public static final String WIN = "win";
|
||||
|
||||
/**
|
||||
* mac system
|
||||
*/
|
||||
public static final String MAC = "mac";
|
||||
|
||||
/**
|
||||
* mac system
|
||||
*/
|
||||
public static final String LINUX = "linux";
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
package top.aias.seg.utils;
|
||||
|
||||
import ai.djl.util.Utils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 文件上传工具包
|
||||
* File upload tool package
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
public class FileUtils {
|
||||
/**
|
||||
* @param file 文件 - file
|
||||
* @param path 文件存放路径 - file storage path
|
||||
* @param fileName 源文件名 - source file name
|
||||
* @return
|
||||
*/
|
||||
public static boolean upload(MultipartFile file, String path, String fileName) {
|
||||
// 生成新的文件名
|
||||
// Generate a new file name
|
||||
//String realPath = path + "/" + FileNameUtils.getFileName(fileName);
|
||||
Path filePath = Paths.get(path + fileName);
|
||||
File dest = filePath.toAbsolutePath().toFile();
|
||||
|
||||
//判断文件父目录是否存在
|
||||
// Determine if the parent directory of the file exists
|
||||
if (!dest.getParentFile().exists()) {
|
||||
dest.getParentFile().mkdir();
|
||||
}
|
||||
|
||||
try {
|
||||
//保存文件
|
||||
// Save the file
|
||||
file.transferTo(dest);
|
||||
return true;
|
||||
} catch (IllegalStateException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件后缀
|
||||
* Get file suffix
|
||||
*
|
||||
* @param fileName
|
||||
* @return
|
||||
*/
|
||||
public static String getSuffix(String fileName) {
|
||||
return fileName.substring(fileName.lastIndexOf("."));
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成新的文件名
|
||||
* Generate a new file name
|
||||
* @param fileOriginName 源文件名 - source file name
|
||||
* @return
|
||||
*/
|
||||
public static String getFileName(String fileOriginName) {
|
||||
return UUIDUtils.getUUID() + getSuffix(fileOriginName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取json文件
|
||||
* Read json file
|
||||
*
|
||||
* @param path 文件路径信息 - file path information
|
||||
* @param fileName 文件名 - file name
|
||||
* @return
|
||||
*/
|
||||
public static String readFile(String path, String fileName) throws IOException {
|
||||
StringBuilder json = new StringBuilder();
|
||||
Path filePath = Paths.get(path + fileName);
|
||||
List<String> lines = Utils.readLines(filePath, true);
|
||||
lines.stream()
|
||||
.filter(line -> (line != null && line != ""))
|
||||
.forEach(
|
||||
line -> {
|
||||
json.append(line);
|
||||
});
|
||||
|
||||
return json.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存json文件
|
||||
* Save json file
|
||||
*
|
||||
* @param path 文件路径信息 file path information
|
||||
* @param fileName 文件名 file name
|
||||
* @param json json信息 json information
|
||||
* @return
|
||||
*/
|
||||
public static void saveFile(String path, String fileName, String json) throws IOException {
|
||||
Path filePath = Paths.get(path + fileName);
|
||||
try (PrintStream ps = new PrintStream(new FileOutputStream(filePath.toFile()))) {
|
||||
ps.print(json);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除json文件
|
||||
* Delete json file
|
||||
*
|
||||
* @param path 文件路径信息 file path information
|
||||
* @param fileName 文件名 file name
|
||||
* @return
|
||||
*/
|
||||
public static void removeFile(String path, String fileName) {
|
||||
Path filePath = Paths.get(path + fileName);
|
||||
filePath.toFile().delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check & create file path
|
||||
*
|
||||
* @param fileRelativePath 文件路径信息 - file path information
|
||||
* @return
|
||||
*/
|
||||
public static void checkAndCreatePath(String fileRelativePath) {
|
||||
//Check & create file path
|
||||
Path filePath = Paths.get(fileRelativePath).toAbsolutePath();
|
||||
File file = filePath.toFile();
|
||||
if (!file.exists() && !file.isDirectory()) {
|
||||
file.mkdirs();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,293 @@
|
||||
package top.aias.seg.utils;
|
||||
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.output.DetectedObjects;
|
||||
import ai.djl.ndarray.NDArray;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
/**
|
||||
* 图像工具类
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
public class ImageUtils {
|
||||
|
||||
/**
|
||||
* 保存BufferedImage图片
|
||||
*
|
||||
* @param bufferedImage
|
||||
* @param name
|
||||
* @param path
|
||||
*/
|
||||
public static void saveImage(BufferedImage bufferedImage, String name, String path) {
|
||||
try {
|
||||
Path outputDir = Paths.get(path);
|
||||
Path imagePath = outputDir.resolve(name);
|
||||
File output = imagePath.toFile();
|
||||
ImageIO.write(bufferedImage, "png", output);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存DJL图片
|
||||
*
|
||||
* @param img
|
||||
* @param name
|
||||
* @param path
|
||||
*/
|
||||
public static void saveImage(Image img, String name, String path) {
|
||||
Path outputDir = Paths.get(path);
|
||||
Path imagePath = outputDir.resolve(name);
|
||||
// OpenJDK 不能保存 jpg 图片的 alpha channel
|
||||
try {
|
||||
img.save(Files.newOutputStream(imagePath), "png");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存图片,含检测框
|
||||
*
|
||||
* @param img
|
||||
* @param detection
|
||||
* @param name
|
||||
* @param path
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void saveBoundingBoxImage(
|
||||
Image img, DetectedObjects detection, String name, String path) throws IOException {
|
||||
// Make image copy with alpha channel because original image was jpg
|
||||
img.drawBoundingBoxes(detection);
|
||||
Path outputDir = Paths.get(path);
|
||||
Files.createDirectories(outputDir);
|
||||
Path imagePath = outputDir.resolve(name);
|
||||
// OpenJDK can't save jpg with alpha channel
|
||||
img.save(Files.newOutputStream(imagePath), "png");
|
||||
}
|
||||
|
||||
/**
|
||||
* 画矩形
|
||||
*
|
||||
* @param mat
|
||||
* @param box
|
||||
* @return
|
||||
*/
|
||||
public static void drawRect(Mat mat, NDArray box) {
|
||||
|
||||
float[] points = box.toFloatArray();
|
||||
List<Point> list = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Point point = new Point((int) points[2 * i], (int) points[2 * i + 1]);
|
||||
list.add(point);
|
||||
}
|
||||
|
||||
Imgproc.line(mat, list.get(0), list.get(1), new Scalar(0, 255, 0), 1);
|
||||
Imgproc.line(mat, list.get(1), list.get(2), new Scalar(0, 255, 0), 1);
|
||||
Imgproc.line(mat, list.get(2), list.get(3), new Scalar(0, 255, 0), 1);
|
||||
Imgproc.line(mat, list.get(3), list.get(0), new Scalar(0, 255, 0), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 画矩形
|
||||
*
|
||||
* @param mat
|
||||
* @param box
|
||||
* @return
|
||||
*/
|
||||
public static void drawRectWithText(Mat mat, NDArray box, String text) {
|
||||
|
||||
float[] points = box.toFloatArray();
|
||||
List<Point> list = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Point point = new Point((int) points[2 * i], (int) points[2 * i + 1]);
|
||||
list.add(point);
|
||||
}
|
||||
|
||||
Imgproc.line(mat, list.get(0), list.get(1), new Scalar(0, 255, 0), 1);
|
||||
Imgproc.line(mat, list.get(1), list.get(2), new Scalar(0, 255, 0), 1);
|
||||
Imgproc.line(mat, list.get(2), list.get(3), new Scalar(0, 255, 0), 1);
|
||||
Imgproc.line(mat, list.get(3), list.get(0), new Scalar(0, 255, 0), 1);
|
||||
// 中文乱码
|
||||
Imgproc.putText(mat, text, list.get(0), Imgproc.FONT_HERSHEY_SCRIPT_SIMPLEX, 1.0, new Scalar(0, 255, 0), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 画检测框(有倾斜角)
|
||||
*
|
||||
* @param image
|
||||
* @param box
|
||||
*/
|
||||
public static void drawImageRect(BufferedImage image, NDArray box) {
|
||||
float[] points = box.toFloatArray();
|
||||
int[] xPoints = new int[5];
|
||||
int[] yPoints = new int[5];
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
xPoints[i] = (int) points[2 * i];
|
||||
yPoints[i] = (int) points[2 * i + 1];
|
||||
}
|
||||
xPoints[4] = xPoints[0];
|
||||
yPoints[4] = yPoints[0];
|
||||
|
||||
// 将绘制图像转换为Graphics2D
|
||||
Graphics2D g = (Graphics2D) image.getGraphics();
|
||||
try {
|
||||
g.setColor(new Color(0, 255, 0));
|
||||
// 声明画笔属性 :粗 细(单位像素)末端无修饰 折线处呈尖角
|
||||
BasicStroke bStroke = new BasicStroke(4, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
|
||||
g.setStroke(bStroke);
|
||||
g.drawPolyline(xPoints, yPoints, 5); // xPoints, yPoints, nPoints
|
||||
} finally {
|
||||
g.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 画检测框(有倾斜角)和文本
|
||||
*
|
||||
* @param image
|
||||
* @param box
|
||||
* @param text
|
||||
*/
|
||||
public static void drawImageRectWithText(BufferedImage image, NDArray box, String text) {
|
||||
float[] points = box.toFloatArray();
|
||||
int[] xPoints = new int[5];
|
||||
int[] yPoints = new int[5];
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
xPoints[i] = (int) points[2 * i];
|
||||
yPoints[i] = (int) points[2 * i + 1];
|
||||
}
|
||||
xPoints[4] = xPoints[0];
|
||||
yPoints[4] = yPoints[0];
|
||||
|
||||
// 将绘制图像转换为Graphics2D
|
||||
Graphics2D g = (Graphics2D) image.getGraphics();
|
||||
try {
|
||||
int fontSize = 32;
|
||||
Font font = new Font("楷体", Font.PLAIN, fontSize);
|
||||
g.setFont(font);
|
||||
g.setColor(new Color(0, 0, 255));
|
||||
// 声明画笔属性 :粗 细(单位像素)末端无修饰 折线处呈尖角
|
||||
BasicStroke bStroke = new BasicStroke(2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
|
||||
g.setStroke(bStroke);
|
||||
g.drawPolyline(xPoints, yPoints, 5); // xPoints, yPoints, nPoints
|
||||
g.drawString(text, xPoints[0], yPoints[0]);
|
||||
} finally {
|
||||
g.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 画检测框
|
||||
*
|
||||
* @param image
|
||||
* @param x
|
||||
* @param y
|
||||
* @param width
|
||||
* @param height
|
||||
*/
|
||||
public static void drawImageRect(BufferedImage image, int x, int y, int width, int height) {
|
||||
// 将绘制图像转换为Graphics2D
|
||||
Graphics2D g = (Graphics2D) image.getGraphics();
|
||||
try {
|
||||
g.setColor(new Color(0, 255, 0));
|
||||
// 声明画笔属性 :粗 细(单位像素)末端无修饰 折线处呈尖角
|
||||
BasicStroke bStroke = new BasicStroke(2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
|
||||
g.setStroke(bStroke);
|
||||
g.drawRect(x, y, width, height);
|
||||
} finally {
|
||||
g.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示文字
|
||||
*
|
||||
* @param image
|
||||
* @param text
|
||||
* @param x
|
||||
* @param y
|
||||
*/
|
||||
public static void drawImageText(BufferedImage image, String text, int x, int y) {
|
||||
Graphics graphics = image.getGraphics();
|
||||
int fontSize = 32;
|
||||
Font font = new Font("楷体", Font.PLAIN, fontSize);
|
||||
try {
|
||||
graphics.setFont(font);
|
||||
graphics.setColor(new Color(0, 0, 255));
|
||||
int strWidth = graphics.getFontMetrics().stringWidth(text);
|
||||
graphics.drawString(text, x, y);
|
||||
} finally {
|
||||
graphics.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* BufferedImage 转 base64
|
||||
* @param image
|
||||
* @param type - JPG、PNG、GIF、BMP 等
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static String toBase64(BufferedImage image, String type) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ImageIO.write(image, type, baos);
|
||||
byte[] bytes = baos.toByteArray();
|
||||
return Base64.getEncoder().encodeToString(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除背景, 返回 png 格式图片
|
||||
*
|
||||
* @param image
|
||||
* @return
|
||||
*/
|
||||
public static BufferedImage removeBg(BufferedImage image) {
|
||||
// 获取图片的宽度和高度
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
|
||||
// 创建一个新的BufferedImage,类型为ARGB,用于存储转换后的图片
|
||||
BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
// 遍历每个像素
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
// 获取当前像素的RGB值
|
||||
int rgba = image.getRGB(x, y);
|
||||
// 将RGB值转换为颜色对象
|
||||
Color color = new Color(rgba, true);
|
||||
// 如果当前像素是黑色,则将Alpha通道值设置为0
|
||||
if (color.getRed() == 0 && color.getGreen() == 0 && color.getBlue() == 0) {
|
||||
color = new Color(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// 将修改后的颜色设置到新的BufferedImage中
|
||||
newImage.setRGB(x, y, color.getRGB());
|
||||
}
|
||||
}
|
||||
return newImage;
|
||||
}
|
||||
}
|
@ -0,0 +1,339 @@
|
||||
package top.aias.seg.utils;
|
||||
|
||||
import ai.djl.ndarray.NDArray;
|
||||
import ai.djl.ndarray.NDManager;
|
||||
import ai.djl.ndarray.index.NDIndex;
|
||||
import ai.djl.ndarray.types.DataType;
|
||||
import ai.djl.ndarray.types.Shape;
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.MatOfPoint;
|
||||
import org.opencv.core.Point;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
/**
|
||||
* NDArray Utils 工具类
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
public class NDArrayUtils {
|
||||
/**
|
||||
* Sigmoid 激活函数
|
||||
*
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static NDArray Sigmoid(NDArray input) {
|
||||
// Sigmoid 函数,即f(x)=1/(1+e-x)
|
||||
return input.neg().exp().add(1).pow(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* np.arctan2和np.arctan都是计算反正切值的NumPy函数,但它们的参数和返回值不同。一般来说,np.arctan2的参数为(y, x),
|
||||
* 返回值为[-π, π]之间的弧度值;而np.arctan的参数为x,返回值为[-π/2, π/2]之间的弧度值。两者之间的换算关系是:
|
||||
* np.arctan(y/x) = np.arctan2(y, x)(当x>0时),
|
||||
* 或 np.pi + np.arctan(y/x) = np.arctan2(y, x) (当x<0且y>=0时),
|
||||
* 或 np.pi - np.arctan(y/x) = np.arctan2(y, x) (当x<0且y<0时)。
|
||||
* @param y
|
||||
* @param x
|
||||
* @return
|
||||
*/
|
||||
public static NDArray arctan2(NDArray y, NDArray x) {
|
||||
NDArray x_neg = x.lt(0).toType(DataType.INT32, false);
|
||||
NDArray y_pos = y.gte(0).toType(DataType.INT32, false);
|
||||
NDArray y_neg = y.lt(0).toType(DataType.INT32, false);
|
||||
|
||||
NDArray theta = y.div(x).atan();
|
||||
// np.arctan(y/x) + np.pi = np.arctan2(y, x) (当x<0且y>=0时)
|
||||
theta = theta.add(x_neg.mul(y_pos).mul((float) Math.PI));
|
||||
// np.arctan(y/x) - np.pi = np.arctan2(y, x) (当x<0且y<0时)
|
||||
theta = theta.add(x_neg.mul(y_neg).mul(-(float) Math.PI));
|
||||
|
||||
theta = theta.mul(180).div((float) Math.PI);
|
||||
|
||||
return theta;
|
||||
}
|
||||
|
||||
/**
|
||||
* 最大池化
|
||||
*
|
||||
* @param manager
|
||||
* @param heat
|
||||
* @param ksize
|
||||
* @param stride
|
||||
* @param padding
|
||||
* @return
|
||||
*/
|
||||
public static NDArray maxPool(NDManager manager, NDArray heat, int ksize, int stride, int padding) {
|
||||
int rows = (int) (heat.getShape().get(0));
|
||||
int cols = (int) (heat.getShape().get(1));
|
||||
// hmax = F.max_pool2d( heat, (ksize, ksize), stride=1, padding=(ksize-1)//2)
|
||||
NDArray max_pool2d = manager.zeros(new Shape(rows + 2 * padding, cols + 2 * padding));
|
||||
max_pool2d.set(new NDIndex(padding + ":" + (rows + padding) + ","+ padding + ":" + (cols + padding)), heat);
|
||||
float[][] max_pool2d_arr = NDArrayUtils.floatNDArrayToArray(max_pool2d);
|
||||
float[][] arr = new float[rows][cols];
|
||||
|
||||
for (int row = 0; row < rows; row++) {
|
||||
for (int col = 0; col < cols; col++) {
|
||||
float max = max_pool2d_arr[row][col];
|
||||
for (int i = row; i < row + ksize; i++) {
|
||||
for (int j = col; j < col + ksize; j++) {
|
||||
if (max_pool2d_arr[i][j] > max) {
|
||||
max = max_pool2d_arr[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
arr[row][col] = max;
|
||||
}
|
||||
}
|
||||
|
||||
NDArray hmax = manager.create(arr).reshape(rows, cols);
|
||||
return hmax;
|
||||
}
|
||||
|
||||
/**
|
||||
* mat To MatOfPoint
|
||||
*
|
||||
* @param mat
|
||||
* @return
|
||||
*/
|
||||
public static MatOfPoint matToMatOfPoint(Mat mat) {
|
||||
int rows = mat.rows();
|
||||
MatOfPoint matOfPoint = new MatOfPoint();
|
||||
|
||||
List<Point> list = new ArrayList<>();
|
||||
for (int i = 0; i < rows; i++) {
|
||||
Point point = new Point((float) mat.get(i, 0)[0], (float) mat.get(i, 1)[0]);
|
||||
list.add(point);
|
||||
}
|
||||
matOfPoint.fromList(list);
|
||||
|
||||
return matOfPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* int NDArray To int[][] Array
|
||||
*
|
||||
* @param ndArray
|
||||
* @return
|
||||
*/
|
||||
public static int[][] intNDArrayToArray(NDArray ndArray) {
|
||||
int rows = (int) (ndArray.getShape().get(0));
|
||||
int cols = (int) (ndArray.getShape().get(1));
|
||||
int[][] arr = new int[rows][cols];
|
||||
|
||||
int[] arrs = ndArray.toIntArray();
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < cols; j++) {
|
||||
arr[i][j] = arrs[i * cols + j];
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* float NDArray To float[][] Array
|
||||
*
|
||||
* @param ndArray
|
||||
* @return
|
||||
*/
|
||||
public static float[][] floatNDArrayToArray(NDArray ndArray) {
|
||||
int rows = (int) (ndArray.getShape().get(0));
|
||||
int cols = (int) (ndArray.getShape().get(1));
|
||||
float[][] arr = new float[rows][cols];
|
||||
|
||||
float[] arrs = ndArray.toFloatArray();
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < cols; j++) {
|
||||
arr[i][j] = arrs[i * cols + j];
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* mat To double[][] Array
|
||||
*
|
||||
* @param mat
|
||||
* @return
|
||||
*/
|
||||
public static double[][] matToDoubleArray(Mat mat) {
|
||||
int rows = mat.rows();
|
||||
int cols = mat.cols();
|
||||
|
||||
double[][] doubles = new double[rows][cols];
|
||||
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < cols; j++) {
|
||||
doubles[i][j] = mat.get(i, j)[0];
|
||||
}
|
||||
}
|
||||
|
||||
return doubles;
|
||||
}
|
||||
|
||||
/**
|
||||
* mat To float[][] Array
|
||||
*
|
||||
* @param mat
|
||||
* @return
|
||||
*/
|
||||
public static float[][] matToFloatArray(Mat mat) {
|
||||
int rows = mat.rows();
|
||||
int cols = mat.cols();
|
||||
|
||||
float[][] floats = new float[rows][cols];
|
||||
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < cols; j++) {
|
||||
floats[i][j] = (float) mat.get(i, j)[0];
|
||||
}
|
||||
}
|
||||
|
||||
return floats;
|
||||
}
|
||||
|
||||
/**
|
||||
* mat To byte[][] Array
|
||||
*
|
||||
* @param mat
|
||||
* @return
|
||||
*/
|
||||
public static byte[][] matToUint8Array(Mat mat) {
|
||||
int rows = mat.rows();
|
||||
int cols = mat.cols();
|
||||
|
||||
byte[][] bytes = new byte[rows][cols];
|
||||
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < cols; j++) {
|
||||
bytes[i][j] = (byte) mat.get(i, j)[0];
|
||||
}
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* float NDArray To Mat
|
||||
*
|
||||
* @param ndArray
|
||||
* @param cvType
|
||||
* @return
|
||||
*/
|
||||
public static Mat floatNDArrayToMat(NDArray ndArray, int cvType) {
|
||||
int rows = (int) (ndArray.getShape().get(0));
|
||||
int cols = (int) (ndArray.getShape().get(1));
|
||||
Mat mat = new Mat(rows, cols, cvType);
|
||||
|
||||
float[] arrs = ndArray.toFloatArray();
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < cols; j++) {
|
||||
mat.put(i, j, arrs[i * cols + j]);
|
||||
}
|
||||
}
|
||||
return mat;
|
||||
}
|
||||
|
||||
/**
|
||||
* float NDArray To Mat
|
||||
*
|
||||
* @param ndArray
|
||||
* @return
|
||||
*/
|
||||
public static Mat floatNDArrayToMat(NDArray ndArray) {
|
||||
int rows = (int) (ndArray.getShape().get(0));
|
||||
int cols = (int) (ndArray.getShape().get(1));
|
||||
Mat mat = new Mat(rows, cols, CvType.CV_32F);
|
||||
|
||||
float[] arrs = ndArray.toFloatArray();
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < cols; j++) {
|
||||
mat.put(i, j, arrs[i * cols + j]);
|
||||
}
|
||||
}
|
||||
|
||||
return mat;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* uint8 NDArray To Mat
|
||||
*
|
||||
* @param ndArray
|
||||
* @return
|
||||
*/
|
||||
public static Mat uint8NDArrayToMat(NDArray ndArray) {
|
||||
int rows = (int) (ndArray.getShape().get(0));
|
||||
int cols = (int) (ndArray.getShape().get(1));
|
||||
Mat mat = new Mat(rows, cols, CvType.CV_8U);
|
||||
|
||||
byte[] arrs = ndArray.toByteArray();
|
||||
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < cols; j++) {
|
||||
mat.put(i, j, arrs[i * cols + j]);
|
||||
}
|
||||
}
|
||||
return mat;
|
||||
}
|
||||
|
||||
/**
|
||||
* float[][] Array To Mat
|
||||
* @param arr
|
||||
* @return
|
||||
*/
|
||||
public static Mat floatArrayToMat(float[][] arr) {
|
||||
int rows = arr.length;
|
||||
int cols = arr[0].length;
|
||||
Mat mat = new Mat(rows, cols, CvType.CV_32F);
|
||||
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < cols; j++) {
|
||||
mat.put(i, j, arr[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
/**
|
||||
* uint8Array To Mat
|
||||
* @param arr
|
||||
* @return
|
||||
*/
|
||||
public static Mat uint8ArrayToMat(byte[][] arr) {
|
||||
int rows = arr.length;
|
||||
int cols = arr[0].length;
|
||||
Mat mat = new Mat(rows, cols, CvType.CV_8U);
|
||||
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < cols; j++) {
|
||||
mat.put(i, j, arr[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* list 转 Mat
|
||||
*
|
||||
* @param points
|
||||
* @return
|
||||
*/
|
||||
public static Mat toMat(List<ai.djl.modality.cv.output.Point> points) {
|
||||
Mat mat = new Mat(points.size(), 2, CvType.CV_32F);
|
||||
for (int i = 0; i < points.size(); i++) {
|
||||
ai.djl.modality.cv.output.Point point = points.get(i);
|
||||
mat.put(i, 0, (float) point.getX());
|
||||
mat.put(i, 1, (float) point.getY());
|
||||
}
|
||||
|
||||
return mat;
|
||||
}
|
||||
}
|
@ -0,0 +1,293 @@
|
||||
package top.aias.seg.utils;
|
||||
|
||||
import ai.djl.modality.cv.output.Rectangle;
|
||||
import ai.djl.ndarray.NDArray;
|
||||
import ai.djl.ndarray.NDManager;
|
||||
import org.opencv.core.*;
|
||||
import top.aias.seg.bean.Point;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferByte;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* OpenCV Utils 工具类
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
public class OpenCVUtils {
|
||||
/**
|
||||
* 高斯滤波器(GaussianFilter)对图像进行平滑处理
|
||||
* @param manager
|
||||
* @param ndArray
|
||||
* @return
|
||||
*/
|
||||
public static NDArray gaussianBlur(NDManager manager, NDArray ndArray) {
|
||||
org.opencv.core.Mat src = NDArrayUtils.floatNDArrayToMat(ndArray);
|
||||
org.opencv.core.Mat morphMat = src.clone();
|
||||
org.opencv.core.Mat gaussMat = src.clone();
|
||||
org.opencv.core.Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(3, 3));
|
||||
|
||||
// 形态学操作函数: 它可以对图像进行膨胀、腐蚀、开运算、闭运算等操作,从而得到更好的效果。
|
||||
Imgproc.morphologyEx(src, morphMat, Imgproc.MORPH_OPEN, kernel);
|
||||
// 高斯滤波器(GaussianFilter)对图像进行平滑处理
|
||||
Imgproc.GaussianBlur(morphMat, gaussMat, new Size(5, 5), 2.0f, 2.0f);
|
||||
float[][] gaussArr = NDArrayUtils.matToFloatArray(gaussMat);
|
||||
NDArray gaussNDArray = manager.create(gaussArr);
|
||||
|
||||
// release mat
|
||||
src.release();
|
||||
morphMat.release();
|
||||
gaussMat.release();
|
||||
kernel.release();
|
||||
|
||||
return gaussNDArray;
|
||||
}
|
||||
/**
|
||||
* Draws a rectangle on the image.
|
||||
*
|
||||
* @param rectangle the rectangle to draw
|
||||
* @param rgb the color
|
||||
* @param stroke the thickness
|
||||
*/
|
||||
public static void drawRectangle(Mat image, Rectangle rectangle, int rgb, int stroke) {
|
||||
Rect rect =
|
||||
new Rect(
|
||||
(int) rectangle.getX(),
|
||||
(int) rectangle.getY(),
|
||||
(int) rectangle.getWidth(),
|
||||
(int) rectangle.getHeight());
|
||||
int r = (rgb & 0xff0000) >> 16;
|
||||
int g = (rgb & 0x00ff00) >> 8;
|
||||
int b = rgb & 0x0000ff;
|
||||
Scalar color = new Scalar(b, g, r);
|
||||
Imgproc.rectangle(image, rect.tl(), rect.br(), color, stroke);
|
||||
}
|
||||
/**
|
||||
* Mat to BufferedImage
|
||||
*
|
||||
* @param mat
|
||||
* @return
|
||||
*/
|
||||
public static BufferedImage mat2Image(Mat mat) {
|
||||
int width = mat.width();
|
||||
int height = mat.height();
|
||||
byte[] data = new byte[width * height * (int) mat.elemSize()];
|
||||
Imgproc.cvtColor(mat, mat, 4);
|
||||
mat.get(0, 0, data);
|
||||
BufferedImage ret = new BufferedImage(width, height, 5);
|
||||
ret.getRaster().setDataElements(0, 0, width, height, data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* BufferedImage to Mat
|
||||
*
|
||||
* @param img
|
||||
* @return
|
||||
*/
|
||||
public static Mat image2Mat(BufferedImage img) {
|
||||
int width = img.getWidth();
|
||||
int height = img.getHeight();
|
||||
byte[] data = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
|
||||
Mat mat = new Mat(height, width, CvType.CV_8UC3);
|
||||
mat.put(0, 0, data);
|
||||
return mat;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* list 转 Mat
|
||||
*
|
||||
* @param points
|
||||
* @return
|
||||
*/
|
||||
public static Mat toMat(List<Point> points) {
|
||||
Mat mat = new Mat(points.size(), 2, CvType.CV_32F);
|
||||
for (int i = 0; i < points.size(); i++) {
|
||||
Point point = points.get(i);
|
||||
mat.put(i, 0, (float) point.getX());
|
||||
mat.put(i, 1, (float) point.getY());
|
||||
}
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
/**
|
||||
* 透视变换
|
||||
*
|
||||
* @param src
|
||||
* @param dst
|
||||
* @param warp_mat
|
||||
* @return
|
||||
*/
|
||||
public static Mat warpPerspective(Mat src, Mat dst, Mat warp_mat) {
|
||||
Mat dstClone = dst.clone();
|
||||
// org.opencv.core.Mat mat = new org.opencv.core.Mat(dst.rows(), dst.cols(), CvType.CV_8UC3);
|
||||
Imgproc.warpPerspective(src, dstClone, warp_mat, dst.size());
|
||||
return dstClone;
|
||||
}
|
||||
|
||||
/**
|
||||
* 透视变换
|
||||
*
|
||||
* @param src
|
||||
* @param srcPoints
|
||||
* @param dstPoints
|
||||
* @return
|
||||
*/
|
||||
public static Mat perspectiveTransform(Mat src, Mat srcPoints, Mat dstPoints) {
|
||||
Mat dst = src.clone();
|
||||
Mat warp_mat = Imgproc.getPerspectiveTransform(srcPoints, dstPoints);
|
||||
Imgproc.warpPerspective(src, dst, warp_mat, dst.size());
|
||||
warp_mat.release();
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**
|
||||
* 透视变换
|
||||
*
|
||||
* @param src
|
||||
* @param dst
|
||||
* @param srcPoints
|
||||
* @param dstPoints
|
||||
* @return
|
||||
*/
|
||||
public static Mat perspectiveTransform(Mat src, Mat dst, Mat srcPoints, Mat dstPoints) {
|
||||
Mat dstClone = dst.clone();
|
||||
Mat warp_mat = Imgproc.getPerspectiveTransform(srcPoints, dstPoints);
|
||||
Imgproc.warpPerspective(src, dstClone, warp_mat, dst.size());
|
||||
warp_mat.release();
|
||||
|
||||
return dstClone;
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片裁剪
|
||||
*
|
||||
* @param points
|
||||
* @return
|
||||
*/
|
||||
public static int[] imgCrop(float[] points) {
|
||||
int[] wh = new int[2];
|
||||
float[] lt = java.util.Arrays.copyOfRange(points, 0, 2);
|
||||
float[] rt = java.util.Arrays.copyOfRange(points, 2, 4);
|
||||
float[] rb = java.util.Arrays.copyOfRange(points, 4, 6);
|
||||
float[] lb = java.util.Arrays.copyOfRange(points, 6, 8);
|
||||
wh[0] = (int) Math.max(PointUtils.distance(lt, rt), PointUtils.distance(rb, lb));
|
||||
wh[1] = (int) Math.max(PointUtils.distance(lt, lb), PointUtils.distance(rt, rb));
|
||||
return wh;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转正图片
|
||||
*
|
||||
* @param mat
|
||||
* @param points
|
||||
* @return
|
||||
*/
|
||||
public static Mat perspectiveTransform(Mat mat, float[] points) {
|
||||
float[] lt = java.util.Arrays.copyOfRange(points, 0, 2);
|
||||
float[] rt = java.util.Arrays.copyOfRange(points, 2, 4);
|
||||
float[] rb = java.util.Arrays.copyOfRange(points, 4, 6);
|
||||
float[] lb = java.util.Arrays.copyOfRange(points, 6, 8);
|
||||
int img_crop_width = (int) Math.max(PointUtils.distance(lt, rt), PointUtils.distance(rb, lb));
|
||||
int img_crop_height = (int) Math.max(PointUtils.distance(lt, lb), PointUtils.distance(rt, rb));
|
||||
List<Point> srcPoints = new ArrayList<>();
|
||||
srcPoints.add(new Point((int)lt[0], (int)lt[1]));
|
||||
srcPoints.add(new Point((int)rt[0], (int)rt[1]));
|
||||
srcPoints.add(new Point((int)rb[0], (int)rb[1]));
|
||||
srcPoints.add(new Point((int)lb[0], (int)lb[1]));
|
||||
List<Point> dstPoints = new ArrayList<>();
|
||||
dstPoints.add(new Point(0, 0));
|
||||
dstPoints.add(new Point(img_crop_width, 0));
|
||||
dstPoints.add(new Point(img_crop_width, img_crop_height));
|
||||
dstPoints.add(new Point(0, img_crop_height));
|
||||
|
||||
Mat srcPoint2f = toMat(srcPoints);
|
||||
Mat dstPoint2f = toMat(dstPoints);
|
||||
|
||||
Mat cvMat = OpenCVUtils.perspectiveTransform(mat, srcPoint2f, dstPoint2f);
|
||||
srcPoint2f.release();
|
||||
dstPoint2f.release();
|
||||
return cvMat;
|
||||
}
|
||||
/**
|
||||
* 转正图片 - 废弃
|
||||
*
|
||||
* @param mat
|
||||
* @param points
|
||||
* @return
|
||||
*/
|
||||
public Mat perspectiveTransformOld(Mat mat, float[] points) {
|
||||
List<org.opencv.core.Point> pointList = new ArrayList<>();
|
||||
float[][] srcArr = new float[4][2];
|
||||
float min_X = Float.MAX_VALUE;
|
||||
float min_Y = Float.MAX_VALUE;
|
||||
float max_X = -1;
|
||||
float max_Y = -1;
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
org.opencv.core.Point pt = new org.opencv.core.Point(points[2 * j], points[2 * j + 1]);
|
||||
pointList.add(pt);
|
||||
srcArr[j][0] = points[2 * j];
|
||||
srcArr[j][1] = points[2 * j + 1];
|
||||
if (points[2 * j] > max_X) {
|
||||
max_X = points[2 * j];
|
||||
}
|
||||
if (points[2 * j] < min_X) {
|
||||
min_X = points[2 * j];
|
||||
}
|
||||
if (points[2 * j + 1] > max_Y) {
|
||||
max_Y = points[2 * j + 1];
|
||||
}
|
||||
if (points[2 * j + 1] < min_Y) {
|
||||
min_Y = points[2 * j + 1];
|
||||
}
|
||||
}
|
||||
|
||||
Mat src = NDArrayUtils.floatArrayToMat(srcArr);
|
||||
|
||||
float width = max_Y - min_Y;
|
||||
float height = max_X - min_X;
|
||||
|
||||
float[][] dstArr = new float[4][2];
|
||||
dstArr[0] = new float[]{0, 0};
|
||||
dstArr[1] = new float[]{width - 1, 0};
|
||||
dstArr[2] = new float[]{width - 1, height - 1};
|
||||
dstArr[3] = new float[]{0, height - 1};
|
||||
|
||||
Mat dst = NDArrayUtils.floatArrayToMat(dstArr);
|
||||
return OpenCVUtils.perspectiveTransform(mat, src, dst);
|
||||
}
|
||||
|
||||
/**
|
||||
* 画边框
|
||||
*
|
||||
* @param mat
|
||||
* @param squares
|
||||
* @param topK
|
||||
*/
|
||||
public static void drawSquares(Mat mat, NDArray squares, int topK) {
|
||||
for (int i = 0; i < topK; i++) {
|
||||
float[] points = squares.get(i).toFloatArray();
|
||||
List<MatOfPoint> matOfPoints = new ArrayList<>();
|
||||
MatOfPoint matOfPoint = new MatOfPoint();
|
||||
matOfPoints.add(matOfPoint);
|
||||
List<org.opencv.core.Point> pointList = new ArrayList<>();
|
||||
for (int j = 0; j < 4; j++) {
|
||||
org.opencv.core.Point pt = new org.opencv.core.Point(points[2 * j], points[2 * j + 1]);
|
||||
pointList.add(pt);
|
||||
Imgproc.circle(mat, pt, 10, new Scalar(0, 255, 255), -1);
|
||||
Imgproc.putText(mat, "" + j, pt, Imgproc.FONT_HERSHEY_SCRIPT_SIMPLEX, 1.0, new Scalar(0, 255, 0), 1);
|
||||
}
|
||||
matOfPoint.fromList(pointList);
|
||||
Imgproc.polylines(mat, matOfPoints, true, new Scalar(200, 200, 0), 5);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,343 @@
|
||||
package top.aias.seg.utils;
|
||||
|
||||
import ai.djl.ndarray.NDArray;
|
||||
import ai.djl.ndarray.NDArrays;
|
||||
import ai.djl.ndarray.NDList;
|
||||
import ai.djl.ndarray.NDManager;
|
||||
import ai.djl.ndarray.types.Shape;
|
||||
import top.aias.seg.bean.Point;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 点工具类
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
public class PointUtils {
|
||||
/**
|
||||
* 计算两点距离
|
||||
* @param point1
|
||||
* @param point2
|
||||
* @return
|
||||
*/
|
||||
public static float distance(float[] point1, float[] point2) {
|
||||
float disX = point1[0] - point2[0];
|
||||
float disY = point1[1] - point2[1];
|
||||
float dis = (float) Math.sqrt(disX * disX + disY * disY);
|
||||
return dis;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两点距离
|
||||
* @param point1
|
||||
* @param point2
|
||||
* @return
|
||||
*/
|
||||
public static float distance(Point point1, Point point2) {
|
||||
double disX = point1.getX() - point2.getX();
|
||||
double disY = point1.getY() - point2.getY();
|
||||
float dis = (float) Math.sqrt(disX * disX + disY * disY);
|
||||
return dis;
|
||||
}
|
||||
|
||||
/**
|
||||
* sort the points based on their x-coordinates
|
||||
* 顺时针排序
|
||||
*
|
||||
* @param pts
|
||||
* @return
|
||||
*/
|
||||
|
||||
private static NDArray order_points_clockwise(NDArray pts) {
|
||||
NDList list = new NDList();
|
||||
long[] indexes = pts.get(":, 0").argSort().toLongArray();
|
||||
|
||||
// grab the left-most and right-most points from the sorted
|
||||
// x-roodinate points
|
||||
Shape s1 = pts.getShape();
|
||||
NDArray leftMost1 = pts.get(indexes[0] + ",:");
|
||||
NDArray leftMost2 = pts.get(indexes[1] + ",:");
|
||||
NDArray leftMost = leftMost1.concat(leftMost2).reshape(2, 2);
|
||||
NDArray rightMost1 = pts.get(indexes[2] + ",:");
|
||||
NDArray rightMost2 = pts.get(indexes[3] + ",:");
|
||||
NDArray rightMost = rightMost1.concat(rightMost2).reshape(2, 2);
|
||||
|
||||
// now, sort the left-most coordinates according to their
|
||||
// y-coordinates so we can grab the top-left and bottom-left
|
||||
// points, respectively
|
||||
indexes = leftMost.get(":, 1").argSort().toLongArray();
|
||||
NDArray lt = leftMost.get(indexes[0] + ",:");
|
||||
NDArray lb = leftMost.get(indexes[1] + ",:");
|
||||
indexes = rightMost.get(":, 1").argSort().toLongArray();
|
||||
NDArray rt = rightMost.get(indexes[0] + ",:");
|
||||
NDArray rb = rightMost.get(indexes[1] + ",:");
|
||||
|
||||
list.add(lt);
|
||||
list.add(rt);
|
||||
list.add(rb);
|
||||
list.add(lb);
|
||||
|
||||
NDArray rect = NDArrays.concat(list).reshape(4, 2);
|
||||
return rect;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算四边形的面积
|
||||
* 根据海伦公式(Heron's formula)计算面积
|
||||
*
|
||||
* @param arr
|
||||
* @return
|
||||
*/
|
||||
public static double getQuadArea(NDManager manager, double[][] arr) {
|
||||
NDArray ndArray = manager.create(arr).reshape(4, 2);
|
||||
ndArray = order_points_clockwise(ndArray);
|
||||
double[] array = ndArray.toDoubleArray();
|
||||
|
||||
double x1 = array[0];
|
||||
double y1 = array[1];
|
||||
double x2 = array[2];
|
||||
double y2 = array[3];
|
||||
double x3 = array[4];
|
||||
double y3 = array[5];
|
||||
double x4 = array[6];
|
||||
double y4 = array[7];
|
||||
|
||||
double totalArea;
|
||||
if (isInTriangle(x2, y2, x3, y3, x4, y4, x1, y1)) { // 判断点 (x1, y1) 是否在三角形 (x2,y2),(x3,y3),(x4,y4) 内
|
||||
double area1 = getTriangleArea(x2, y2, x3, y3, x1, y1);
|
||||
double area2 = getTriangleArea(x2, y2, x4, y4, x1, y1);
|
||||
double area3 = getTriangleArea(x3, y3, x4, y4, x1, y1);
|
||||
totalArea = area1 + area2 + area3;
|
||||
} else if (isInTriangle(x1, y1, x3, y3, x4, y4, x2, y2)) {// 判断点 (x2, y2) 是否在三角形 (x1,y1),(x3,y3),(x4,y4) 内
|
||||
double area1 = getTriangleArea(x1, y1, x3, y3, x2, y2);
|
||||
double area2 = getTriangleArea(x1, y1, x4, y4, x2, y2);
|
||||
double area3 = getTriangleArea(x3, y3, x4, y4, x2, y2);
|
||||
totalArea = area1 + area2 + area3;
|
||||
} else if (isInTriangle(x1, y1, x2, y2, x4, y4, x3, y3)) {// 判断点 (x3, y3) 是否在三角形 (x1,y1),(x2,y2),(x4,y4) 内
|
||||
double area1 = getTriangleArea(x1, y1, x2, y2, x3, y3);
|
||||
double area2 = getTriangleArea(x1, y1, x4, y4, x3, y3);
|
||||
double area3 = getTriangleArea(x2, y2, x4, y4, x3, y3);
|
||||
totalArea = area1 + area2 + area3;
|
||||
} else if (isInTriangle(x1, y1, x2, y2, x3, y3, x4, y4)) {// 判断点 (x4, y4) 是否在三角形 (x1,y1),(x2,y2),(x3,y3) 内
|
||||
double area1 = getTriangleArea(x1, y1, x2, y2, x4, y4);
|
||||
double area2 = getTriangleArea(x1, y1, x3, y3, x4, y4);
|
||||
double area3 = getTriangleArea(x2, y2, x3, y3, x4, y4);
|
||||
totalArea = area1 + area2 + area3;
|
||||
} else {
|
||||
double area1 = getTriangleArea(x1, y1, x2, y2, x3, y3);
|
||||
double area2 = getTriangleArea(x1, y1, x3, y3, x4, y4);
|
||||
totalArea = area1 + area2;
|
||||
}
|
||||
|
||||
return totalArea;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断点 (px, py) 是否在三角形 (x1,y1),(x2,y2),(x3,y3) 内
|
||||
*
|
||||
* @param x1
|
||||
* @param y1
|
||||
* @param x2
|
||||
* @param y2
|
||||
* @param x3
|
||||
* @param y3
|
||||
* @param px
|
||||
* @param py
|
||||
* @return
|
||||
*/
|
||||
public static boolean isInTriangle(double x1, double y1, double x2, double y2, double x3, double y3, double px, double py) {
|
||||
if(!isTriangle(x1, y1, x2, y2, px, py))
|
||||
return false;
|
||||
double area1 = getTriangleArea(x1, y1, x2, y2, px, py);
|
||||
if(!isTriangle(x1, y1, x3, y3, px, py))
|
||||
return false;
|
||||
double area2 = getTriangleArea(x1, y1, x3, y3, px, py);
|
||||
if(!isTriangle(x2, y2, x3, y3, px, py))
|
||||
return false;
|
||||
double area3 = getTriangleArea(x2, y2, x3, y3, px, py);
|
||||
if(!isTriangle(x1, y1, x2, y2, x3, y3))
|
||||
return false;
|
||||
double totalArea = getTriangleArea(x1, y1, x2, y2, x3, y3);
|
||||
double delta = Math.abs(totalArea - (area1 + area2 + area3));
|
||||
if (delta < 1)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 给定3个点坐标(x1,y1),(x2,y2),(x3,y3),给出判断是否能组成三角形
|
||||
* @param x1
|
||||
* @param y1
|
||||
* @param x2
|
||||
* @param y2
|
||||
* @param x3
|
||||
* @param y3
|
||||
* @return
|
||||
*/
|
||||
public static boolean isTriangle(double x1, double y1, double x2, double y2, double x3, double y3) {
|
||||
double a = Math.sqrt(Math.pow(x1-x2, 2) + Math.pow(y1-y2, 2));
|
||||
double b = Math.sqrt(Math.pow(x1-x3, 2) + Math.pow(y1-y3, 2));
|
||||
double c = Math.sqrt(Math.pow(x2-x3, 2) + Math.pow(y2-y3, 2));
|
||||
return a + b > c && b + c > a && a + c > b;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算三角形的面积
|
||||
* 根据海伦公式(Heron's formula)计算三角形面积
|
||||
*
|
||||
* @param x1
|
||||
* @param y1
|
||||
* @param x2
|
||||
* @param y2
|
||||
* @param x3
|
||||
* @param y3
|
||||
* @return
|
||||
*/
|
||||
public static double getTriangleArea(double x1, double y1, double x2, double y2, double x3, double y3) {
|
||||
double a = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
|
||||
double b = Math.sqrt(Math.pow(x3 - x2, 2) + Math.pow(y3 - y2, 2));
|
||||
double c = Math.sqrt(Math.pow(x1 - x3, 2) + Math.pow(y1 - y3, 2));
|
||||
double p = (a + b + c) / 2;
|
||||
double area = Math.sqrt(p * (p - a) * (p - b) * (p - c));
|
||||
return area;
|
||||
}
|
||||
|
||||
public static ai.djl.modality.cv.output.Point getCenterPoint(List<Point> points) {
|
||||
double sumX = 0;
|
||||
double sumY = 0;
|
||||
|
||||
for (Point point : points) {
|
||||
sumX = sumX + point.getX();
|
||||
sumY = sumY + point.getY();
|
||||
}
|
||||
|
||||
ai.djl.modality.cv.output.Point centerPoint = new ai.djl.modality.cv.output.Point(sumX / 4, sumY / 4);
|
||||
return centerPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* 点坐标变换
|
||||
*
|
||||
* @param manager
|
||||
* @param mat
|
||||
* @param point
|
||||
* @return
|
||||
*/
|
||||
public static Point transformPoint(NDManager manager, org.opencv.core.Mat mat, Point point) {
|
||||
double[][] pointsArray = new double[3][3];
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
pointsArray[i][j] = mat.get(i, j)[0];
|
||||
}
|
||||
}
|
||||
NDArray ndPoints = manager.create(pointsArray);
|
||||
|
||||
double[] vector = new double[3];
|
||||
vector[0] = point.getX();
|
||||
vector[1] = point.getY();
|
||||
vector[2] = 1f;
|
||||
NDArray vPoints = manager.create(vector);
|
||||
vPoints = vPoints.reshape(3, 1);
|
||||
NDArray result = ndPoints.matMul(vPoints);
|
||||
double[] dArray = result.toDoubleArray();
|
||||
if (dArray[2] != 0) {
|
||||
point.setX((int) (dArray[0] / dArray[2]));
|
||||
point.setY((int) (dArray[1] / dArray[2]));
|
||||
}
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
/**
|
||||
* 坐标变换
|
||||
*
|
||||
* @param manager
|
||||
* @param mat
|
||||
* @param points
|
||||
* @return
|
||||
*/
|
||||
public static List<Point> transformPoints(NDManager manager, org.opencv.core.Mat mat, List<Point> points) {
|
||||
int cols = mat.cols();
|
||||
int rows = mat.rows();
|
||||
double[][] pointsArray = new double[rows][cols];
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < cols; j++) {
|
||||
pointsArray[i][j] = mat.get(i, j)[0];
|
||||
}
|
||||
}
|
||||
NDArray ndPoints = manager.create(pointsArray);
|
||||
|
||||
double[] vector = new double[3];
|
||||
for (int i = 0; i < points.size(); i++) {
|
||||
vector[0] = points.get(i).getX();
|
||||
vector[1] = points.get(i).getY();
|
||||
vector[2] = 1f;
|
||||
NDArray vPoints = manager.create(vector);
|
||||
vPoints = vPoints.reshape(3, 1);
|
||||
NDArray result = ndPoints.matMul(vPoints);
|
||||
double[] dArray = result.toDoubleArray();
|
||||
if (dArray.length > 2) {
|
||||
if (dArray[2] != 0) {
|
||||
points.get(i).setX((int) (dArray[0] / dArray[2]));
|
||||
points.get(i).setY((int) (dArray[1] / dArray[2]));
|
||||
}
|
||||
} else {
|
||||
points.get(i).setX((int) (dArray[0]));
|
||||
points.get(i).setY((int) (dArray[1]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取左上角和有下角的坐标
|
||||
* Get (x1,y1,x2,y2) coordinations
|
||||
*
|
||||
* @param points
|
||||
* @return
|
||||
*/
|
||||
public static int[] rectXYXY(List<Point> points) {
|
||||
int left = points.get(0).getX();
|
||||
int top = points.get(0).getY();
|
||||
int right = points.get(2).getX();
|
||||
int bottom = points.get(2).getY();
|
||||
return new int[]{left, top, right, bottom};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取左上角的坐标,宽度,高度
|
||||
* Get (x1,y1,w,h) coordinations
|
||||
*
|
||||
* @param points
|
||||
* @return
|
||||
*/
|
||||
public static int[] rectXYWH(List<Point> points) {
|
||||
int minX = Integer.MAX_VALUE;
|
||||
int minY = Integer.MAX_VALUE;
|
||||
int maxX = Integer.MIN_VALUE;
|
||||
int maxY = Integer.MIN_VALUE;
|
||||
|
||||
for (Point point : points) {
|
||||
int x = point.getX();
|
||||
int y = point.getY();
|
||||
if (x < minX)
|
||||
minX = x;
|
||||
if (x > maxX)
|
||||
maxX = x;
|
||||
if (y < minY)
|
||||
minY = y;
|
||||
if (y > maxY)
|
||||
maxY = y;
|
||||
}
|
||||
|
||||
int w = maxX - minX;
|
||||
int h = maxY - minY;
|
||||
return new int[]{minX, minY, w, h};
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package top.aias.seg.utils;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 生成文件名
|
||||
* Generate file name
|
||||
*
|
||||
* @author Calvin
|
||||
* @mail 179209347@qq.com
|
||||
* @website www.aias.top
|
||||
*/
|
||||
public class UUIDUtils {
|
||||
|
||||
public static String getUUID() {
|
||||
return UUID.randomUUID().toString().replace("-", "");
|
||||
}
|
||||
|
||||
}
|
11
6_web_app/image_seg_sam2/sam2_backend/src/main/main.iml
Normal file
11
6_web_app/image_seg_sam2/sam2_backend/src/main/main.iml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/java" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
@ -0,0 +1,17 @@
|
||||
# Server Port
|
||||
server:
|
||||
port: 8089
|
||||
tomcat:
|
||||
uri-encoding: UTF-8
|
||||
baseUri: http://127.0.0.1:${server.port}
|
||||
|
||||
model:
|
||||
# 设置为 CPU 核心数 (Core Number)
|
||||
poolSize: 4
|
||||
sam2:
|
||||
# encoder model URI
|
||||
# sam2-hiera-large-encoder.onnx
|
||||
encoder: /Users/calvin/AIAS/6_web_app/image_seg_sam2/sam2_backend/models/sam2-hiera-tiny-encoder.onnx
|
||||
# decoder model URI
|
||||
# sam2-hiera-large-decoder.onnx
|
||||
decoder: /Users/calvin/AIAS/6_web_app/image_seg_sam2/sam2_backend/models/sam2-hiera-tiny-decoder.onnx
|
@ -0,0 +1,17 @@
|
||||
# Server Port
|
||||
server:
|
||||
port: 8089
|
||||
tomcat:
|
||||
uri-encoding: UTF-8
|
||||
baseUri: http://127.0.0.1:${server.port}
|
||||
|
||||
model:
|
||||
# 设置为 CPU 核心数 (Core Number)
|
||||
poolSize: 4
|
||||
sam2:
|
||||
# encoder model URI
|
||||
# sam2-hiera-large-encoder.onnx
|
||||
encoder: /Users/calvin/AIAS/6_web_app/image_seg_sam2/sam2_backend/models/sam2-hiera-tiny-encoder.onnx
|
||||
# decoder model URI
|
||||
# sam2-hiera-large-decoder.onnx
|
||||
decoder: /Users/calvin/AIAS/6_web_app/image_seg_sam2/sam2_backend/models/sam2-hiera-tiny-decoder.onnx
|
@ -0,0 +1,19 @@
|
||||
# Server Port
|
||||
server:
|
||||
port: 8089
|
||||
tomcat:
|
||||
uri-encoding: UTF-8
|
||||
baseUri: http://127.0.0.1:${server.port}
|
||||
|
||||
model:
|
||||
# 设置为 CPU 核心数 (Core Number)
|
||||
poolSize: 4
|
||||
sam2:
|
||||
# encoder model URI
|
||||
# sam2-hiera-large-encoder.onnx
|
||||
encoder: https://aias-home.oss-cn-beijing.aliyuncs.com/models/sam2/sam2-hiera-tiny-encoder.onnx
|
||||
# decoder model URI
|
||||
# sam2-hiera-large-decoder.onnx
|
||||
decoder: https://aias-home.oss-cn-beijing.aliyuncs.com/models/sam2/sam2-hiera-tiny-decoder.onnx
|
||||
|
||||
|
@ -0,0 +1,20 @@
|
||||
# Server Port
|
||||
server:
|
||||
port: 8089
|
||||
tomcat:
|
||||
uri-encoding: UTF-8
|
||||
baseUri: http://127.0.0.1:${server.port}
|
||||
|
||||
model:
|
||||
# 设置为 CPU 核心数 (Core Number)
|
||||
poolSize: 4
|
||||
sam2:
|
||||
# encoder model URI
|
||||
# sam2-hiera-large-encoder.onnx
|
||||
encoder: D:\\ai_projects\\AIAS\\1_image_sdks\\seg_sam2_sdk\\models\\sam2-hiera-tiny-encoder.onnx
|
||||
# decoder model URI
|
||||
# sam2-hiera-large-decoder.onnx
|
||||
decoder: D:\\ai_projects\\AIAS\\1_image_sdks\\seg_sam2_sdk\\models\\sam2-hiera-tiny-decoder.onnx
|
||||
|
||||
|
||||
|
@ -0,0 +1,46 @@
|
||||
|
||||
spring:
|
||||
profiles:
|
||||
active: win
|
||||
servlet:
|
||||
multipart:
|
||||
enabled: true
|
||||
max-file-size: 30MB
|
||||
max-request-size: 30MB
|
||||
http:
|
||||
encoding:
|
||||
charset: utf-8
|
||||
enabled: true
|
||||
force: true
|
||||
messages:
|
||||
encoding: UTF-8
|
||||
|
||||
# Swagger-ui
|
||||
swagger:
|
||||
enabled: true
|
||||
|
||||
# File path
|
||||
file:
|
||||
mac:
|
||||
path: file/
|
||||
linux:
|
||||
path: file/
|
||||
windows:
|
||||
path: C:\\iocr\\file\\
|
||||
# File max size - MB
|
||||
maxSize: 100
|
||||
|
||||
|
||||
# Verify image transformation result
|
||||
image:
|
||||
debug: true
|
||||
# 设置图片摆正对齐透视变换次数的上限
|
||||
maxNum: 4
|
||||
# 4个锚点框对应的4边形的4个顶点,与待识别图片检测框对应的4个顶点距离
|
||||
disThreshold: 3
|
||||
|
||||
# distance calculation type: L2, IoU
|
||||
distance:
|
||||
type: IoU
|
||||
|
||||
|
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="INFO">
|
||||
<Appenders>
|
||||
<Console name="console" target="SYSTEM_OUT">
|
||||
<PatternLayout
|
||||
pattern="[%-5level] - %msg%n"/>
|
||||
</Console>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Root level="info" additivity="false">
|
||||
<AppenderRef ref="console"/>
|
||||
</Root>
|
||||
<Logger name="me.calvin" level="${sys:me.calvin.logging.level:-info}" additivity="false">
|
||||
<AppenderRef ref="console"/>
|
||||
</Logger>
|
||||
</Loggers>
|
||||
</Configuration>
|
12
6_web_app/image_seg_sam2/sam2_backend/src/test/test.iml
Normal file
12
6_web_app/image_seg_sam2/sam2_backend/src/test/test.iml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/java" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="main" />
|
||||
</component>
|
||||
</module>
|
14
6_web_app/image_seg_sam2/sam2_ui/.editorconfig
Normal file
14
6_web_app/image_seg_sam2/sam2_ui/.editorconfig
Normal file
@ -0,0 +1,14 @@
|
||||
# http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
insert_final_newline = false
|
||||
trim_trailing_whitespace = false
|
6
6_web_app/image_seg_sam2/sam2_ui/.env.development
Normal file
6
6_web_app/image_seg_sam2/sam2_ui/.env.development
Normal file
@ -0,0 +1,6 @@
|
||||
# just a flag
|
||||
ENV = 'development'
|
||||
|
||||
# base api 127.0.0.1
|
||||
VUE_APP_BASE_API = 'http://127.0.0.1:8089'
|
||||
|
6
6_web_app/image_seg_sam2/sam2_ui/.env.production
Normal file
6
6_web_app/image_seg_sam2/sam2_ui/.env.production
Normal file
@ -0,0 +1,6 @@
|
||||
# just a flag
|
||||
ENV = 'production'
|
||||
|
||||
# base api 127.0.0.1
|
||||
VUE_APP_BASE_API = 'http://127.0.0.1:8089'
|
||||
|
8
6_web_app/image_seg_sam2/sam2_ui/.env.staging
Normal file
8
6_web_app/image_seg_sam2/sam2_ui/.env.staging
Normal file
@ -0,0 +1,8 @@
|
||||
NODE_ENV = production
|
||||
|
||||
# just a flag
|
||||
ENV = 'staging'
|
||||
|
||||
# base api
|
||||
VUE_APP_BASE_API = '/stage-api'
|
||||
|
4
6_web_app/image_seg_sam2/sam2_ui/.eslintignore
Normal file
4
6_web_app/image_seg_sam2/sam2_ui/.eslintignore
Normal file
@ -0,0 +1,4 @@
|
||||
build/*.js
|
||||
src/assets
|
||||
public
|
||||
dist
|
198
6_web_app/image_seg_sam2/sam2_ui/.eslintrc.js
Normal file
198
6_web_app/image_seg_sam2/sam2_ui/.eslintrc.js
Normal file
@ -0,0 +1,198 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint',
|
||||
sourceType: 'module'
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
es6: true,
|
||||
},
|
||||
extends: ['plugin:vue/recommended', 'eslint:recommended'],
|
||||
|
||||
// add your custom rules here
|
||||
//it is base on https://github.com/vuejs/eslint-config-vue
|
||||
rules: {
|
||||
"vue/max-attributes-per-line": [2, {
|
||||
"singleline": 10,
|
||||
"multiline": {
|
||||
"max": 1,
|
||||
"allowFirstLine": false
|
||||
}
|
||||
}],
|
||||
"vue/singleline-html-element-content-newline": "off",
|
||||
"vue/multiline-html-element-content-newline":"off",
|
||||
"vue/name-property-casing": ["error", "PascalCase"],
|
||||
"vue/no-v-html": "off",
|
||||
'accessor-pairs': 2,
|
||||
'arrow-spacing': [2, {
|
||||
'before': true,
|
||||
'after': true
|
||||
}],
|
||||
'block-spacing': [2, 'always'],
|
||||
'brace-style': [2, '1tbs', {
|
||||
'allowSingleLine': true
|
||||
}],
|
||||
'camelcase': [0, {
|
||||
'properties': 'always'
|
||||
}],
|
||||
'comma-dangle': [2, 'never'],
|
||||
'comma-spacing': [2, {
|
||||
'before': false,
|
||||
'after': true
|
||||
}],
|
||||
'comma-style': [2, 'last'],
|
||||
'constructor-super': 2,
|
||||
'curly': [2, 'multi-line'],
|
||||
'dot-location': [2, 'property'],
|
||||
'eol-last': 2,
|
||||
'eqeqeq': ["error", "always", {"null": "ignore"}],
|
||||
'generator-star-spacing': [2, {
|
||||
'before': true,
|
||||
'after': true
|
||||
}],
|
||||
'handle-callback-err': [2, '^(err|error)$'],
|
||||
'indent': [2, 2, {
|
||||
'SwitchCase': 1
|
||||
}],
|
||||
'jsx-quotes': [2, 'prefer-single'],
|
||||
'key-spacing': [2, {
|
||||
'beforeColon': false,
|
||||
'afterColon': true
|
||||
}],
|
||||
'keyword-spacing': [2, {
|
||||
'before': true,
|
||||
'after': true
|
||||
}],
|
||||
'new-cap': [2, {
|
||||
'newIsCap': true,
|
||||
'capIsNew': false
|
||||
}],
|
||||
'new-parens': 2,
|
||||
'no-array-constructor': 2,
|
||||
'no-caller': 2,
|
||||
'no-console': 'off',
|
||||
'no-class-assign': 2,
|
||||
'no-cond-assign': 2,
|
||||
'no-const-assign': 2,
|
||||
'no-control-regex': 0,
|
||||
'no-delete-var': 2,
|
||||
'no-dupe-args': 2,
|
||||
'no-dupe-class-members': 2,
|
||||
'no-dupe-keys': 2,
|
||||
'no-duplicate-case': 2,
|
||||
'no-empty-character-class': 2,
|
||||
'no-empty-pattern': 2,
|
||||
'no-eval': 2,
|
||||
'no-ex-assign': 2,
|
||||
'no-extend-native': 2,
|
||||
'no-extra-bind': 2,
|
||||
'no-extra-boolean-cast': 2,
|
||||
'no-extra-parens': [2, 'functions'],
|
||||
'no-fallthrough': 2,
|
||||
'no-floating-decimal': 2,
|
||||
'no-func-assign': 2,
|
||||
'no-implied-eval': 2,
|
||||
'no-inner-declarations': [2, 'functions'],
|
||||
'no-invalid-regexp': 2,
|
||||
'no-irregular-whitespace': 2,
|
||||
'no-iterator': 2,
|
||||
'no-label-var': 2,
|
||||
'no-labels': [2, {
|
||||
'allowLoop': false,
|
||||
'allowSwitch': false
|
||||
}],
|
||||
'no-lone-blocks': 2,
|
||||
'no-mixed-spaces-and-tabs': 2,
|
||||
'no-multi-spaces': 2,
|
||||
'no-multi-str': 2,
|
||||
'no-multiple-empty-lines': [2, {
|
||||
'max': 1
|
||||
}],
|
||||
'no-native-reassign': 2,
|
||||
'no-negated-in-lhs': 2,
|
||||
'no-new-object': 2,
|
||||
'no-new-require': 2,
|
||||
'no-new-symbol': 2,
|
||||
'no-new-wrappers': 2,
|
||||
'no-obj-calls': 2,
|
||||
'no-octal': 2,
|
||||
'no-octal-escape': 2,
|
||||
'no-path-concat': 2,
|
||||
'no-proto': 2,
|
||||
'no-redeclare': 2,
|
||||
'no-regex-spaces': 2,
|
||||
'no-return-assign': [2, 'except-parens'],
|
||||
'no-self-assign': 2,
|
||||
'no-self-compare': 2,
|
||||
'no-sequences': 2,
|
||||
'no-shadow-restricted-names': 2,
|
||||
'no-spaced-func': 2,
|
||||
'no-sparse-arrays': 2,
|
||||
'no-this-before-super': 2,
|
||||
'no-throw-literal': 2,
|
||||
'no-trailing-spaces': 2,
|
||||
'no-undef': 2,
|
||||
'no-undef-init': 2,
|
||||
'no-unexpected-multiline': 2,
|
||||
'no-unmodified-loop-condition': 2,
|
||||
'no-unneeded-ternary': [2, {
|
||||
'defaultAssignment': false
|
||||
}],
|
||||
'no-unreachable': 2,
|
||||
'no-unsafe-finally': 2,
|
||||
'no-unused-vars': [2, {
|
||||
'vars': 'all',
|
||||
'args': 'none'
|
||||
}],
|
||||
'no-useless-call': 2,
|
||||
'no-useless-computed-key': 2,
|
||||
'no-useless-constructor': 2,
|
||||
'no-useless-escape': 0,
|
||||
'no-whitespace-before-property': 2,
|
||||
'no-with': 2,
|
||||
'one-var': [2, {
|
||||
'initialized': 'never'
|
||||
}],
|
||||
'operator-linebreak': [2, 'after', {
|
||||
'overrides': {
|
||||
'?': 'before',
|
||||
':': 'before'
|
||||
}
|
||||
}],
|
||||
'padded-blocks': [2, 'never'],
|
||||
'quotes': [2, 'single', {
|
||||
'avoidEscape': true,
|
||||
'allowTemplateLiterals': true
|
||||
}],
|
||||
'semi': [2, 'never'],
|
||||
'semi-spacing': [2, {
|
||||
'before': false,
|
||||
'after': true
|
||||
}],
|
||||
'space-before-blocks': [2, 'always'],
|
||||
'space-before-function-paren': [2, 'never'],
|
||||
'space-in-parens': [2, 'never'],
|
||||
'space-infix-ops': 2,
|
||||
'space-unary-ops': [2, {
|
||||
'words': true,
|
||||
'nonwords': false
|
||||
}],
|
||||
'spaced-comment': [2, 'always', {
|
||||
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
|
||||
}],
|
||||
'template-curly-spacing': [2, 'never'],
|
||||
'use-isnan': 2,
|
||||
'valid-typeof': 2,
|
||||
'wrap-iife': [2, 'any'],
|
||||
'yield-star-spacing': [2, 'both'],
|
||||
'yoda': [2, 'never'],
|
||||
'prefer-const': 2,
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
|
||||
'object-curly-spacing': [2, 'always', {
|
||||
objectsInObjects: false
|
||||
}],
|
||||
'array-bracket-spacing': [2, 'never']
|
||||
}
|
||||
}
|
5
6_web_app/image_seg_sam2/sam2_ui/.travis.yml
Normal file
5
6_web_app/image_seg_sam2/sam2_ui/.travis.yml
Normal file
@ -0,0 +1,5 @@
|
||||
language: node_js
|
||||
node_js: 10
|
||||
script: npm run test
|
||||
notifications:
|
||||
email: false
|
14
6_web_app/image_seg_sam2/sam2_ui/babel.config.js
Normal file
14
6_web_app/image_seg_sam2/sam2_ui/babel.config.js
Normal file
@ -0,0 +1,14 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
// https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app
|
||||
'@vue/cli-plugin-babel/preset'
|
||||
],
|
||||
'env': {
|
||||
'development': {
|
||||
// babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
|
||||
// This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
|
||||
// https://panjiachen.github.io/vue-element-admin-site/guide/advanced/lazy-loading.html
|
||||
'plugins': ['dynamic-import-node']
|
||||
}
|
||||
}
|
||||
}
|
35
6_web_app/image_seg_sam2/sam2_ui/build/index.js
Normal file
35
6_web_app/image_seg_sam2/sam2_ui/build/index.js
Normal file
@ -0,0 +1,35 @@
|
||||
const { run } = require('runjs')
|
||||
const chalk = require('chalk')
|
||||
const config = require('../vue.config.js')
|
||||
const rawArgv = process.argv.slice(2)
|
||||
const args = rawArgv.join(' ')
|
||||
|
||||
if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
|
||||
const report = rawArgv.includes('--report')
|
||||
|
||||
run(`vue-cli-service build ${args}`)
|
||||
|
||||
const port = 9526
|
||||
const publicPath = config.publicPath
|
||||
|
||||
var connect = require('connect')
|
||||
var serveStatic = require('serve-static')
|
||||
const app = connect()
|
||||
|
||||
app.use(
|
||||
publicPath,
|
||||
serveStatic('./dist', {
|
||||
index: ['index.html', '/']
|
||||
})
|
||||
)
|
||||
|
||||
app.listen(port, function () {
|
||||
console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`))
|
||||
if (report) {
|
||||
console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`))
|
||||
}
|
||||
|
||||
})
|
||||
} else {
|
||||
run(`vue-cli-service build ${args}`)
|
||||
}
|
24
6_web_app/image_seg_sam2/sam2_ui/jest.config.js
Normal file
24
6_web_app/image_seg_sam2/sam2_ui/jest.config.js
Normal file
@ -0,0 +1,24 @@
|
||||
module.exports = {
|
||||
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
|
||||
transform: {
|
||||
'^.+\\.vue$': 'vue-jest',
|
||||
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
|
||||
'jest-transform-stub',
|
||||
'^.+\\.jsx?$': 'babel-jest'
|
||||
},
|
||||
moduleNameMapper: {
|
||||
'^@/(.*)$': '<rootDir>/src/$1'
|
||||
},
|
||||
snapshotSerializers: ['jest-serializer-vue'],
|
||||
testMatch: [
|
||||
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
|
||||
],
|
||||
collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'],
|
||||
coverageDirectory: '<rootDir>/tests/unit/coverage',
|
||||
// 'collectCoverage': true,
|
||||
'coverageReporters': [
|
||||
'lcov',
|
||||
'text-summary'
|
||||
],
|
||||
testURL: 'http://localhost/'
|
||||
}
|
9
6_web_app/image_seg_sam2/sam2_ui/jsconfig.json
Normal file
9
6_web_app/image_seg_sam2/sam2_ui/jsconfig.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
85
6_web_app/image_seg_sam2/sam2_ui/nginx.conf
Normal file
85
6_web_app/image_seg_sam2/sam2_ui/nginx.conf
Normal file
@ -0,0 +1,85 @@
|
||||
user www-data;
|
||||
worker_processes auto;
|
||||
pid /run/nginx.pid;
|
||||
include /etc/nginx/modules-enabled/*.conf;
|
||||
|
||||
events {
|
||||
worker_connections 768;
|
||||
# multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
|
||||
##
|
||||
# Basic Settings
|
||||
##
|
||||
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
# server_tokens off;
|
||||
|
||||
# server_names_hash_bucket_size 64;
|
||||
# server_name_in_redirect off;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
##
|
||||
# SSL Settings
|
||||
##
|
||||
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
##
|
||||
# Logging Settings
|
||||
##
|
||||
|
||||
access_log /var/log/nginx/access.log;
|
||||
error_log /var/log/nginx/error.log;
|
||||
|
||||
##
|
||||
# Gzip Settings
|
||||
##
|
||||
|
||||
gzip on;
|
||||
|
||||
# gzip_vary on;
|
||||
# gzip_proxied any;
|
||||
# gzip_comp_level 6;
|
||||
# gzip_buffers 16 8k;
|
||||
# gzip_http_version 1.1;
|
||||
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
|
||||
##
|
||||
# Virtual Host Configs
|
||||
##
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
include /etc/nginx/sites-enabled/*;
|
||||
}
|
||||
|
||||
|
||||
#mail {
|
||||
# # See sample authentication script at:
|
||||
# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
|
||||
#
|
||||
# # auth_http localhost/auth.php;
|
||||
# # pop3_capabilities "TOP" "USER";
|
||||
# # imap_capabilities "IMAP4rev1" "UIDPLUS";
|
||||
#
|
||||
# server {
|
||||
# listen localhost:110;
|
||||
# protocol pop3;
|
||||
# proxy on;
|
||||
# }
|
||||
#
|
||||
# server {
|
||||
# listen localhost:143;
|
||||
# protocol imap;
|
||||
# proxy on;
|
||||
# }
|
||||
#}
|
37822
6_web_app/image_seg_sam2/sam2_ui/package-lock.json
generated
Normal file
37822
6_web_app/image_seg_sam2/sam2_ui/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
65
6_web_app/image_seg_sam2/sam2_ui/package.json
Normal file
65
6_web_app/image_seg_sam2/sam2_ui/package.json
Normal file
@ -0,0 +1,65 @@
|
||||
{
|
||||
"name": "sam2-ui",
|
||||
"version": "1.0.0",
|
||||
"description": "Sam2 UI",
|
||||
"author": "Calvin <179209347@qq.com>",
|
||||
"scripts": {
|
||||
"dev": "vue-cli-service serve",
|
||||
"build:prod": "vue-cli-service build",
|
||||
"build:stage": "vue-cli-service build --mode staging",
|
||||
"preview": "node build/index.js --preview",
|
||||
"lint": "eslint --ext .js,.vue src",
|
||||
"test:unit": "jest --clearCache && vue-cli-service test:unit",
|
||||
"test:ci": "npm run lint && npm run test:unit"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "0.18.1",
|
||||
"core-js": "3.6.5",
|
||||
"easy-circular-progress": "1.0.4",
|
||||
"echarts": "^4.2.1",
|
||||
"element-ui": "2.13.2",
|
||||
"js-base64": "^2.6.4",
|
||||
"js-cookie": "2.2.0",
|
||||
"normalize.css": "7.0.0",
|
||||
"nprogress": "0.2.0",
|
||||
"path-to-regexp": "2.4.0",
|
||||
"vertx3-eventbus-client": "^3.9.4",
|
||||
"vue": "2.6.10",
|
||||
"vue-count-to": "^1.0.13",
|
||||
"vue-json-viewer": "^2.2.18",
|
||||
"vue-router": "3.0.6",
|
||||
"vuex": "3.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "4.4.4",
|
||||
"@vue/cli-plugin-eslint": "4.4.4",
|
||||
"@vue/cli-plugin-unit-jest": "4.4.4",
|
||||
"@vue/cli-service": "4.4.4",
|
||||
"@vue/test-utils": "1.0.0-beta.29",
|
||||
"autoprefixer": "9.5.1",
|
||||
"babel-eslint": "10.1.0",
|
||||
"babel-jest": "23.6.0",
|
||||
"babel-plugin-dynamic-import-node": "2.3.3",
|
||||
"chalk": "2.4.2",
|
||||
"connect": "3.6.6",
|
||||
"eslint": "6.7.2",
|
||||
"eslint-plugin-vue": "6.2.2",
|
||||
"html-webpack-plugin": "3.2.0",
|
||||
"mockjs": "1.0.1-beta3",
|
||||
"runjs": "4.3.2",
|
||||
"sass": "1.26.8",
|
||||
"sass-loader": "8.0.2",
|
||||
"script-ext-html-webpack-plugin": "2.1.3",
|
||||
"serve-static": "1.13.2",
|
||||
"vue-template-compiler": "2.6.10"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=8.9",
|
||||
"npm": ">= 3.0.0"
|
||||
},
|
||||
"license": ""
|
||||
}
|
8
6_web_app/image_seg_sam2/sam2_ui/postcss.config.js
Normal file
8
6_web_app/image_seg_sam2/sam2_ui/postcss.config.js
Normal file
@ -0,0 +1,8 @@
|
||||
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||
|
||||
module.exports = {
|
||||
'plugins': {
|
||||
// to edit target browsers: use "browserslist" field in package.json
|
||||
'autoprefixer': {}
|
||||
}
|
||||
}
|
BIN
6_web_app/image_seg_sam2/sam2_ui/public/favicon.ico
Normal file
BIN
6_web_app/image_seg_sam2/sam2_ui/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
17
6_web_app/image_seg_sam2/sam2_ui/public/index.html
Normal file
17
6_web_app/image_seg_sam2/sam2_ui/public/index.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title><%= webpackConfig.name %></title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
11
6_web_app/image_seg_sam2/sam2_ui/src/App.vue
Normal file
11
6_web_app/image_seg_sam2/sam2_ui/src/App.vue
Normal file
@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'App'
|
||||
}
|
||||
</script>
|
22
6_web_app/image_seg_sam2/sam2_ui/src/api/inference.js
Normal file
22
6_web_app/image_seg_sam2/sam2_ui/src/api/inference.js
Normal file
@ -0,0 +1,22 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getLabelData(data) {
|
||||
return request({
|
||||
url: '/infer/getLabelData',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function uploadImage(name, imageFile) {
|
||||
return request({
|
||||
url: '/infer/uploadImage',
|
||||
method: 'post',
|
||||
params: {
|
||||
name: name,
|
||||
imageFile: imageFile
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default { uploadImage, getLabelData }
|
BIN
6_web_app/image_seg_sam2/sam2_ui/src/assets/404_images/404.png
Normal file
BIN
6_web_app/image_seg_sam2/sam2_ui/src/assets/404_images/404.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 96 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.7 KiB |
55
6_web_app/image_seg_sam2/sam2_ui/src/assets/styles/base.scss
Normal file
55
6_web_app/image_seg_sam2/sam2_ui/src/assets/styles/base.scss
Normal file
@ -0,0 +1,55 @@
|
||||
// flex row
|
||||
@mixin flex-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
@mixin flex-row-between {
|
||||
@include flex-row();
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
@mixin flex-row-between-center {
|
||||
@include flex-row-between();
|
||||
align-items: center
|
||||
}
|
||||
|
||||
@mixin flex-row-center {
|
||||
@include flex-row();
|
||||
justify-content: center
|
||||
}
|
||||
|
||||
@mixin flex-row-all-center {
|
||||
@include flex-row-center;
|
||||
align-items: center
|
||||
|
||||
}
|
||||
|
||||
@mixin all-height($height) {
|
||||
height: $height;
|
||||
line-height: $height
|
||||
}
|
||||
|
||||
@mixin ellipsis($width) {
|
||||
width: $width;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis
|
||||
}
|
||||
|
||||
// flex column
|
||||
@mixin flex-column {
|
||||
display: flex;
|
||||
flex-direction: column
|
||||
}
|
||||
|
||||
@mixin flex-column-center {
|
||||
@include flex-column();
|
||||
justify-content: center
|
||||
}
|
||||
|
||||
@mixin flex-column-all-center {
|
||||
@include flex-column-center;
|
||||
align-items: center
|
||||
}
|
||||
|
99
6_web_app/image_seg_sam2/sam2_ui/src/assets/styles/btn.scss
Normal file
99
6_web_app/image_seg_sam2/sam2_ui/src/assets/styles/btn.scss
Normal file
@ -0,0 +1,99 @@
|
||||
@import 'variables';
|
||||
|
||||
@mixin colorBtn($color) {
|
||||
background: $color;
|
||||
|
||||
&:hover {
|
||||
color: $color;
|
||||
|
||||
&:before,
|
||||
&:after {
|
||||
background: $color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.blue-btn {
|
||||
@include colorBtn($blue)
|
||||
}
|
||||
|
||||
.light-blue-btn {
|
||||
@include colorBtn($light-blue)
|
||||
}
|
||||
|
||||
.red-btn {
|
||||
@include colorBtn($red)
|
||||
}
|
||||
|
||||
.pink-btn {
|
||||
@include colorBtn($pink)
|
||||
}
|
||||
|
||||
.green-btn {
|
||||
@include colorBtn($green)
|
||||
}
|
||||
|
||||
.tiffany-btn {
|
||||
@include colorBtn($tiffany)
|
||||
}
|
||||
|
||||
.yellow-btn {
|
||||
@include colorBtn($yellow)
|
||||
}
|
||||
|
||||
.pan-btn {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
padding: 14px 36px;
|
||||
border-radius: 8px;
|
||||
border: none;
|
||||
outline: none;
|
||||
transition: 600ms ease all;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
|
||||
&:hover {
|
||||
background: #fff;
|
||||
|
||||
&:before,
|
||||
&:after {
|
||||
width: 100%;
|
||||
transition: 600ms ease all;
|
||||
}
|
||||
}
|
||||
|
||||
&:before,
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
width: 0;
|
||||
transition: 400ms ease all;
|
||||
}
|
||||
|
||||
&::after {
|
||||
right: inherit;
|
||||
top: inherit;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-button {
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
background: #fff;
|
||||
color: #fff;
|
||||
-webkit-appearance: none;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
outline: 0;
|
||||
margin: 0;
|
||||
padding: 10px 15px;
|
||||
font-size: 14px;
|
||||
border-radius: 4px;
|
||||
}
|
117
6_web_app/image_seg_sam2/sam2_ui/src/assets/styles/eladmin.scss
Normal file
117
6_web_app/image_seg_sam2/sam2_ui/src/assets/styles/eladmin.scss
Normal file
@ -0,0 +1,117 @@
|
||||
.head-container {
|
||||
padding-bottom: 10px;
|
||||
.filter-item {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin: 0 3px 10px 0;
|
||||
input {
|
||||
height: 30.5px;
|
||||
line-height: 30.5px;
|
||||
}
|
||||
}
|
||||
.el-form-item-label {
|
||||
margin: 0 3px 9px 0;
|
||||
display: inline-block;
|
||||
text-align: right;
|
||||
vertical-align: middle;
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
line-height: 30.5px;
|
||||
padding: 0 7px 0 7px;
|
||||
}
|
||||
.el-button+.el-button {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
.el-select__caret.el-input__icon.el-icon-arrow-up{
|
||||
line-height: 30.5px;
|
||||
}
|
||||
.date-item {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-bottom: 10px;
|
||||
height: 30.5px !important;
|
||||
width: 230px !important;
|
||||
}
|
||||
}
|
||||
.el-avatar {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
background: #ccc;
|
||||
color: #fff;
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
vertical-align: middle;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
.logo-con{
|
||||
height: 60px;
|
||||
padding: 13px 0 0;
|
||||
img{
|
||||
height: 32px;
|
||||
width: 135px;
|
||||
display: block;
|
||||
//margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
#el-login-footer {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-family: Arial, serif;
|
||||
font-size: 12px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
#el-main-footer {
|
||||
background: none repeat scroll 0 0 white;
|
||||
border-top: 1px solid #e7eaec;
|
||||
overflow: hidden;
|
||||
padding: 10px 6px 0 6px;
|
||||
height: 33px;
|
||||
font-size: 0.7rem !important;
|
||||
color: #7a8b9a;
|
||||
letter-spacing: 0.8px;
|
||||
font-family: Arial, sans-serif !important;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
z-index: 99;
|
||||
width: 100%;
|
||||
}
|
||||
.eladmin-upload {
|
||||
border: 1px dashed #c0ccda;
|
||||
border-radius: 5px;
|
||||
height: 45px;
|
||||
line-height: 45px;
|
||||
width: 368px;
|
||||
}
|
||||
.my-blockquote{
|
||||
margin: 0 0 10px;
|
||||
padding: 15px;
|
||||
line-height: 22px;
|
||||
border-left: 5px solid #00437B;
|
||||
border-radius: 0 2px 2px 0;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
.my-code{
|
||||
position: relative;
|
||||
padding: 15px;
|
||||
line-height: 20px;
|
||||
border-left: 5px solid #ddd;
|
||||
color: #333;
|
||||
font-family: Courier New, serif;
|
||||
font-size: 12px
|
||||
}
|
||||
|
||||
.el-tabs{
|
||||
margin-bottom: 25px;
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
// cover some element-ui styles
|
||||
|
||||
.el-breadcrumb__inner,
|
||||
.el-breadcrumb__inner a {
|
||||
font-weight: 400 !important;
|
||||
}
|
||||
|
||||
.el-upload {
|
||||
input[type="file"] {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-upload__input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cell {
|
||||
.el-tag {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.small-padding {
|
||||
.cell {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.fixed-width {
|
||||
.el-button--mini {
|
||||
padding: 7px 10px;
|
||||
width: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
.status-col {
|
||||
.cell {
|
||||
padding: 0 10px;
|
||||
text-align: center;
|
||||
|
||||
.el-tag {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// to fixed https://github.com/ElemeFE/element/issues/2461
|
||||
.el-dialog {
|
||||
transform: none;
|
||||
left: 0;
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
// refine element ui upload
|
||||
.upload-container {
|
||||
.el-upload {
|
||||
width: 100%;
|
||||
|
||||
.el-upload-dragger {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dropdown
|
||||
.el-dropdown-menu {
|
||||
a {
|
||||
display: block
|
||||
}
|
||||
}
|
||||
|
||||
// fix date-picker ui bug in filter-item
|
||||
.el-range-editor.el-input__inner {
|
||||
display: inline-flex !important;
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* I think element-ui's default theme color is too light for long-term use.
|
||||
* So I modified the default color and you can modify it to your liking.
|
||||
**/
|
||||
|
||||
/* theme color */
|
||||
$--color-primary: #1890ff;
|
||||
$--color-success: #13ce66;
|
||||
$--color-warning: #FFBA00;
|
||||
$--color-danger: #ff4949;
|
||||
// $--color-info: #1E1E1E;
|
||||
|
||||
$--button-font-weight: 400;
|
||||
|
||||
// $--color-text-regular: #1f2d3d;
|
||||
|
||||
$--border-color-light: #dfe4ed;
|
||||
$--border-color-lighter: #e6ebf5;
|
||||
|
||||
$--table-border:1px solid#dfe6ec;
|
||||
|
||||
/* icon font path, required */
|
||||
$--font-path: '~element-ui/lib/theme-chalk/fonts';
|
||||
|
||||
@import "../../../node_modules/element-ui/packages/theme-chalk/src/index";
|
||||
|
||||
// the :export directive is the magic sauce for webpack
|
||||
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
|
||||
:export {
|
||||
theme: $--color-primary;
|
||||
}
|
182
6_web_app/image_seg_sam2/sam2_ui/src/assets/styles/index.scss
Normal file
182
6_web_app/image_seg_sam2/sam2_ui/src/assets/styles/index.scss
Normal file
@ -0,0 +1,182 @@
|
||||
@import 'variables';
|
||||
@import 'mixin';
|
||||
@import 'transition';
|
||||
@import 'element-ui';
|
||||
@import 'sidebar';
|
||||
@import 'btn';
|
||||
@import 'eladmin';
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#app {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
.no-padding {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.padding-content {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
a:focus,
|
||||
a:active {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
a,
|
||||
a:focus,
|
||||
a:hover {
|
||||
cursor: pointer;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
div:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.fr {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.fl {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.pr-5 {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.pl-5 {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.block {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.inlineBlock {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.clearfix {
|
||||
&:after {
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
font-size: 0;
|
||||
content: " ";
|
||||
clear: both;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
aside {
|
||||
background: #eef1f6;
|
||||
padding: 8px 24px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 2px;
|
||||
display: block;
|
||||
line-height: 32px;
|
||||
font-size: 16px;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
color: #2c3e50;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
a {
|
||||
color: #337ab7;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: rgb(32, 160, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//main-container全局样式
|
||||
.app-container {
|
||||
padding: 20px 20px 45px 20px;
|
||||
}
|
||||
|
||||
.components-container {
|
||||
margin: 30px 50px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center
|
||||
}
|
||||
|
||||
.sub-navbar {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
padding-right: 20px;
|
||||
transition: 600ms ease position;
|
||||
background: linear-gradient(90deg, rgba(32, 182, 249, 1) 0%, rgba(32, 182, 249, 1) 0%, rgba(33, 120, 241, 1) 100%, rgba(33, 120, 241, 1) 100%);
|
||||
|
||||
.subtitle {
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.draft {
|
||||
background: #d0d0d0;
|
||||
}
|
||||
|
||||
&.deleted {
|
||||
background: #d0d0d0;
|
||||
}
|
||||
}
|
||||
|
||||
.link-type,
|
||||
.link-type:focus {
|
||||
color: #337ab7;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: rgb(32, 160, 255);
|
||||
}
|
||||
}
|
||||
|
||||
//refine vue-multiselect plugin
|
||||
.multiselect {
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.multiselect--active {
|
||||
z-index: 1000 !important;
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
@mixin clearfix {
|
||||
&:after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin scrollBar {
|
||||
&::-webkit-scrollbar-track-piece {
|
||||
background: #d3dce6;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #99a9bf;
|
||||
border-radius: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin relative {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@mixin pct($pct) {
|
||||
width: #{$pct};
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@mixin triangle($width, $height, $color, $direction) {
|
||||
$width: $width/2;
|
||||
$color-border-style: $height solid $color;
|
||||
$transparent-border-style: $width solid transparent;
|
||||
height: 0;
|
||||
width: 0;
|
||||
|
||||
@if $direction==up {
|
||||
border-bottom: $color-border-style;
|
||||
border-left: $transparent-border-style;
|
||||
border-right: $transparent-border-style;
|
||||
}
|
||||
|
||||
@else if $direction==right {
|
||||
border-left: $color-border-style;
|
||||
border-top: $transparent-border-style;
|
||||
border-bottom: $transparent-border-style;
|
||||
}
|
||||
|
||||
@else if $direction==down {
|
||||
border-top: $color-border-style;
|
||||
border-left: $transparent-border-style;
|
||||
border-right: $transparent-border-style;
|
||||
}
|
||||
|
||||
@else if $direction==left {
|
||||
border-right: $color-border-style;
|
||||
border-top: $transparent-border-style;
|
||||
border-bottom: $transparent-border-style;
|
||||
}
|
||||
}
|
209
6_web_app/image_seg_sam2/sam2_ui/src/assets/styles/sidebar.scss
Normal file
209
6_web_app/image_seg_sam2/sam2_ui/src/assets/styles/sidebar.scss
Normal file
@ -0,0 +1,209 @@
|
||||
#app {
|
||||
|
||||
.main-container {
|
||||
min-height: 100%;
|
||||
transition: margin-left .28s;
|
||||
margin-left: $sideBarWidth;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sidebar-container {
|
||||
transition: width 0.28s;
|
||||
width: $sideBarWidth !important;
|
||||
background-color: $menuBg;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
font-size: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1001;
|
||||
overflow: hidden;
|
||||
|
||||
// reset element-ui css
|
||||
.horizontal-collapse-transition {
|
||||
transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
|
||||
}
|
||||
|
||||
.scrollbar-wrapper {
|
||||
overflow-x: hidden !important;
|
||||
}
|
||||
|
||||
.el-scrollbar__bar.is-vertical {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.el-scrollbar {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&.has-logo {
|
||||
.el-scrollbar {
|
||||
height: calc(100% - 50px);
|
||||
}
|
||||
}
|
||||
|
||||
.is-horizontal {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.el-menu {
|
||||
border: none;
|
||||
height: 100%;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
// menu hover
|
||||
.submenu-title-noDropdown,
|
||||
.el-submenu__title {
|
||||
&:hover {
|
||||
background-color: $menuHover !important;
|
||||
}
|
||||
}
|
||||
|
||||
.is-active>.el-submenu__title {
|
||||
color: $subMenuActiveText !important;
|
||||
}
|
||||
|
||||
& .nest-menu .el-submenu>.el-submenu__title,
|
||||
& .el-submenu .el-menu-item {
|
||||
min-width: $sideBarWidth !important;
|
||||
background-color: $subMenuBg !important;
|
||||
|
||||
&:hover {
|
||||
background-color: $subMenuHover !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hideSidebar {
|
||||
.sidebar-container {
|
||||
width: 54px !important;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
margin-left: 54px;
|
||||
}
|
||||
|
||||
.submenu-title-noDropdown {
|
||||
padding: 0 !important;
|
||||
position: relative;
|
||||
|
||||
.el-tooltip {
|
||||
padding: 0 !important;
|
||||
|
||||
.svg-icon {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-submenu {
|
||||
overflow: hidden;
|
||||
|
||||
&>.el-submenu__title {
|
||||
padding: 0 !important;
|
||||
|
||||
.svg-icon {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.el-submenu__icon-arrow {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-menu--collapse {
|
||||
.el-submenu {
|
||||
&>.el-submenu__title {
|
||||
&>span {
|
||||
height: 0;
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-menu--collapse .el-menu .el-submenu {
|
||||
min-width: $sideBarWidth !important;
|
||||
}
|
||||
|
||||
// mobile responsive
|
||||
.mobile {
|
||||
.main-container {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.sidebar-container {
|
||||
transition: transform .28s;
|
||||
width: $sideBarWidth !important;
|
||||
}
|
||||
|
||||
&.hideSidebar {
|
||||
.sidebar-container {
|
||||
pointer-events: none;
|
||||
transition-duration: 0.3s;
|
||||
transform: translate3d(-$sideBarWidth, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.withoutAnimation {
|
||||
|
||||
.main-container,
|
||||
.sidebar-container {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// when menu collapsed
|
||||
.el-menu--vertical {
|
||||
&>.el-menu {
|
||||
.svg-icon {
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.nest-menu .el-submenu>.el-submenu__title,
|
||||
.el-menu-item {
|
||||
&:hover {
|
||||
// you can use $subMenuHover
|
||||
background-color: $menuHover !important;
|
||||
}
|
||||
}
|
||||
|
||||
// the scroll bar appears when the subMenu is too long
|
||||
>.el-menu--popup {
|
||||
max-height: 100vh;
|
||||
overflow-y: auto;
|
||||
|
||||
&::-webkit-scrollbar-track-piece {
|
||||
background: #d3dce6;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #99a9bf;
|
||||
border-radius: 20px;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
// global transition css
|
||||
|
||||
/* fade */
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.28s;
|
||||
}
|
||||
|
||||
.fade-enter,
|
||||
.fade-leave-active {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* fade-transform */
|
||||
.fade-transform-leave-active,
|
||||
.fade-transform-enter-active {
|
||||
transition: all .5s;
|
||||
}
|
||||
|
||||
.fade-transform-enter {
|
||||
opacity: 0;
|
||||
transform: translateX(-30px);
|
||||
}
|
||||
|
||||
.fade-transform-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(30px);
|
||||
}
|
||||
|
||||
/* breadcrumb transition */
|
||||
.breadcrumb-enter-active,
|
||||
.breadcrumb-leave-active {
|
||||
transition: all .5s;
|
||||
}
|
||||
|
||||
.breadcrumb-enter,
|
||||
.breadcrumb-leave-active {
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
}
|
||||
|
||||
.breadcrumb-move {
|
||||
transition: all .5s;
|
||||
}
|
||||
|
||||
.breadcrumb-leave-active {
|
||||
position: absolute;
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
// base color
|
||||
$blue:#324157;
|
||||
$light-blue:#3A71A8;
|
||||
$red:#C03639;
|
||||
$pink: #E65D6E;
|
||||
$green: #30B08F;
|
||||
$tiffany: #4AB7BD;
|
||||
$yellow:#FEC171;
|
||||
$panGreen: #30B08F;
|
||||
|
||||
// sidebar
|
||||
$menuText:#bfcbd9;
|
||||
$menuActiveText:#409EFF;
|
||||
$subMenuActiveText:#f4f4f5; // https://github.com/ElemeFE/element/issues/12951
|
||||
|
||||
$menuBg:#304156;
|
||||
$menuHover:#263445;
|
||||
|
||||
$subMenuBg:#1f2d3d;
|
||||
$subMenuHover:#001528;
|
||||
|
||||
$sideBarWidth: 205px;
|
||||
|
||||
// the :export directive is the magic sauce for webpack
|
||||
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
|
||||
:export {
|
||||
menuText: $menuText;
|
||||
menuActiveText: $menuActiveText;
|
||||
subMenuActiveText: $subMenuActiveText;
|
||||
menuBg: $menuBg;
|
||||
menuHover: $menuHover;
|
||||
subMenuBg: $subMenuBg;
|
||||
subMenuHover: $subMenuHover;
|
||||
sideBarWidth: $sideBarWidth;
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
tableInit: false,
|
||||
emptyTable: false,
|
||||
page: {
|
||||
pageNum: 1,
|
||||
pageSize: 8,
|
||||
total: 0,
|
||||
},
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
computed: {
|
||||
// emptyTable () {
|
||||
// return this.page.total === 0 && this.page.pageNum === 1 && this.emptyParam
|
||||
// },
|
||||
},
|
||||
watch: {
|
||||
'page.total' () {
|
||||
if (this.page.total > 0) {
|
||||
this.emptyTable = false
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
isObjectEmpty (data = {}) {
|
||||
return Object.values(data).filter(a => !!a).length === 0
|
||||
},
|
||||
setEmptyTable () {
|
||||
this.tableInit = true
|
||||
console.log(this.page.total, this.page.total == 0)
|
||||
this.emptyTable = this.page.total == 0
|
||||
},
|
||||
clearPage () {
|
||||
this.page.pageNum = 1
|
||||
},
|
||||
},
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<el-breadcrumb class="app-breadcrumb" separator="/">
|
||||
<transition-group name="breadcrumb">
|
||||
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
|
||||
<span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
|
||||
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
|
||||
</el-breadcrumb-item>
|
||||
</transition-group>
|
||||
</el-breadcrumb>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pathToRegexp from 'path-to-regexp'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
levelList: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
this.getBreadcrumb()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getBreadcrumb()
|
||||
},
|
||||
methods: {
|
||||
getBreadcrumb() {
|
||||
// only show routes with meta.title
|
||||
let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
|
||||
const first = matched[0]
|
||||
|
||||
if (!this.isDashboard(first)) {
|
||||
matched = [{ path: '/dashboard', meta: { title: 'Dashboard' }}].concat(matched)
|
||||
}
|
||||
|
||||
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
|
||||
},
|
||||
isDashboard(route) {
|
||||
const name = route && route.name
|
||||
if (!name) {
|
||||
return false
|
||||
}
|
||||
return name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase()
|
||||
},
|
||||
pathCompile(path) {
|
||||
// To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
|
||||
const { params } = this.$route
|
||||
var toPath = pathToRegexp.compile(path)
|
||||
return toPath(params)
|
||||
},
|
||||
handleLink(item) {
|
||||
const { redirect, path } = item
|
||||
if (redirect) {
|
||||
this.$router.push(redirect)
|
||||
return
|
||||
}
|
||||
this.$router.push(this.pathCompile(path))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.app-breadcrumb.el-breadcrumb {
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
line-height: 50px;
|
||||
margin-left: 8px;
|
||||
|
||||
.no-redirect {
|
||||
color: #97a8be;
|
||||
cursor: text;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<div style="padding: 0 15px;" @click="toggleClick">
|
||||
<svg
|
||||
:class="{'is-active':isActive}"
|
||||
class="hamburger"
|
||||
viewBox="0 0 1024 1024"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="64"
|
||||
height="64"
|
||||
>
|
||||
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Hamburger',
|
||||
props: {
|
||||
isActive: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleClick() {
|
||||
this.$emit('toggleClick')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hamburger {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.hamburger.is-active {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
</style>
|
@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
|
||||
<svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
|
||||
<use :xlink:href="iconName" />
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
|
||||
import { isExternal } from '@/utils/validate'
|
||||
|
||||
export default {
|
||||
name: 'SvgIcon',
|
||||
props: {
|
||||
iconClass: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
className: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isExternal() {
|
||||
return isExternal(this.iconClass)
|
||||
},
|
||||
iconName() {
|
||||
return `#icon-${this.iconClass}`
|
||||
},
|
||||
svgClass() {
|
||||
if (this.className) {
|
||||
return 'svg-icon ' + this.className
|
||||
} else {
|
||||
return 'svg-icon'
|
||||
}
|
||||
},
|
||||
styleExternalIcon() {
|
||||
return {
|
||||
mask: `url(${this.iconClass}) no-repeat 50% 50%`,
|
||||
'-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.svg-icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: -0.15em;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.svg-external-icon {
|
||||
background-color: currentColor;
|
||||
mask-size: cover!important;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<section class="app-main">
|
||||
<transition name="fade-transform" mode="out-in">
|
||||
<router-view :key="key" />
|
||||
</transition>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'AppMain',
|
||||
computed: {
|
||||
key() {
|
||||
return this.$route.path
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-main {
|
||||
/*50 = navbar */
|
||||
min-height: calc(100vh - 50px);
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.fixed-header+.app-main {
|
||||
padding-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
// fix css style bug in open el-dialog
|
||||
.el-popup-parent--hidden {
|
||||
.fixed-header {
|
||||
padding-right: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<div class="navbar">
|
||||
<hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
|
||||
|
||||
<breadcrumb class="breadcrumb-container" />
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import Breadcrumb from '@/components/Breadcrumb'
|
||||
import Hamburger from '@/components/Hamburger'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Breadcrumb,
|
||||
Hamburger
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'sidebar',
|
||||
'avatar'
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
toggleSideBar() {
|
||||
this.$store.dispatch('app/toggleSideBar')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.navbar {
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 4px rgba(0,21,41,.08);
|
||||
|
||||
.hamburger-container {
|
||||
line-height: 46px;
|
||||
height: 100%;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
transition: background .3s;
|
||||
-webkit-tap-highlight-color:transparent;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, .025)
|
||||
}
|
||||
}
|
||||
|
||||
.breadcrumb-container {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.right-menu {
|
||||
float: right;
|
||||
height: 100%;
|
||||
line-height: 50px;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.right-menu-item {
|
||||
display: inline-block;
|
||||
padding: 0 8px;
|
||||
height: 100%;
|
||||
font-size: 18px;
|
||||
color: #5a5e66;
|
||||
vertical-align: text-bottom;
|
||||
|
||||
&.hover-effect {
|
||||
cursor: pointer;
|
||||
transition: background .3s;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, .025)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
margin-right: 30px;
|
||||
|
||||
.avatar-wrapper {
|
||||
margin-top: 5px;
|
||||
position: relative;
|
||||
|
||||
.user-avatar {
|
||||
cursor: pointer;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.el-icon-caret-bottom {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: -20px;
|
||||
top: 25px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,26 @@
|
||||
export default {
|
||||
computed: {
|
||||
device() {
|
||||
return this.$store.state.app.device
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// In order to fix the click on menu on the ios device will trigger the mouseleave bug
|
||||
// https://github.com/PanJiaChen/vue-element-admin/issues/1135
|
||||
this.fixBugIniOS()
|
||||
},
|
||||
methods: {
|
||||
fixBugIniOS() {
|
||||
const $subMenu = this.$refs.subMenu
|
||||
if ($subMenu) {
|
||||
const handleMouseleave = $subMenu.handleMouseleave
|
||||
$subMenu.handleMouseleave = (e) => {
|
||||
if (this.device === 'mobile') {
|
||||
return
|
||||
}
|
||||
handleMouseleave(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'MenuItem',
|
||||
functional: true,
|
||||
props: {
|
||||
icon: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
render(h, context) {
|
||||
const { icon, title } = context.props
|
||||
const vnodes = []
|
||||
|
||||
if (icon) {
|
||||
if (icon.includes('el-icon')) {
|
||||
vnodes.push(<i class={[icon, 'sub-el-icon']} />)
|
||||
} else {
|
||||
vnodes.push(<svg-icon icon-class={icon}/>)
|
||||
}
|
||||
}
|
||||
|
||||
if (title) {
|
||||
vnodes.push(<span slot='title'>{(title)}</span>)
|
||||
}
|
||||
return vnodes
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.sub-el-icon {
|
||||
color: currentColor;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<component :is="type" v-bind="linkProps(to)">
|
||||
<slot />
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { isExternal } from '@/utils/validate'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
to: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isExternal() {
|
||||
return isExternal(this.to)
|
||||
},
|
||||
type() {
|
||||
if (this.isExternal) {
|
||||
return 'a'
|
||||
}
|
||||
return 'router-link'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
linkProps(to) {
|
||||
if (this.isExternal) {
|
||||
return {
|
||||
href: to,
|
||||
target: '_blank',
|
||||
rel: 'noopener'
|
||||
}
|
||||
}
|
||||
return {
|
||||
to: to
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div class="sidebar-logo-container" :class="{'collapse':collapse}">
|
||||
<transition name="sidebarLogoFade">
|
||||
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
|
||||
<img v-if="logo" :src="logo" class="sidebar-logo">
|
||||
<h1 v-else class="sidebar-title">{{ title }} </h1>
|
||||
</router-link>
|
||||
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
|
||||
<img v-if="logo" :src="logo" class="sidebar-logo">
|
||||
<h1 class="sidebar-title">{{ title }} </h1>
|
||||
</router-link>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SidebarLogo',
|
||||
props: {
|
||||
collapse: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
title: 'OCR'
|
||||
// logo: 'https://djl.ai/website/img/djl-middle.png'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.sidebarLogoFade-enter-active {
|
||||
transition: opacity 1.5s;
|
||||
}
|
||||
|
||||
.sidebarLogoFade-enter,
|
||||
.sidebarLogoFade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.sidebar-logo-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
background: #2b2f3a;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
|
||||
& .sidebar-logo-link {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
& .sidebar-logo {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
vertical-align: middle;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
& .sidebar-title {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
line-height: 50px;
|
||||
font-size: 14px;
|
||||
font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
&.collapse {
|
||||
.sidebar-logo {
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<div v-if="!item.hidden">
|
||||
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
|
||||
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
|
||||
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
|
||||
<item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" />
|
||||
</el-menu-item>
|
||||
</app-link>
|
||||
</template>
|
||||
|
||||
<el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
|
||||
<template slot="title">
|
||||
<item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
|
||||
</template>
|
||||
<sidebar-item
|
||||
v-for="child in item.children"
|
||||
:key="child.path"
|
||||
:is-nest="true"
|
||||
:item="child"
|
||||
:base-path="resolvePath(child.path)"
|
||||
class="nest-menu"
|
||||
/>
|
||||
</el-submenu>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import path from 'path'
|
||||
import { isExternal } from '@/utils/validate'
|
||||
import Item from './Item'
|
||||
import AppLink from './Link'
|
||||
import FixiOSBug from './FixiOSBug'
|
||||
|
||||
export default {
|
||||
name: 'SidebarItem',
|
||||
components: { Item, AppLink },
|
||||
mixins: [FixiOSBug],
|
||||
props: {
|
||||
// route object
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
isNest: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
basePath: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
// To fix https://github.com/PanJiaChen/vue-admin-template/issues/237
|
||||
// TODO: refactor with render function
|
||||
this.onlyOneChild = null
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
hasOneShowingChild(children = [], parent) {
|
||||
const showingChildren = children.filter(item => {
|
||||
if (item.hidden) {
|
||||
return false
|
||||
} else {
|
||||
// Temp set(will be used if only has one showing child)
|
||||
this.onlyOneChild = item
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
// When there is only one child router, the child router is displayed by default
|
||||
if (showingChildren.length === 1) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Show parent if there are no child router to display
|
||||
if (showingChildren.length === 0) {
|
||||
this.onlyOneChild = { ... parent, path: '', noShowingChildren: true }
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
resolvePath(routePath) {
|
||||
if (isExternal(routePath)) {
|
||||
return routePath
|
||||
}
|
||||
if (isExternal(this.basePath)) {
|
||||
return this.basePath
|
||||
}
|
||||
return path.resolve(this.basePath, routePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<div :class="{'has-logo':showLogo}">
|
||||
<logo v-if="showLogo" :collapse="isCollapse" />
|
||||
<el-scrollbar wrap-class="scrollbar-wrapper">
|
||||
<el-menu
|
||||
:default-active="activeMenu"
|
||||
:collapse="isCollapse"
|
||||
:background-color="variables.menuBg"
|
||||
:text-color="variables.menuText"
|
||||
:unique-opened="false"
|
||||
:active-text-color="variables.menuActiveText"
|
||||
:collapse-transition="false"
|
||||
mode="vertical"
|
||||
>
|
||||
<sidebar-item v-for="route in routes" :key="route.path" :item="route" :base-path="route.path" />
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import Logo from './Logo'
|
||||
import SidebarItem from './SidebarItem'
|
||||
import variables from '@/styles/variables.scss'
|
||||
|
||||
export default {
|
||||
components: { SidebarItem, Logo },
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'sidebar'
|
||||
]),
|
||||
routes() {
|
||||
return this.$router.options.routes
|
||||
},
|
||||
activeMenu() {
|
||||
const route = this.$route
|
||||
const { meta, path } = route
|
||||
// if set path, the sidebar will highlight the path you set
|
||||
if (meta.activeMenu) {
|
||||
return meta.activeMenu
|
||||
}
|
||||
return path
|
||||
},
|
||||
showLogo() {
|
||||
return this.$store.state.settings.sidebarLogo
|
||||
},
|
||||
variables() {
|
||||
return variables
|
||||
},
|
||||
isCollapse() {
|
||||
return !this.sidebar.opened
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,3 @@
|
||||
export { default as Navbar } from './Navbar'
|
||||
export { default as Sidebar } from './Sidebar'
|
||||
export { default as AppMain } from './AppMain'
|
93
6_web_app/image_seg_sam2/sam2_ui/src/layout/index.vue
Normal file
93
6_web_app/image_seg_sam2/sam2_ui/src/layout/index.vue
Normal file
@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<div :class="classObj" class="app-wrapper">
|
||||
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
|
||||
<sidebar class="sidebar-container" />
|
||||
<div class="main-container">
|
||||
<div :class="{'fixed-header':fixedHeader}">
|
||||
<navbar />
|
||||
</div>
|
||||
<app-main />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Navbar, Sidebar, AppMain } from './components'
|
||||
import ResizeMixin from './mixin/ResizeHandler'
|
||||
|
||||
export default {
|
||||
name: 'Layout',
|
||||
components: {
|
||||
Navbar,
|
||||
Sidebar,
|
||||
AppMain
|
||||
},
|
||||
mixins: [ResizeMixin],
|
||||
computed: {
|
||||
sidebar() {
|
||||
return this.$store.state.app.sidebar
|
||||
},
|
||||
device() {
|
||||
return this.$store.state.app.device
|
||||
},
|
||||
fixedHeader() {
|
||||
return this.$store.state.settings.fixedHeader
|
||||
},
|
||||
classObj() {
|
||||
return {
|
||||
hideSidebar: !this.sidebar.opened,
|
||||
openSidebar: this.sidebar.opened,
|
||||
withoutAnimation: this.sidebar.withoutAnimation,
|
||||
mobile: this.device === 'mobile'
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClickOutside() {
|
||||
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "~@/styles/mixin.scss";
|
||||
@import "~@/styles/variables.scss";
|
||||
|
||||
.app-wrapper {
|
||||
@include clearfix;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
&.mobile.openSidebar{
|
||||
position: fixed;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
.drawer-bg {
|
||||
background: #000;
|
||||
opacity: 0.3;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.fixed-header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 9;
|
||||
width: calc(100% - #{$sideBarWidth});
|
||||
transition: width 0.28s;
|
||||
}
|
||||
|
||||
.hideSidebar .fixed-header {
|
||||
width: calc(100% - 54px)
|
||||
}
|
||||
|
||||
.mobile .fixed-header {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,45 @@
|
||||
import store from '@/store'
|
||||
|
||||
const { body } = document
|
||||
const WIDTH = 992 // refer to Bootstrap's responsive design
|
||||
|
||||
export default {
|
||||
watch: {
|
||||
$route(route) {
|
||||
if (this.device === 'mobile' && this.sidebar.opened) {
|
||||
store.dispatch('app/closeSideBar', { withoutAnimation: false })
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
window.addEventListener('resize', this.$_resizeHandler)
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.$_resizeHandler)
|
||||
},
|
||||
mounted() {
|
||||
const isMobile = this.$_isMobile()
|
||||
if (isMobile) {
|
||||
store.dispatch('app/toggleDevice', 'mobile')
|
||||
store.dispatch('app/closeSideBar', { withoutAnimation: true })
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// use $_ for mixins properties
|
||||
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
|
||||
$_isMobile() {
|
||||
const rect = body.getBoundingClientRect()
|
||||
return rect.width - 1 < WIDTH
|
||||
},
|
||||
$_resizeHandler() {
|
||||
if (!document.hidden) {
|
||||
const isMobile = this.$_isMobile()
|
||||
store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop')
|
||||
|
||||
if (isMobile) {
|
||||
store.dispatch('app/closeSideBar', { withoutAnimation: true })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
30
6_web_app/image_seg_sam2/sam2_ui/src/main.js
Normal file
30
6_web_app/image_seg_sam2/sam2_ui/src/main.js
Normal file
@ -0,0 +1,30 @@
|
||||
import Vue from 'vue'
|
||||
|
||||
import 'normalize.css/normalize.css' // A modern alternative to CSS resets
|
||||
|
||||
import ElementUI from 'element-ui'
|
||||
import 'element-ui/lib/theme-chalk/index.css'
|
||||
import locale from 'element-ui/lib/locale/lang/en' // lang i18n
|
||||
|
||||
import '@/styles/index.scss' // global css
|
||||
|
||||
import App from './App'
|
||||
import store from './store'
|
||||
import router from './router'
|
||||
|
||||
import '@/permission' // permission control
|
||||
|
||||
// set ElementUI lang to EN
|
||||
Vue.use(ElementUI, { locale })
|
||||
// 如果想要中文版 element-ui,按如下方式声明
|
||||
// To use the Chinese version of element-ui, declare as follows
|
||||
// Vue.use(ElementUI)
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
router,
|
||||
store,
|
||||
render: h => h(App)
|
||||
})
|
27
6_web_app/image_seg_sam2/sam2_ui/src/permission.js
Normal file
27
6_web_app/image_seg_sam2/sam2_ui/src/permission.js
Normal file
@ -0,0 +1,27 @@
|
||||
import router from './router'
|
||||
import NProgress from 'nprogress' // progress bar
|
||||
import 'nprogress/nprogress.css' // progress bar style
|
||||
import getPageTitle from '@/utils/get-page-title'
|
||||
|
||||
NProgress.configure({ showSpinner: false }) // NProgress Configuration
|
||||
|
||||
router.beforeEach(async(to, from, next) => {
|
||||
// start progress bar
|
||||
NProgress.start()
|
||||
|
||||
// set page title
|
||||
document.title = getPageTitle(to.meta.title)
|
||||
|
||||
if (to.path === '/login') {
|
||||
// if is logged in, redirect to the home page
|
||||
next({ path: '/' })
|
||||
NProgress.done()
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
})
|
||||
|
||||
router.afterEach(() => {
|
||||
// finish progress bar
|
||||
NProgress.done()
|
||||
})
|
69
6_web_app/image_seg_sam2/sam2_ui/src/router/index.js
Normal file
69
6_web_app/image_seg_sam2/sam2_ui/src/router/index.js
Normal file
@ -0,0 +1,69 @@
|
||||
import Vue from 'vue'
|
||||
import Router from 'vue-router'
|
||||
|
||||
Vue.use(Router)
|
||||
|
||||
/* Layout */
|
||||
import Layout from '@/layout'
|
||||
|
||||
/**
|
||||
* Note: sub-menu only appear when route children.length >= 1
|
||||
* Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
|
||||
*
|
||||
* hidden: true if set true, item will not show in the sidebar(default is false)
|
||||
* alwaysShow: true if set true, will always show the root menu
|
||||
* if not set alwaysShow, when item has more than one children route,
|
||||
* it will becomes nested mode, otherwise not show the root menu
|
||||
* redirect: noRedirect if set noRedirect will no redirect in the breadcrumb
|
||||
* name:'router-name' the name is used by <keep-alive> (must set!!!)
|
||||
* meta : {
|
||||
roles: ['admin','editor'] control the page roles (you can set multiple roles)
|
||||
title: 'title' the name show in sidebar and breadcrumb (recommend set)
|
||||
icon: 'svg-name'/'el-icon-x' the icon show in the sidebar
|
||||
breadcrumb: false if set false, the item will hidden in breadcrumb(default is true)
|
||||
activeMenu: '/example/list' if set path, the sidebar will highlight the path you set
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* constantRoutes
|
||||
* a base page that does not have permission requirements
|
||||
* all roles can be accessed
|
||||
*/
|
||||
export const constantRoutes = [
|
||||
{
|
||||
path: '/404',
|
||||
component: () => import('@/views/404'),
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: '/',
|
||||
component: () => import('@/views/seg/index'),
|
||||
name: 'inference',
|
||||
meta: { title: '框选一键抠图', icon: 'el-icon-full-screen' }
|
||||
}
|
||||
]
|
||||
},
|
||||
// 404 page must be placed at the end !!!
|
||||
{ path: '*', redirect: '/404', hidden: true }
|
||||
]
|
||||
|
||||
const createRouter = () => new Router({
|
||||
// mode: 'history', // require service support
|
||||
scrollBehavior: () => ({ y: 0 }),
|
||||
routes: constantRoutes
|
||||
})
|
||||
|
||||
const router = createRouter()
|
||||
|
||||
// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
|
||||
export function resetRouter() {
|
||||
const newRouter = createRouter()
|
||||
router.matcher = newRouter.matcher // reset router
|
||||
}
|
||||
|
||||
export default router
|
16
6_web_app/image_seg_sam2/sam2_ui/src/settings.js
Normal file
16
6_web_app/image_seg_sam2/sam2_ui/src/settings.js
Normal file
@ -0,0 +1,16 @@
|
||||
module.exports = {
|
||||
|
||||
title: 'Web UI',
|
||||
|
||||
/**
|
||||
* @type {boolean} true | false
|
||||
* @description Whether fix the header
|
||||
*/
|
||||
fixedHeader: false,
|
||||
|
||||
/**
|
||||
* @type {boolean} true | false
|
||||
* @description Whether show the logo in sidebar
|
||||
*/
|
||||
sidebarLogo: false
|
||||
}
|
8
6_web_app/image_seg_sam2/sam2_ui/src/store/getters.js
Normal file
8
6_web_app/image_seg_sam2/sam2_ui/src/store/getters.js
Normal file
@ -0,0 +1,8 @@
|
||||
const getters = {
|
||||
sidebar: state => state.app.sidebar,
|
||||
device: state => state.app.device,
|
||||
token: state => state.user.token,
|
||||
avatar: state => state.user.avatar,
|
||||
name: state => state.user.name
|
||||
}
|
||||
export default getters
|
17
6_web_app/image_seg_sam2/sam2_ui/src/store/index.js
Normal file
17
6_web_app/image_seg_sam2/sam2_ui/src/store/index.js
Normal file
@ -0,0 +1,17 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import getters from './getters'
|
||||
import app from './modules/app'
|
||||
import settings from './modules/settings'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
const store = new Vuex.Store({
|
||||
modules: {
|
||||
app,
|
||||
settings
|
||||
},
|
||||
getters
|
||||
})
|
||||
|
||||
export default store
|
48
6_web_app/image_seg_sam2/sam2_ui/src/store/modules/app.js
Normal file
48
6_web_app/image_seg_sam2/sam2_ui/src/store/modules/app.js
Normal file
@ -0,0 +1,48 @@
|
||||
import Cookies from 'js-cookie'
|
||||
|
||||
const state = {
|
||||
sidebar: {
|
||||
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
|
||||
withoutAnimation: false
|
||||
},
|
||||
device: 'desktop'
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
TOGGLE_SIDEBAR: state => {
|
||||
state.sidebar.opened = !state.sidebar.opened
|
||||
state.sidebar.withoutAnimation = false
|
||||
if (state.sidebar.opened) {
|
||||
Cookies.set('sidebarStatus', 1)
|
||||
} else {
|
||||
Cookies.set('sidebarStatus', 0)
|
||||
}
|
||||
},
|
||||
CLOSE_SIDEBAR: (state, withoutAnimation) => {
|
||||
Cookies.set('sidebarStatus', 0)
|
||||
state.sidebar.opened = false
|
||||
state.sidebar.withoutAnimation = withoutAnimation
|
||||
},
|
||||
TOGGLE_DEVICE: (state, device) => {
|
||||
state.device = device
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
toggleSideBar({ commit }) {
|
||||
commit('TOGGLE_SIDEBAR')
|
||||
},
|
||||
closeSideBar({ commit }, { withoutAnimation }) {
|
||||
commit('CLOSE_SIDEBAR', withoutAnimation)
|
||||
},
|
||||
toggleDevice({ commit }, device) {
|
||||
commit('TOGGLE_DEVICE', device)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
mutations,
|
||||
actions
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user