提交
This commit is contained in:
33
.gitignore
vendored
Normal file
33
.gitignore
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
nbproject/private/
|
||||
build/
|
||||
nbbuild/
|
||||
dist/
|
||||
nbdist/
|
||||
.nb-gradle/
|
||||
|
||||
### Project ###
|
||||
logs/
|
||||
dependency-reduced-pom.xml
|
||||
disconf/
|
||||
/catlogs
|
||||
log
|
||||
status
|
||||
catlogs
|
||||
95
pom.xml
Normal file
95
pom.xml
Normal file
@@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.lmc.shuiyin</groupId>
|
||||
<artifactId>shuiyin</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<!--内部框架版本号-->
|
||||
<business.version>1.0.0-SNAPSHOT</business.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
<artifactId>jsoup</artifactId>
|
||||
<version>1.12.1</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
<artifactId>jsoup</artifactId>
|
||||
</dependency>
|
||||
<!--用于代码简写,注意provided-->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!--如果是非 web 应用则导入 core 包即可,如果是 web 应用,则 core 与 javase 一起导入。-->
|
||||
<!-- https://mvnrepository.com/artifact/com.google.zxing/core -->
|
||||
<dependency>
|
||||
<groupId>com.google.zxing</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>3.3.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.zxing</groupId>
|
||||
<artifactId>javase</artifactId>
|
||||
<version>3.3.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
<excludes>
|
||||
<exclude>*.properties</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
<includes>
|
||||
<include>application.properties</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
185
src/main/java/com/lmc/shuiyin/DFTUtil.java
Normal file
185
src/main/java/com/lmc/shuiyin/DFTUtil.java
Normal file
@@ -0,0 +1,185 @@
|
||||
package com.lmc.shuiyin;
|
||||
import lombok.val;
|
||||
import lombok.var;
|
||||
import org.opencv.core.*;
|
||||
import org.opencv.imgcodecs.Imgcodecs;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.opencv.core.CvType.CV_8S;
|
||||
|
||||
public class DFTUtil {
|
||||
public static void main(String[] args){
|
||||
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
|
||||
|
||||
var mat = Imgcodecs.imread("C:\\tools\\meinv.png",CV_8S);
|
||||
// var matscr=mat.clone();
|
||||
// Imgcodecs.imwrite("C:\\tools\\meinv_scr.png",matscr);
|
||||
//傅里叶变化
|
||||
//var mat1 = mat.clone();
|
||||
val dft = DFTUtil.getInstance();
|
||||
dft.transformImageWithText(mat,"aaaaaa",new Point(40,40),1D,new Scalar(0,0,0,0));
|
||||
var mat4 = dft.antitransformImage();
|
||||
Imgcodecs.imwrite("C:\\tools\\meinv2.png", mat4);
|
||||
// //加水印
|
||||
// var mat2 = mat1.clone();
|
||||
// dft.transformImageWithText(mat2,"车神威武",new Point(0,0),16.5, new Scalar(50,60,80));
|
||||
// Imgcodecs.imwrite("C:\\tools\\meinv2.png", mat2);
|
||||
//
|
||||
// //傅里叶变化
|
||||
// var mat3 = mat.clone();
|
||||
// mat3=dft.transformImage(mat3);
|
||||
// //逆傅里叶
|
||||
// var mat4 = dft.antitransformImage();
|
||||
// Imgcodecs.imwrite("C:\\tools\\meinv3.png", mat4);
|
||||
|
||||
}
|
||||
private static List<Mat> planes;
|
||||
private static Mat complexImage;
|
||||
|
||||
private DFTUtil(){}
|
||||
private static final DFTUtil dftUtil = new DFTUtil();
|
||||
|
||||
public static DFTUtil getInstance () {
|
||||
// System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
|
||||
planes = new ArrayList<>();
|
||||
complexImage = new Mat();
|
||||
return dftUtil;
|
||||
}
|
||||
|
||||
public Mat transformImage(Mat image) {
|
||||
// planes数组中存的通道数若开始不为空,需清空.
|
||||
if (!planes.isEmpty()) {
|
||||
planes.clear();
|
||||
}
|
||||
// optimize the dimension of the loaded com.lmc.image
|
||||
Mat padded = this.optimizeImageDim(image);
|
||||
padded.convertTo(padded, CvType.CV_32F);
|
||||
// prepare the com.lmc.image planes to obtain the complex com.lmc.image
|
||||
planes.add(padded);
|
||||
planes.add(Mat.zeros(padded.size(), CvType.CV_32F));
|
||||
// prepare a complex com.lmc.image for performing the dft
|
||||
Core.merge(planes, complexImage);
|
||||
// dft
|
||||
Core.dft(complexImage, complexImage);
|
||||
// optimize the com.lmc.image resulting from the dft operation
|
||||
Mat magnitude = this.createOptimizedMagnitude(complexImage);
|
||||
planes.clear();
|
||||
return magnitude;
|
||||
}
|
||||
|
||||
public void transformImageWithText(Mat image, String watermarkText, Point point, double fontSize, Scalar scalar) {
|
||||
// planes数组中存的通道数若开始不为空,需清空.
|
||||
if (!planes.isEmpty()) {
|
||||
planes.clear();
|
||||
}
|
||||
// optimize the dimension of the loaded com.lmc.image
|
||||
//Mat padded = this.optimizeImageDim(com.lmc.image);
|
||||
Mat padded = image;
|
||||
padded.convertTo(padded, CvType.CV_32F);
|
||||
// prepare the com.lmc.image planes to obtain the complex com.lmc.image
|
||||
planes.add(padded);
|
||||
planes.add(Mat.zeros(padded.size(), CvType.CV_32F));
|
||||
// prepare a complex com.lmc.image for performing the dft
|
||||
Core.merge(planes, complexImage);
|
||||
// dft
|
||||
Core.dft(complexImage, complexImage);
|
||||
// 频谱图上添加文本
|
||||
Imgproc.putText(complexImage, watermarkText, point, Imgproc.FONT_HERSHEY_DUPLEX, fontSize, scalar,2);
|
||||
Core.flip(complexImage, complexImage, -1);
|
||||
Imgproc.putText(complexImage, watermarkText, point, Imgproc.FONT_HERSHEY_DUPLEX, fontSize, scalar,2);
|
||||
Core.flip(complexImage, complexImage, -1);
|
||||
|
||||
planes.clear();
|
||||
}
|
||||
|
||||
public Mat antitransformImage() {
|
||||
Mat invDFT = new Mat();
|
||||
Core.idft(complexImage, invDFT, Core.DFT_SCALE | Core.DFT_REAL_OUTPUT, 0);
|
||||
Mat restoredImage = new Mat();
|
||||
invDFT.convertTo(restoredImage, CvType.CV_8U);
|
||||
planes.clear();
|
||||
return restoredImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 为加快傅里叶变换的速度,对要处理的图片尺寸进行优化
|
||||
*
|
||||
* @param image
|
||||
* the {@link Mat} to optimize
|
||||
* @return the com.lmc.image whose dimensions have been optimized
|
||||
*/
|
||||
private Mat optimizeImageDim(Mat image) {
|
||||
// init
|
||||
Mat padded = new Mat();
|
||||
// get the optimal rows size for dft
|
||||
int addPixelRows = Core.getOptimalDFTSize(image.rows());
|
||||
// get the optimal cols size for dft
|
||||
int addPixelCols = Core.getOptimalDFTSize(image.cols());
|
||||
// apply the optimal cols and rows size to the com.lmc.image
|
||||
Core.copyMakeBorder(image, padded, 0, addPixelRows - image.rows(), 0, addPixelCols - image.cols(),
|
||||
Core.BORDER_CONSTANT, Scalar.all(0));
|
||||
|
||||
return padded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimize the magnitude of the complex com.lmc.image obtained from the DFT, to
|
||||
* improve its visualization
|
||||
*
|
||||
* @param complexImage
|
||||
* the complex com.lmc.image obtained from the DFT
|
||||
* @return the optimized com.lmc.image
|
||||
*/
|
||||
private Mat createOptimizedMagnitude(Mat complexImage) {
|
||||
// init
|
||||
List<Mat> newPlanes = new ArrayList<>();
|
||||
Mat mag = new Mat();
|
||||
// split the comples com.lmc.image in two planes
|
||||
Core.split(complexImage, newPlanes);
|
||||
// compute the magnitude
|
||||
Core.magnitude(newPlanes.get(0), newPlanes.get(1), mag);
|
||||
|
||||
// move to a logarithmic scale
|
||||
Core.add(Mat.ones(mag.size(), CvType.CV_32F), mag, mag);
|
||||
Core.log(mag, mag);
|
||||
// optionally reorder the 4 quadrants of the magnitude com.lmc.image
|
||||
this.shiftDFT(mag);
|
||||
// normalize the magnitude com.lmc.image for the visualization since both JavaFX
|
||||
// and OpenCV need images with value between 0 and 255
|
||||
// convert back to CV_8UC1
|
||||
mag.convertTo(mag, CvType.CV_8UC1);
|
||||
Core.normalize(mag, mag, 0, 255, Core.NORM_MINMAX, CvType.CV_8UC1);
|
||||
|
||||
return mag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder the 4 quadrants of the com.lmc.image representing the magnitude, after
|
||||
* the DFT
|
||||
*
|
||||
* @param image
|
||||
* the {@link Mat} object whose quadrants are to reorder
|
||||
*/
|
||||
private void shiftDFT(Mat image) {
|
||||
image = image.submat(new Rect(0, 0, image.cols() & -2, image.rows() & -2));
|
||||
int cx = image.cols() / 2;
|
||||
int cy = image.rows() / 2;
|
||||
|
||||
Mat q0 = new Mat(image, new Rect(0, 0, cx, cy));
|
||||
Mat q1 = new Mat(image, new Rect(cx, 0, cx, cy));
|
||||
Mat q2 = new Mat(image, new Rect(0, cy, cx, cy));
|
||||
Mat q3 = new Mat(image, new Rect(cx, cy, cx, cy));
|
||||
|
||||
Mat tmp = new Mat();
|
||||
q0.copyTo(tmp);
|
||||
q3.copyTo(q0);
|
||||
tmp.copyTo(q3);
|
||||
|
||||
q1.copyTo(tmp);
|
||||
q2.copyTo(q1);
|
||||
tmp.copyTo(q2);
|
||||
}
|
||||
}
|
||||
33
src/main/java/com/lmc/shuiyin/ImageWatermarkUtilMain.java
Normal file
33
src/main/java/com/lmc/shuiyin/ImageWatermarkUtilMain.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package com.lmc.shuiyin;
|
||||
|
||||
import com.lmc.shuiyin.one.util.Utils;
|
||||
import org.opencv.core.Core;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.imgcodecs.Imgcodecs;
|
||||
|
||||
import static org.opencv.core.CvType.CV_8S;
|
||||
|
||||
/**
|
||||
* @author yangxiaohui
|
||||
* @Date: Create by 2018-10-25 19:42
|
||||
* @Description:
|
||||
*/
|
||||
public class ImageWatermarkUtilMain {
|
||||
static{
|
||||
//加载opencv动态库
|
||||
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
|
||||
}
|
||||
public static void main(String[] args){
|
||||
Mat img = Utils.read("C:\\tools\\meinv.png",CV_8S);//加载图片
|
||||
Mat outImg = ImgWatermarkUtil.addImageWatermarkWithText(img,"cheshen");
|
||||
Imgcodecs.imwrite("C:\\tools\\meinv2.png",outImg);//保存加过水印的图片
|
||||
//读取图片水印
|
||||
Mat watermarkImg = ImgWatermarkUtil.getImageWatermarkWithText(outImg);
|
||||
Imgcodecs.imwrite("C:\\tools\\meinv3.png",watermarkImg);//保存获取到的水印
|
||||
//部分截图
|
||||
Mat img444 = Utils.read("C:\\tools\\444.png",CV_8S);//加载图片
|
||||
Mat watermarkImg2 = ImgWatermarkUtil.getImageWatermarkWithText(img444);
|
||||
Imgcodecs.imwrite("C:\\tools\\555.png",watermarkImg2);//保存获取到的水印
|
||||
}
|
||||
|
||||
}
|
||||
146
src/main/java/com/lmc/shuiyin/ImgWatermarkUtil.java
Normal file
146
src/main/java/com/lmc/shuiyin/ImgWatermarkUtil.java
Normal file
@@ -0,0 +1,146 @@
|
||||
package com.lmc.shuiyin;
|
||||
|
||||
import org.opencv.core.*;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yangxiaohui
|
||||
* @Date: Create by 2018-10-25 19:14
|
||||
* @Description: 添加图片盲水印工具类
|
||||
*/
|
||||
public class ImgWatermarkUtil {
|
||||
private static List<Mat> planes = new ArrayList<Mat>();
|
||||
private static List<Mat> allPlanes = new ArrayList<Mat>();
|
||||
/**
|
||||
* <pre>
|
||||
* 添加图片文字水印
|
||||
* <pre>
|
||||
* @author Yangxiaohui
|
||||
* @date 2018-10-25 19:16
|
||||
* @param image 图片对象
|
||||
* @param watermarkText 水印文字
|
||||
*/
|
||||
public static Mat addImageWatermarkWithText(Mat image, String watermarkText){
|
||||
Mat complexImage = new Mat();
|
||||
//优化图像的尺寸
|
||||
//Mat padded = optimizeImageDim(com.lmc.image);
|
||||
Mat padded = splitSrc(image);
|
||||
padded.convertTo(padded, CvType.CV_32F);
|
||||
planes.add(padded);
|
||||
planes.add(Mat.zeros(padded.size(), CvType.CV_32F));
|
||||
Core.merge(planes, complexImage);
|
||||
// dft
|
||||
Core.dft(complexImage, complexImage);
|
||||
// 添加文本水印
|
||||
Scalar scalar = new Scalar(0, 0, 0);
|
||||
Point point = new Point(40, 40);
|
||||
Imgproc.putText(complexImage, watermarkText, point, Imgproc.FONT_HERSHEY_DUPLEX, 1D, scalar);
|
||||
Core.flip(complexImage, complexImage, -1);
|
||||
Imgproc.putText(complexImage, watermarkText, point, Imgproc.FONT_HERSHEY_DUPLEX, 1D, scalar);
|
||||
Core.flip(complexImage, complexImage, -1);
|
||||
return antitransformImage(complexImage, allPlanes);
|
||||
}
|
||||
/**
|
||||
* <pre>
|
||||
* 获取图片水印
|
||||
* <pre>
|
||||
* @author Yangxiaohui
|
||||
* @date 2018-10-25 19:58
|
||||
* @param image
|
||||
*/
|
||||
public static Mat getImageWatermarkWithText(Mat image){
|
||||
List<Mat> planes = new ArrayList<Mat>();
|
||||
Mat complexImage = new Mat();
|
||||
Mat padded = splitSrc(image);
|
||||
padded.convertTo(padded, CvType.CV_32F);
|
||||
planes.add(padded);
|
||||
planes.add(Mat.zeros(padded.size(), CvType.CV_32F));
|
||||
Core.merge(planes, complexImage);
|
||||
// dft
|
||||
Core.dft(complexImage, complexImage);
|
||||
Mat magnitude = createOptimizedMagnitude(complexImage);
|
||||
planes.clear();
|
||||
return magnitude;
|
||||
}
|
||||
|
||||
private static Mat splitSrc(Mat mat) {
|
||||
mat = optimizeImageDim(mat);
|
||||
Core.split(mat, allPlanes);
|
||||
Mat padded = new Mat();
|
||||
if (allPlanes.size() > 1) {
|
||||
for (int i = 0; i < allPlanes.size(); i++) {
|
||||
if (i == 0) {
|
||||
padded = allPlanes.get(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
padded = mat;
|
||||
}
|
||||
return padded;
|
||||
}
|
||||
private static Mat antitransformImage(Mat complexImage, List<Mat> allPlanes) {
|
||||
Mat invDFT = new Mat();
|
||||
Core.idft(complexImage, invDFT, Core.DFT_SCALE | Core.DFT_REAL_OUTPUT, 0);
|
||||
Mat restoredImage = new Mat();
|
||||
invDFT.convertTo(restoredImage, CvType.CV_8U);
|
||||
if (allPlanes.size() == 0) {
|
||||
allPlanes.add(restoredImage);
|
||||
} else {
|
||||
allPlanes.set(0, restoredImage);
|
||||
}
|
||||
Mat lastImage = new Mat();
|
||||
Core.merge(allPlanes, lastImage);
|
||||
return lastImage;
|
||||
}
|
||||
/**
|
||||
* <pre>
|
||||
* 为加快傅里叶变换的速度,对要处理的图片尺寸进行优化
|
||||
* <pre>
|
||||
* @author Yangxiaohui
|
||||
* @date 2018-10-25 19:33
|
||||
* @param image
|
||||
* @return
|
||||
*/
|
||||
private static Mat optimizeImageDim(Mat image) {
|
||||
Mat padded = new Mat();
|
||||
int addPixelRows = Core.getOptimalDFTSize(image.rows());
|
||||
int addPixelCols = Core.getOptimalDFTSize(image.cols());
|
||||
Core.copyMakeBorder(image, padded, 0, addPixelRows - image.rows(), 0, addPixelCols - image.cols(),
|
||||
Core.BORDER_CONSTANT, Scalar.all(0));
|
||||
|
||||
return padded;
|
||||
}
|
||||
private static Mat createOptimizedMagnitude(Mat complexImage) {
|
||||
List<Mat> newPlanes = new ArrayList<Mat>();
|
||||
Mat mag = new Mat();
|
||||
Core.split(complexImage, newPlanes);
|
||||
Core.magnitude(newPlanes.get(0), newPlanes.get(1), mag);
|
||||
Core.add(Mat.ones(mag.size(), CvType.CV_32F), mag, mag);
|
||||
Core.log(mag, mag);
|
||||
shiftDFT(mag);
|
||||
mag.convertTo(mag, CvType.CV_8UC1);
|
||||
Core.normalize(mag, mag, 0, 255, Core.NORM_MINMAX, CvType.CV_8UC1);
|
||||
return mag;
|
||||
}
|
||||
private static void shiftDFT(Mat image) {
|
||||
image = image.submat(new Rect(0, 0, image.cols() & -2, image.rows() & -2));
|
||||
int cx = image.cols() / 2;
|
||||
int cy = image.rows() / 2;
|
||||
|
||||
Mat q0 = new Mat(image, new Rect(0, 0, cx, cy));
|
||||
Mat q1 = new Mat(image, new Rect(cx, 0, cx, cy));
|
||||
Mat q2 = new Mat(image, new Rect(0, cy, cx, cy));
|
||||
Mat q3 = new Mat(image, new Rect(cx, cy, cx, cy));
|
||||
Mat tmp = new Mat();
|
||||
q0.copyTo(tmp);
|
||||
q3.copyTo(q0);
|
||||
tmp.copyTo(q3);
|
||||
q1.copyTo(tmp);
|
||||
q2.copyTo(q1);
|
||||
tmp.copyTo(q2);
|
||||
}
|
||||
}
|
||||
19
src/main/java/com/lmc/shuiyin/ShuiYinUtils.java
Normal file
19
src/main/java/com/lmc/shuiyin/ShuiYinUtils.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package com.lmc.shuiyin;
|
||||
|
||||
import org.opencv.core.Size;
|
||||
|
||||
import static org.opencv.imgproc.Imgproc.FONT_HERSHEY_COMPLEX;
|
||||
import static org.opencv.imgproc.Imgproc.getTextSize;
|
||||
|
||||
public class ShuiYinUtils {
|
||||
public static double getFontScale(Size maxSize, String watermark,int fontFace,int tickness){
|
||||
double fontScale=0.5;
|
||||
while (true){
|
||||
Size size = getTextSize(watermark,fontFace,fontScale,tickness,null);
|
||||
if(size.height>=maxSize.height || size.width>= maxSize.width)
|
||||
break;
|
||||
fontScale=fontScale+0.2;
|
||||
}
|
||||
return fontScale;
|
||||
}
|
||||
}
|
||||
20
src/main/java/com/lmc/shuiyin/one/Test.java
Normal file
20
src/main/java/com/lmc/shuiyin/one/Test.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package com.lmc.shuiyin.one;
|
||||
|
||||
import com.lmc.shuiyin.one.converter.Converter;
|
||||
import com.lmc.shuiyin.one.converter.DftConverter;
|
||||
import com.lmc.shuiyin.one.dencoder.Decoder;
|
||||
import com.lmc.shuiyin.one.dencoder.Encoder;
|
||||
import com.lmc.shuiyin.one.dencoder.TextEncoder;
|
||||
import org.opencv.core.Core;
|
||||
|
||||
public class Test {
|
||||
public static void main(String[] args) {
|
||||
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
|
||||
Converter converter = new DftConverter();
|
||||
Encoder encoder = new TextEncoder(converter);
|
||||
Decoder decoder = new Decoder(converter);
|
||||
encoder.encode("C:\\tools\\yinhua.png", "CheShenWeiWu", "C:\\tools\\yinhua2.png");
|
||||
decoder.decode("C:\\tools\\yinhua2.png", "C:\\tools\\yinhua3.png");
|
||||
decoder.decode("C:\\tools\\444.jpg", "C:\\tools\\555.jpg");
|
||||
}
|
||||
}
|
||||
30
src/main/java/com/lmc/shuiyin/one/converter/Converter.java
Normal file
30
src/main/java/com/lmc/shuiyin/one/converter/Converter.java
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2020 ww23(https://github.com/ww23/BlindWatermark).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.lmc.shuiyin.one.converter;
|
||||
|
||||
import org.opencv.core.Mat;
|
||||
|
||||
/**
|
||||
* @author ww23
|
||||
*/
|
||||
public interface Converter {
|
||||
Mat start(Mat src);
|
||||
void inverse(Mat com);
|
||||
void addTextWatermark(Mat com, String watermark);
|
||||
void addImageWatermark(Mat com, Mat watermark);
|
||||
Mat showWatermark(Mat src);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2020 ww23(https://github.com/ww23/BlindWatermark).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.lmc.shuiyin.one.converter;
|
||||
|
||||
import com.lmc.shuiyin.one.util.Utils;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
|
||||
import static org.opencv.core.Core.*;
|
||||
import static org.opencv.core.CvType.CV_32F;
|
||||
import static org.opencv.core.CvType.CV_8UC1;
|
||||
import static org.opencv.imgproc.Imgproc.*;
|
||||
|
||||
/**
|
||||
* @author ww23
|
||||
*/
|
||||
public class DctConverter implements Converter {
|
||||
|
||||
@Override
|
||||
public Mat start(Mat src) {
|
||||
if ((src.cols() & 1) != 0) {
|
||||
copyMakeBorder(src, src, 0, 0, 0, 1, BORDER_CONSTANT, Scalar.all(0));
|
||||
}
|
||||
if ((src.rows() & 1) != 0) {
|
||||
copyMakeBorder(src, src, 0, 1, 0, 0, BORDER_CONSTANT, Scalar.all(0));
|
||||
}
|
||||
src.convertTo(src, CV_32F);
|
||||
dct(src, src);
|
||||
return src;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inverse(Mat com) {
|
||||
idct(com, com);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTextWatermark(Mat com, String watermark) {
|
||||
putText(com, watermark,
|
||||
new Point(com.cols() >> 2, com.rows() >> 2),
|
||||
FONT_HERSHEY_COMPLEX, 2.0,
|
||||
new Scalar(2, 2, 2, 0), 2, 8, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addImageWatermark(Mat com, Mat watermark) {
|
||||
Mat mask = new Mat();
|
||||
inRange(watermark, new Scalar(0, 0, 0, 0), new Scalar(0, 0, 0, 0), mask);
|
||||
Mat i2 = new Mat(watermark.size(), watermark.type(), new Scalar(2, 2, 2, 0));
|
||||
i2.copyTo(watermark, mask);
|
||||
watermark.convertTo(watermark, CV_32F);
|
||||
int row = (com.rows() - watermark.rows()) >> 1;
|
||||
int col = (com.cols() - watermark.cols()) >> 1;
|
||||
copyMakeBorder(watermark, watermark, row, row, col, col, BORDER_CONSTANT, Scalar.all(0));
|
||||
Utils.fixSize(watermark, com);
|
||||
addWeighted(watermark, 0.03, com, 1, 0.0, com);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mat showWatermark(Mat src) {
|
||||
src.convertTo(src, COLOR_RGB2HSV);
|
||||
inRange(src, new Scalar(0, 0, 0, 0), new Scalar(16, 16, 16, 0), src);
|
||||
normalize(src, src, 0, 255, NORM_MINMAX, CV_8UC1);
|
||||
return src;
|
||||
}
|
||||
}
|
||||
107
src/main/java/com/lmc/shuiyin/one/converter/DftConverter.java
Normal file
107
src/main/java/com/lmc/shuiyin/one/converter/DftConverter.java
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2020 ww23(https://github.com/ww23/BlindWatermark).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.lmc.shuiyin.one.converter;
|
||||
|
||||
import com.lmc.shuiyin.ShuiYinUtils;
|
||||
import com.lmc.shuiyin.one.util.Utils;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.core.Size;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.opencv.core.Core.*;
|
||||
import static org.opencv.core.CvType.*;
|
||||
import static org.opencv.imgproc.Imgproc.*;
|
||||
|
||||
|
||||
/**
|
||||
* @author ww23
|
||||
*/
|
||||
@Deprecated
|
||||
public class DftConverter implements Converter {
|
||||
|
||||
@Override
|
||||
public Mat start(Mat src) {
|
||||
src.convertTo(src, CV_32F);
|
||||
List<Mat> planes = new ArrayList<>(2);
|
||||
Mat com = new Mat();
|
||||
planes.add(0, src);
|
||||
planes.add(1, Mat.zeros(src.size(), CV_32F));
|
||||
merge(planes, com);
|
||||
dft(com, com);
|
||||
return com;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inverse(Mat com) {
|
||||
List<Mat> planes = new ArrayList<>(2);
|
||||
idft(com, com);
|
||||
split(com, planes);
|
||||
normalize(planes.get(0), com, 0, 255, NORM_MINMAX, CV_8UC3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTextWatermark(Mat com, String watermark) {
|
||||
Scalar s = new Scalar(255, 255,255, 0);
|
||||
Point p = new Point(0, com.rows() / 3);
|
||||
int tickness=3;
|
||||
double fontScale = ShuiYinUtils.getFontScale(new Size(com.cols(),com.rows()/2),watermark,FONT_HERSHEY_COMPLEX,tickness);
|
||||
putText(com, watermark, p, FONT_HERSHEY_COMPLEX , fontScale, s, tickness,8,false);
|
||||
flip(com, com, -1);
|
||||
putText(com, watermark, p, FONT_HERSHEY_COMPLEX , fontScale, s, tickness,8,false);
|
||||
flip(com, com, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addImageWatermark(Mat com, Mat watermark) {
|
||||
List<Mat> planes = new ArrayList<>(2);
|
||||
List<Mat> newPlanes = new ArrayList<>(2);
|
||||
Mat temp = new Mat();
|
||||
int col = (com.cols() - watermark.cols()) >> 1;
|
||||
int row = ((com.rows() >> 1) - watermark.rows()) >> 1;
|
||||
watermark.convertTo(watermark, CV_32F);
|
||||
copyMakeBorder(watermark, watermark, row, row, col, col, BORDER_CONSTANT, Scalar.all(0));
|
||||
planes.add(0, watermark);
|
||||
flip(watermark, temp, -1);
|
||||
planes.add(1, temp);
|
||||
vconcat(planes, watermark);
|
||||
|
||||
newPlanes.add(0, watermark);
|
||||
newPlanes.add(1, watermark);
|
||||
merge(newPlanes, watermark);
|
||||
Utils.fixSize(watermark, com);
|
||||
addWeighted(watermark, 8, com, 1, 0.0, com);
|
||||
|
||||
split(com, planes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mat showWatermark(Mat src) {
|
||||
List<Mat> newPlanes = new ArrayList<>(2);
|
||||
Mat mag = new Mat();
|
||||
split(src, newPlanes);
|
||||
magnitude(newPlanes.get(0), newPlanes.get(1), mag);
|
||||
add(Mat.ones(mag.size(), CV_32F), mag, mag);
|
||||
log(mag, mag);
|
||||
mag.convertTo(mag, CV_8UC1);
|
||||
normalize(mag, mag, 0, 255, NORM_MINMAX, CV_8UC1);
|
||||
return mag;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2020 ww23(https://github.com/ww23/BlindWatermark).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.lmc.shuiyin.one.converter;
|
||||
|
||||
import org.opencv.core.Mat;
|
||||
|
||||
//TODO
|
||||
public class DwtConverter implements Converter {
|
||||
@Override
|
||||
public Mat start(Mat src) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inverse(Mat com) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTextWatermark(Mat com, String watermark) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addImageWatermark(Mat com, Mat watermark) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mat showWatermark(Mat src) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
47
src/main/java/com/lmc/shuiyin/one/dencoder/Decoder.java
Normal file
47
src/main/java/com/lmc/shuiyin/one/dencoder/Decoder.java
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2020 ww23(https://github.com/ww23/BlindWatermark).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.lmc.shuiyin.one.dencoder;
|
||||
|
||||
import com.lmc.shuiyin.one.converter.Converter;
|
||||
import com.lmc.shuiyin.one.util.Utils;
|
||||
|
||||
import static org.opencv.core.CvType.CV_8U;
|
||||
import static org.opencv.imgcodecs.Imgcodecs.imwrite;
|
||||
|
||||
/**
|
||||
* @author ww23
|
||||
*/
|
||||
public class Decoder {
|
||||
|
||||
private Converter converter;
|
||||
|
||||
public Decoder(Converter converter) {
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
public Converter getConverter() {
|
||||
return converter;
|
||||
}
|
||||
|
||||
public void setConverter(Converter converter) {
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
public void decode(String image, String output) {
|
||||
imwrite(output, this.converter.showWatermark(this.converter.start(Utils.read(image, CV_8U))));
|
||||
}
|
||||
}
|
||||
76
src/main/java/com/lmc/shuiyin/one/dencoder/Encoder.java
Normal file
76
src/main/java/com/lmc/shuiyin/one/dencoder/Encoder.java
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2020 ww23(https://github.com/ww23/BlindWatermark).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.lmc.shuiyin.one.dencoder;
|
||||
|
||||
import com.lmc.shuiyin.one.converter.Converter;
|
||||
import com.lmc.shuiyin.one.util.Utils;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.Rect;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.opencv.core.Core.merge;
|
||||
import static org.opencv.core.Core.split;
|
||||
import static org.opencv.core.CvType.CV_8S;
|
||||
import static org.opencv.imgcodecs.Imgcodecs.imwrite;
|
||||
|
||||
/**
|
||||
* @author ww23
|
||||
*/
|
||||
public abstract class Encoder {
|
||||
|
||||
Converter converter;
|
||||
|
||||
Encoder(Converter converter) {
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
public Converter getConverter() {
|
||||
return converter;
|
||||
}
|
||||
|
||||
public void setConverter(Converter converter) {
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
public void encode(String image, String watermark, String output) {
|
||||
Mat src = Utils.read(image, CV_8S);
|
||||
|
||||
List<Mat> channel = new ArrayList<>(3);
|
||||
List<Mat> newChannel = new ArrayList<>(3);
|
||||
split(src, channel);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
Mat com = this.converter.start(channel.get(i)).clone();
|
||||
this.addWatermark(com, watermark);
|
||||
this.converter.inverse(com);
|
||||
newChannel.add(i, com);
|
||||
}
|
||||
|
||||
Mat res = new Mat();
|
||||
merge(newChannel, res);
|
||||
|
||||
if (res.rows() != src.rows() || res.cols() != src.cols()) {
|
||||
res = new Mat(res, new Rect(0, 0, src.width(), src.height()));
|
||||
}
|
||||
|
||||
imwrite(output, res);
|
||||
}
|
||||
|
||||
public abstract void addWatermark(Mat com, String watermark);
|
||||
}
|
||||
38
src/main/java/com/lmc/shuiyin/one/dencoder/ImageEncoder.java
Normal file
38
src/main/java/com/lmc/shuiyin/one/dencoder/ImageEncoder.java
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2020 ww23(https://github.com/ww23/BlindWatermark).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.lmc.shuiyin.one.dencoder;
|
||||
|
||||
import com.lmc.shuiyin.one.converter.Converter;
|
||||
import com.lmc.shuiyin.one.util.Utils;
|
||||
import org.opencv.core.Mat;
|
||||
|
||||
import static org.opencv.core.CvType.CV_8U;
|
||||
|
||||
/**
|
||||
* @author ww23
|
||||
*/
|
||||
public class ImageEncoder extends Encoder {
|
||||
|
||||
public ImageEncoder(Converter converter) {
|
||||
super(converter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addWatermark(Mat com, String watermark) {
|
||||
this.converter.addImageWatermark(com, Utils.read(watermark, CV_8U));
|
||||
}
|
||||
}
|
||||
42
src/main/java/com/lmc/shuiyin/one/dencoder/TextEncoder.java
Normal file
42
src/main/java/com/lmc/shuiyin/one/dencoder/TextEncoder.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2020 ww23(https://github.com/ww23/BlindWatermark).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.lmc.shuiyin.one.dencoder;
|
||||
|
||||
import com.lmc.shuiyin.one.converter.Converter;
|
||||
import com.lmc.shuiyin.one.util.Utils;
|
||||
import org.opencv.core.Mat;
|
||||
|
||||
/**
|
||||
* @author ww23
|
||||
*/
|
||||
public class TextEncoder extends Encoder {
|
||||
|
||||
public TextEncoder(Converter converter) {
|
||||
super(converter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addWatermark(Mat com, String watermark) {
|
||||
//this.converter.addTextWatermark(com, watermark);
|
||||
if (Utils.isAscii(watermark)) {
|
||||
this.converter.addTextWatermark(com, watermark);
|
||||
} else {
|
||||
//Mat mat = Utils.read("C:\\tools\\test.png",CV_8U);//
|
||||
this.converter.addImageWatermark(com,Utils.drawNonAscii(watermark));
|
||||
}
|
||||
}
|
||||
}
|
||||
103
src/main/java/com/lmc/shuiyin/one/util/Utils.java
Normal file
103
src/main/java/com/lmc/shuiyin/one/util/Utils.java
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2020 ww23(https://github.com/ww23/BlindWatermark).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.lmc.shuiyin.one.util;
|
||||
|
||||
import org.apache.commons.lang.CharUtils;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.imgcodecs.Imgcodecs;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferByte;
|
||||
|
||||
import static org.opencv.core.Core.*;
|
||||
import static org.opencv.core.CvType.CV_8U;
|
||||
import static org.opencv.highgui.HighGui.imshow;
|
||||
import static org.opencv.highgui.HighGui.waitKey;
|
||||
import static org.opencv.imgcodecs.Imgcodecs.imread;
|
||||
|
||||
/**
|
||||
* @author ww23
|
||||
*/
|
||||
public class Utils {
|
||||
|
||||
public static Mat read(String image, int type) {
|
||||
Mat src = imread(image, type);
|
||||
if (src.empty()) {
|
||||
System.out.println("File not found!");
|
||||
System.exit(-1);
|
||||
}
|
||||
return src;
|
||||
}
|
||||
|
||||
public static void show(Mat mat) {
|
||||
imshow(Utils.class.toString(), mat);
|
||||
waitKey(0);
|
||||
}
|
||||
|
||||
public static Mat optimalDft(Mat srcImg) {
|
||||
Mat padded = new Mat();
|
||||
int opRows = getOptimalDFTSize(srcImg.rows());
|
||||
int opCols = getOptimalDFTSize(srcImg.cols());
|
||||
copyMakeBorder(srcImg, padded, 0, opRows - srcImg.rows(),
|
||||
0, opCols - srcImg.cols(), BORDER_CONSTANT, Scalar.all(0));
|
||||
return padded;
|
||||
}
|
||||
|
||||
public static boolean isAscii(String str) {
|
||||
for(char c : str.toCharArray()){
|
||||
if(!CharUtils.isAscii(c)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
//return "^[ -~]+$".matches(str);
|
||||
}
|
||||
|
||||
public static Mat drawNonAscii(String watermark) {
|
||||
Font font = new Font("Default", Font.PLAIN, 64);
|
||||
FontMetrics metrics = new Canvas().getFontMetrics(font);
|
||||
int width = metrics.stringWidth(watermark);
|
||||
int height = metrics.getHeight();
|
||||
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
|
||||
Graphics2D graphics = bufferedImage.createGraphics();
|
||||
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
|
||||
graphics.setFont(font);
|
||||
graphics.setColor(Color.WHITE);
|
||||
graphics.drawString(watermark, 0, metrics.getAscent());
|
||||
graphics.dispose();
|
||||
byte[] pixels = ((DataBufferByte) bufferedImage.getRaster().getDataBuffer()).getData();
|
||||
Mat res = new Mat(bufferedImage.getHeight(), bufferedImage.getWidth(), CV_8U);
|
||||
res.put(0, 0, pixels);
|
||||
Imgcodecs.imwrite("C:\\tools\\shuiyin.png", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
public static void fixSize(Mat src, Mat mirror) {
|
||||
if (src.rows() != mirror.rows()) {
|
||||
copyMakeBorder(src, src, 0, mirror.rows() - src.rows(),
|
||||
0, 0, BORDER_CONSTANT, Scalar.all(0));
|
||||
}
|
||||
if (src.cols() != mirror.cols()) {
|
||||
copyMakeBorder(src, src, 0, 0,
|
||||
0, mirror.cols() - src.cols(), BORDER_CONSTANT, Scalar.all(0));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
139
src/main/java/com/lmc/shuiyin/two/utils/QRCodeUtils.java
Normal file
139
src/main/java/com/lmc/shuiyin/two/utils/QRCodeUtils.java
Normal file
@@ -0,0 +1,139 @@
|
||||
package com.lmc.shuiyin.two.utils;
|
||||
|
||||
import com.google.zxing.*;
|
||||
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
|
||||
import com.google.zxing.client.j2se.MatrixToImageWriter;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.common.CharacterSetECI;
|
||||
import com.google.zxing.common.HybridBinarizer;
|
||||
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class QRCodeUtils {
|
||||
|
||||
// 二维码的宽度
|
||||
private int width;
|
||||
// 二维码的高度
|
||||
private int height;
|
||||
// 二维码的格式
|
||||
private String format;
|
||||
// 二维码参数
|
||||
private final Map<EncodeHintType, Object> paramMap;
|
||||
|
||||
|
||||
public QRCodeUtils() {
|
||||
// 1.默认尺寸
|
||||
this.width = 100;
|
||||
this.height = 100;
|
||||
// 2.默认格式
|
||||
this.format = "png";
|
||||
// 3,默认参数
|
||||
// 定义二维码的参数
|
||||
this.paramMap = new HashMap<>();
|
||||
// 设置二维码字符编码
|
||||
paramMap.put(EncodeHintType.CHARACTER_SET, CharacterSetECI.UTF8);
|
||||
// 设置二维码纠错等级
|
||||
paramMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
|
||||
// 设置二维码边距
|
||||
paramMap.put(EncodeHintType.MARGIN, 1);
|
||||
|
||||
}
|
||||
|
||||
public void setFormat(String format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public void setSize(int width, int heigth) {
|
||||
this.width = width;
|
||||
this.height = heigth;
|
||||
}
|
||||
|
||||
public void setParam(EncodeHintType type, Object param) {
|
||||
paramMap.put(type,param);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成二维码(写入文件)
|
||||
*
|
||||
* @param content 二维码内容
|
||||
* @param outPutFile 二维码输出路径
|
||||
*/
|
||||
public void QREncode(String content,String outPutFile) throws Exception {
|
||||
// 开始生成二维码
|
||||
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
|
||||
BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, width, height, paramMap);
|
||||
// 导出到指定目录
|
||||
Path path = new File(outPutFile).toPath();
|
||||
MatrixToImageWriter.writeToPath(bitMatrix, format, path);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成二维码(内存中)
|
||||
*
|
||||
* @param contents 二维码的内容
|
||||
* @return BufferedImage
|
||||
*/
|
||||
public BufferedImage QREncode(String contents) throws Exception {
|
||||
// 开始生成二维码
|
||||
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
|
||||
BitMatrix bitMatrix = multiFormatWriter.encode(contents,BarcodeFormat.QR_CODE, width, height, paramMap);
|
||||
// 写入内存
|
||||
int width = bitMatrix.getWidth();
|
||||
int height = bitMatrix.getHeight();
|
||||
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
bufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
return bufferedImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bufferedImage 二维码图片
|
||||
* @return 文本内容
|
||||
*/
|
||||
private Result getResult(BufferedImage bufferedImage) throws NotFoundException {
|
||||
BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(bufferedImage);
|
||||
HybridBinarizer binarizer = new HybridBinarizer(source);
|
||||
BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
|
||||
// 二维码参数
|
||||
Map hints = new HashMap<>();
|
||||
hints.put(EncodeHintType.CHARACTER_SET, CharacterSetECI.UTF8);
|
||||
MultiFormatReader formatReader = new MultiFormatReader();
|
||||
return formatReader.decode(binaryBitmap, hints);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析二维码
|
||||
*
|
||||
* @param filePath 待解析的二维码路径
|
||||
* @return 二维码内容
|
||||
*/
|
||||
public String QRReader(String filePath) throws Exception {
|
||||
File file = new File(filePath);
|
||||
// 读取指定的二维码文件
|
||||
BufferedImage bufferedImage = ImageIO.read(file);
|
||||
Result result = getResult(bufferedImage);
|
||||
bufferedImage.flush();
|
||||
return result.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析二维码
|
||||
*
|
||||
* @return 二维码内容
|
||||
*/
|
||||
public String QRReader(BufferedImage bufferedImage) throws Exception {
|
||||
Result result = getResult(bufferedImage);
|
||||
bufferedImage.flush();
|
||||
return result.getText();
|
||||
}
|
||||
}
|
||||
18
src/main/java/com/lmc/shuiyin/two/utils/TwoMain.java
Normal file
18
src/main/java/com/lmc/shuiyin/two/utils/TwoMain.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package com.lmc.shuiyin.two.utils;
|
||||
|
||||
|
||||
import org.opencv.core.Core;
|
||||
|
||||
public class TwoMain {
|
||||
static{
|
||||
//加载opencv动态库
|
||||
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
|
||||
}
|
||||
public static void main(String[] args){
|
||||
WaterMarkDFT.embed("C:\\tools\\meinv.png","huafu","C:\\tools\\meinv2.png");//保存加过水印的图片
|
||||
//读取图片水印
|
||||
WaterMarkDFT.extract("C:\\tools\\meinv2.png", "C:\\tools\\meinv3.png");
|
||||
//部分截图
|
||||
WaterMarkDFT.extract("C:\\tools\\444.png", "C:\\tools\\555.png");
|
||||
}
|
||||
}
|
||||
180
src/main/java/com/lmc/shuiyin/two/utils/WaterMarkDCT.java
Normal file
180
src/main/java/com/lmc/shuiyin/two/utils/WaterMarkDCT.java
Normal file
@@ -0,0 +1,180 @@
|
||||
package com.lmc.shuiyin.two.utils;
|
||||
|
||||
import org.opencv.core.Core;
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.imgcodecs.Imgcodecs;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.opencv.imgcodecs.Imgcodecs.imread;
|
||||
import static org.opencv.imgcodecs.Imgcodecs.imwrite;
|
||||
|
||||
/**
|
||||
* 1、DCT分块大小为8*8
|
||||
* 2、二值图大小为100*100
|
||||
* 3、所以原图需要800*800尺寸以上(长或宽不能低于800)
|
||||
*/
|
||||
public class WaterMarkDCT {
|
||||
|
||||
/**
|
||||
* 水印强度
|
||||
*/
|
||||
private static final double P = 65;
|
||||
|
||||
/**
|
||||
* @param imagePath 图片路径
|
||||
* @param watermarkPath 水印路径
|
||||
* @param outputPath 输出路径
|
||||
*/
|
||||
public static void embed(String imagePath, String watermarkPath, String outputPath) {
|
||||
// 读取原始图像
|
||||
Mat originaleImage = imread(imagePath);
|
||||
// 分离通道
|
||||
List<Mat> allPlanes = new ArrayList<>();
|
||||
Core.split(originaleImage, allPlanes);
|
||||
Mat YMat = allPlanes.get(0);
|
||||
// 获取水印的二值矩阵
|
||||
int[][] watermark = imageToMatrix(watermarkPath);
|
||||
// 开始将水印嵌入
|
||||
int length = 8; // DCT变换 分块的大小
|
||||
for (int i = 0; i < watermark.length; i++) {
|
||||
for (int j = 0; j < watermark[0].length; j++) {
|
||||
// 提取每个分块
|
||||
// block表示分块 而且为8*8的方阵
|
||||
Mat block = getImageValue(YMat, i, j, length);
|
||||
|
||||
int x1 = 1, y1 = 2;
|
||||
int x2 = 2, y2 = 1;
|
||||
|
||||
double[] a = block.get(x1, y1);
|
||||
double[] c = block.get(x2, y2);
|
||||
//对分块进行DCT变换
|
||||
Core.dct(block, block);
|
||||
a = block.get(x1, y1);
|
||||
c = block.get(x2, y2);
|
||||
if (watermark[i][j] == 1) {
|
||||
block.put(x1, y1, P);
|
||||
block.put(x2, y2, -P);
|
||||
}
|
||||
if (watermark[i][j] == 0) {
|
||||
block.put(x1, y1, -P);
|
||||
block.put(x2, y2, P);
|
||||
}
|
||||
//对上面分块进行IDCT变换
|
||||
Core.idct(block, block);
|
||||
for (int m = 0; m < length; m++) {
|
||||
for (int t = 0; t < length; t++) {
|
||||
double[] e = block.get(m, t);
|
||||
YMat.put(i * length + m, j * length + t, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Mat imageOut = new Mat();
|
||||
Core.merge(allPlanes, imageOut);
|
||||
imwrite(outputPath,imageOut);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param targetImage 带水印的目标图片
|
||||
* @param outputWatermark 输出水印
|
||||
*/
|
||||
public static void extract(String targetImage, String outputWatermark) {
|
||||
Mat image = imread(targetImage);
|
||||
List<Mat> allPlanes = new ArrayList<Mat>();
|
||||
Core.split(image, allPlanes);
|
||||
Mat YMat = allPlanes.get(0);
|
||||
// 注意 rows和cols 应该与之前加的水印尺寸一致
|
||||
int rows = 100;
|
||||
int cols = 100;
|
||||
int length = 8;
|
||||
int[][] watermark = new int[rows][cols];
|
||||
// 提取每块嵌入的水印信息
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < cols; j++) {
|
||||
//提取每个分块,block表示分块 而且为8*8的方阵
|
||||
Mat block = getImageValue(YMat, i, j, length);
|
||||
//对分块进行DCT变换
|
||||
Core.dct(block, block);
|
||||
//用于容纳DCT系数
|
||||
int x1 = 1, y1 = 2;
|
||||
int x2 = 2, y2 = 1;
|
||||
double[] a = block.get(x1, y1);
|
||||
double[] c = block.get(x2, y2);
|
||||
if (a[0] >= c[0]){
|
||||
watermark[i][j] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
matrixToImage(watermark,outputWatermark);
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取每个分块
|
||||
*
|
||||
* @param YMat:原分块
|
||||
* @param x:x与y联合表示第几个块
|
||||
* @param y:x与y联合表示第几个块
|
||||
* @param length:每个块的长度
|
||||
* @return mat
|
||||
*/
|
||||
private static Mat getImageValue(Mat YMat, int x, int y, int length) {
|
||||
Mat mat = new Mat(length, length, CvType.CV_32F);
|
||||
for (int i = 0; i < length; i++) {
|
||||
for (int j = 0; j < length; j++) {
|
||||
double[] temp = YMat.get(x * length + i, y * length + j);
|
||||
mat.put(i, j, temp);
|
||||
}
|
||||
}
|
||||
return mat;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将二维数组转换为一张图片
|
||||
*
|
||||
* @param watermark 水印信息二维数组
|
||||
* @param dstPath 图片路径
|
||||
*/
|
||||
private static void matrixToImage(int[][] watermark, String dstPath) {
|
||||
int rows = watermark.length;
|
||||
int columns = watermark[0].length;
|
||||
Mat image = new Mat(rows, columns, Imgproc.THRESH_BINARY);
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < columns; j++) {
|
||||
if (watermark[i][j] == 1) {
|
||||
image.put(i, j, 255);
|
||||
} else {
|
||||
image.put(i, j, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
Imgcodecs.imwrite(dstPath, image);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param srcPath 水印图片(二维码)的路径
|
||||
* @return 二维数组
|
||||
*/
|
||||
private static int[][] imageToMatrix(String srcPath) {
|
||||
Mat mat = imread(srcPath, Imgproc.THRESH_BINARY);
|
||||
int rows = mat.rows();
|
||||
int columns = mat.cols();
|
||||
int[][] waterMark = new int[rows][columns];
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < columns; j++) {
|
||||
double[] doubles = mat.get(i, j);
|
||||
if ((int) doubles[0] == 255) {
|
||||
waterMark[i][j] = 1;
|
||||
} else {
|
||||
waterMark[i][j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return waterMark;
|
||||
}
|
||||
}
|
||||
108
src/main/java/com/lmc/shuiyin/two/utils/WaterMarkDFT.java
Normal file
108
src/main/java/com/lmc/shuiyin/two/utils/WaterMarkDFT.java
Normal file
@@ -0,0 +1,108 @@
|
||||
package com.lmc.shuiyin.two.utils;
|
||||
|
||||
import org.opencv.core.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.opencv.core.Core.*;
|
||||
import static org.opencv.imgcodecs.Imgcodecs.imread;
|
||||
import static org.opencv.imgcodecs.Imgcodecs.imwrite;
|
||||
import static org.opencv.imgproc.Imgproc.FONT_HERSHEY_COMPLEX;
|
||||
import static org.opencv.imgproc.Imgproc.putText;
|
||||
|
||||
public class WaterMarkDFT {
|
||||
public static void embed(String imagePath, String watermark, String outputPath) {
|
||||
Mat image = imread(imagePath);
|
||||
// 1.优化图像的尺寸 加快处理速度
|
||||
// Mat padded = optimizeImageDimensions(originaleImage);
|
||||
// 分离通道, allPlanes[0]
|
||||
List<Mat> allPlanes = new ArrayList<>();
|
||||
Core.split(image, allPlanes);
|
||||
image = allPlanes.get(0);
|
||||
image.convertTo(image, CvType.CV_32F);
|
||||
List<Mat> planes = new ArrayList<>();
|
||||
planes.add(image);
|
||||
planes.add(Mat.zeros(image.size(), CvType.CV_32F));
|
||||
Mat complexImage = new Mat();
|
||||
Core.merge(planes, complexImage);
|
||||
// 2.进行dft变换
|
||||
Core.dft(complexImage, complexImage);
|
||||
// 3.添加文本水印
|
||||
Scalar scalar = new Scalar(2, 2, 2);
|
||||
Point point = new Point(40, 40);
|
||||
putText(complexImage, watermark, point, FONT_HERSHEY_COMPLEX, 1.5, scalar,3, 20);
|
||||
flip(complexImage, complexImage, -1);
|
||||
putText(complexImage, watermark, point, FONT_HERSHEY_COMPLEX, 1.5, scalar,3, 20);
|
||||
flip(complexImage, complexImage, -1);
|
||||
// 3.idft逆变换成图片
|
||||
Mat invDFT = new Mat();
|
||||
Core.idft(complexImage, invDFT, Core.DFT_SCALE | Core.DFT_REAL_OUTPUT, 0);
|
||||
// 将得到的invDFT类型转换
|
||||
invDFT.convertTo(invDFT, CvType.CV_8U);
|
||||
// 将转换后的放入数组
|
||||
allPlanes.set(0, invDFT);
|
||||
// 将allPlanes数组合并成一个多通道的mat
|
||||
Core.merge(allPlanes, invDFT);
|
||||
// 4.保存图片
|
||||
imwrite(outputPath, invDFT);
|
||||
}
|
||||
|
||||
public static void extract(String targetImage, String outputWatermark) {
|
||||
Mat image = imread(targetImage);
|
||||
// 1.优化图像的尺寸 加快处理速度
|
||||
// Mat padded = optimizeImageDimensions(com.lmc.image);
|
||||
// 2.分离通道, allPlanes[0]
|
||||
List<Mat> allPlanes = new ArrayList<>();
|
||||
Core.split(image, allPlanes);
|
||||
image = allPlanes.get(0);
|
||||
image.convertTo(image, CvType.CV_32F);
|
||||
// 3.Mat 数组,第一个为扩展后的图像,一个为空图像,
|
||||
List<Mat> planes = new ArrayList<>();
|
||||
planes.add(image);
|
||||
planes.add(Mat.zeros(image.size(), CvType.CV_32F));
|
||||
// 将planes数组组合合并成一个多通道的数组complexImage
|
||||
Mat complexImage = new Mat();
|
||||
Core.merge(planes, complexImage);
|
||||
// 4.进行dft
|
||||
Core.dft(complexImage, complexImage);
|
||||
// 5、进行对数尺度(logarithmic scale)缩放
|
||||
List<Mat> newPlanes = new ArrayList<>();
|
||||
Mat mag = new Mat();
|
||||
Core.split(complexImage, newPlanes);
|
||||
Core.magnitude(newPlanes.get(0), newPlanes.get(1), mag);
|
||||
Core.add(Mat.ones(mag.size(), CvType.CV_32F), mag, mag);
|
||||
Core.log(mag, mag);
|
||||
|
||||
// 6、剪切和重分布图像限
|
||||
mag = mag.submat(new Rect(0, 0, mag.cols() & -2, mag.rows() & -2));
|
||||
int cx = mag.cols() / 2;
|
||||
int cy = mag.rows() / 2;
|
||||
|
||||
Mat q0 = new Mat(mag, new Rect(0, 0, cx, cy));
|
||||
Mat q1 = new Mat(mag, new Rect(cx, 0, cx, cy));
|
||||
Mat q2 = new Mat(mag, new Rect(0, cy, cx, cy));
|
||||
Mat q3 = new Mat(mag, new Rect(cx, cy, cx, cy));
|
||||
Mat tmp = new Mat();
|
||||
q0.copyTo(tmp);
|
||||
q3.copyTo(q0);
|
||||
tmp.copyTo(q3);
|
||||
q1.copyTo(tmp);
|
||||
q2.copyTo(q1);
|
||||
tmp.copyTo(q2);
|
||||
// 7、归一化,用0到1之间的浮点值将矩阵变换为可视的图像格式
|
||||
mag.convertTo(mag, CvType.CV_8UC1);
|
||||
Core.normalize(mag, mag, 0, 255, Core.NORM_MINMAX, CvType.CV_8UC1);
|
||||
// 8.保存图片
|
||||
imwrite(outputWatermark,mag);
|
||||
}
|
||||
|
||||
private static Mat optimizeImageDimensions(Mat image) {
|
||||
Mat padded = new Mat();
|
||||
int addPixelRows = Core.getOptimalDFTSize(image.rows());
|
||||
int addPixelCols = Core.getOptimalDFTSize(image.cols());
|
||||
copyMakeBorder(image, padded, 0, addPixelRows - image.rows(),
|
||||
0, addPixelCols - image.cols(), BORDER_CONSTANT, Scalar.all(0));
|
||||
return padded;
|
||||
}
|
||||
}
|
||||
23
src/main/resources/application.properties
Normal file
23
src/main/resources/application.properties
Normal file
@@ -0,0 +1,23 @@
|
||||
# application
|
||||
spring.application.name=shuiyin
|
||||
# profile
|
||||
pring.main.allow-bean-definition-overriding=true
|
||||
bsf.web.exception.enabled=false
|
||||
bsf.web.response.enabled=false
|
||||
#<23><><EFBFBD><EFBFBD>֧<EFBFBD><D6A7>
|
||||
bsf.web.cors3.enabled=true
|
||||
#֧<><D6A7>cookie<69>Ŀ<EFBFBD><C4BF><EFBFBD>ʹ<EFBFBD><CAB9>
|
||||
bsf.web.cors3.cookie.enabled=true
|
||||
##### web.config####
|
||||
#admin=;admin,123;
|
||||
#bsf.configmanagerconnectstring=type=sqlserver;pooltype=druid;server=192.168.1.101:1433;Database=dyd_bs_configmanager;username=sa;password=12345;
|
||||
#####freemarker####
|
||||
#
|
||||
|
||||
|
||||
# server
|
||||
server.port=8082
|
||||
server.servlet.context-path=/
|
||||
# db
|
||||
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
|
||||
spring.jackson.time-zone=GMT+8
|
||||
BIN
src/main/resources/lib/opencv-460.jar
Normal file
BIN
src/main/resources/lib/opencv-460.jar
Normal file
Binary file not shown.
Reference in New Issue
Block a user