提交
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