This commit is contained in:
chejiangyi
2022-06-14 10:46:36 +08:00
commit b4ff023a4d
22 changed files with 1570 additions and 0 deletions

33
.gitignore vendored Normal file
View 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
View 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>

View 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);
}
}

View 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);//保存获取到的水印
}
}

View 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);
}
}

View 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;
}
}

View 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");
}
}

View 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);
}

View File

@@ -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;
}
}

View 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;
}
}

View 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.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;
}
}

View 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))));
}
}

View 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);
}

View 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));
}
}

View 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));
}
}
}

View 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));
}
}
}

View 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();
}
}

View 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");
}
}

View 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 xx与y联合表示第几个块
* @param yx与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;
}
}

View 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;
}
}

View 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

Binary file not shown.