commit b4ff023a4d00087493554dd38405b8eb524e6d3c Author: chejiangyi <4251595> Date: Tue Jun 14 10:46:36 2022 +0800 提交 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4f99d4e --- /dev/null +++ b/.gitignore @@ -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 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..01c92cc --- /dev/null +++ b/pom.xml @@ -0,0 +1,95 @@ + + + 4.0.0 + + com.lmc.shuiyin + shuiyin + 1.0-SNAPSHOT + + + 8 + 8 + UTF-8 + + 1.0.0-SNAPSHOT + + + + + + + org.jsoup + jsoup + 1.12.1 + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-freemarker + + + com.alibaba + druid + + + org.jsoup + jsoup + + + + org.projectlombok + lombok + provided + + + + + + com.google.zxing + core + 3.3.3 + + + + com.google.zxing + javase + 3.3.3 + + + + + + + src/main/resources + true + + *.properties + + + + src/main/resources + true + + application.properties + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/src/main/java/com/lmc/shuiyin/DFTUtil.java b/src/main/java/com/lmc/shuiyin/DFTUtil.java new file mode 100644 index 0000000..432fb0e --- /dev/null +++ b/src/main/java/com/lmc/shuiyin/DFTUtil.java @@ -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 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 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); + } +} diff --git a/src/main/java/com/lmc/shuiyin/ImageWatermarkUtilMain.java b/src/main/java/com/lmc/shuiyin/ImageWatermarkUtilMain.java new file mode 100644 index 0000000..49d467b --- /dev/null +++ b/src/main/java/com/lmc/shuiyin/ImageWatermarkUtilMain.java @@ -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);//保存获取到的水印 + } + +} \ No newline at end of file diff --git a/src/main/java/com/lmc/shuiyin/ImgWatermarkUtil.java b/src/main/java/com/lmc/shuiyin/ImgWatermarkUtil.java new file mode 100644 index 0000000..842554c --- /dev/null +++ b/src/main/java/com/lmc/shuiyin/ImgWatermarkUtil.java @@ -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 planes = new ArrayList(); + private static List allPlanes = new ArrayList(); + /** + *
+     *     添加图片文字水印
+     * 
+     * @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);
+    }
+    /**
+     * 
+     *     获取图片水印
+     * 
+     * @author Yangxiaohui
+     * @date 2018-10-25 19:58
+     * @param image
+     */
+    public static Mat getImageWatermarkWithText(Mat image){
+        List planes = new ArrayList();
+        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 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;
+    }
+    /**
+     * 
+     *     为加快傅里叶变换的速度,对要处理的图片尺寸进行优化
+     * 
+     * @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 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);
+        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);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/lmc/shuiyin/ShuiYinUtils.java b/src/main/java/com/lmc/shuiyin/ShuiYinUtils.java
new file mode 100644
index 0000000..7ea3f8a
--- /dev/null
+++ b/src/main/java/com/lmc/shuiyin/ShuiYinUtils.java
@@ -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;
+    }
+}
diff --git a/src/main/java/com/lmc/shuiyin/one/Test.java b/src/main/java/com/lmc/shuiyin/one/Test.java
new file mode 100644
index 0000000..f67138f
--- /dev/null
+++ b/src/main/java/com/lmc/shuiyin/one/Test.java
@@ -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");
+    }
+}
diff --git a/src/main/java/com/lmc/shuiyin/one/converter/Converter.java b/src/main/java/com/lmc/shuiyin/one/converter/Converter.java
new file mode 100644
index 0000000..86b8fef
--- /dev/null
+++ b/src/main/java/com/lmc/shuiyin/one/converter/Converter.java
@@ -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);
+}
diff --git a/src/main/java/com/lmc/shuiyin/one/converter/DctConverter.java b/src/main/java/com/lmc/shuiyin/one/converter/DctConverter.java
new file mode 100644
index 0000000..c047a8e
--- /dev/null
+++ b/src/main/java/com/lmc/shuiyin/one/converter/DctConverter.java
@@ -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;
+    }
+}
diff --git a/src/main/java/com/lmc/shuiyin/one/converter/DftConverter.java b/src/main/java/com/lmc/shuiyin/one/converter/DftConverter.java
new file mode 100644
index 0000000..40fe06e
--- /dev/null
+++ b/src/main/java/com/lmc/shuiyin/one/converter/DftConverter.java
@@ -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 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 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 planes = new ArrayList<>(2);
+        List 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 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;
+    }
+}
diff --git a/src/main/java/com/lmc/shuiyin/one/converter/DwtConverter.java b/src/main/java/com/lmc/shuiyin/one/converter/DwtConverter.java
new file mode 100644
index 0000000..5f1197a
--- /dev/null
+++ b/src/main/java/com/lmc/shuiyin/one/converter/DwtConverter.java
@@ -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;
+    }
+}
diff --git a/src/main/java/com/lmc/shuiyin/one/dencoder/Decoder.java b/src/main/java/com/lmc/shuiyin/one/dencoder/Decoder.java
new file mode 100644
index 0000000..da69989
--- /dev/null
+++ b/src/main/java/com/lmc/shuiyin/one/dencoder/Decoder.java
@@ -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))));
+    }
+}
diff --git a/src/main/java/com/lmc/shuiyin/one/dencoder/Encoder.java b/src/main/java/com/lmc/shuiyin/one/dencoder/Encoder.java
new file mode 100644
index 0000000..aba8570
--- /dev/null
+++ b/src/main/java/com/lmc/shuiyin/one/dencoder/Encoder.java
@@ -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 channel = new ArrayList<>(3);
+        List 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);
+}
diff --git a/src/main/java/com/lmc/shuiyin/one/dencoder/ImageEncoder.java b/src/main/java/com/lmc/shuiyin/one/dencoder/ImageEncoder.java
new file mode 100644
index 0000000..3d1375b
--- /dev/null
+++ b/src/main/java/com/lmc/shuiyin/one/dencoder/ImageEncoder.java
@@ -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));
+    }
+}
diff --git a/src/main/java/com/lmc/shuiyin/one/dencoder/TextEncoder.java b/src/main/java/com/lmc/shuiyin/one/dencoder/TextEncoder.java
new file mode 100644
index 0000000..d10accb
--- /dev/null
+++ b/src/main/java/com/lmc/shuiyin/one/dencoder/TextEncoder.java
@@ -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));
+        }
+    }
+}
diff --git a/src/main/java/com/lmc/shuiyin/one/util/Utils.java b/src/main/java/com/lmc/shuiyin/one/util/Utils.java
new file mode 100644
index 0000000..651c687
--- /dev/null
+++ b/src/main/java/com/lmc/shuiyin/one/util/Utils.java
@@ -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));
+        }
+    }
+
+}
diff --git a/src/main/java/com/lmc/shuiyin/two/utils/QRCodeUtils.java b/src/main/java/com/lmc/shuiyin/two/utils/QRCodeUtils.java
new file mode 100644
index 0000000..10fc28a
--- /dev/null
+++ b/src/main/java/com/lmc/shuiyin/two/utils/QRCodeUtils.java
@@ -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 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();
+    }
+}
diff --git a/src/main/java/com/lmc/shuiyin/two/utils/TwoMain.java b/src/main/java/com/lmc/shuiyin/two/utils/TwoMain.java
new file mode 100644
index 0000000..c73733f
--- /dev/null
+++ b/src/main/java/com/lmc/shuiyin/two/utils/TwoMain.java
@@ -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");
+    }
+}
diff --git a/src/main/java/com/lmc/shuiyin/two/utils/WaterMarkDCT.java b/src/main/java/com/lmc/shuiyin/two/utils/WaterMarkDCT.java
new file mode 100644
index 0000000..dd2ad1c
--- /dev/null
+++ b/src/main/java/com/lmc/shuiyin/two/utils/WaterMarkDCT.java
@@ -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 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 allPlanes = new ArrayList();
+        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;
+    }
+}
diff --git a/src/main/java/com/lmc/shuiyin/two/utils/WaterMarkDFT.java b/src/main/java/com/lmc/shuiyin/two/utils/WaterMarkDFT.java
new file mode 100644
index 0000000..3029abf
--- /dev/null
+++ b/src/main/java/com/lmc/shuiyin/two/utils/WaterMarkDFT.java
@@ -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 allPlanes = new ArrayList<>();
+        Core.split(image, allPlanes);
+        image = allPlanes.get(0);
+        image.convertTo(image, CvType.CV_32F);
+        List 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 allPlanes = new ArrayList<>();
+        Core.split(image, allPlanes);
+        image = allPlanes.get(0);
+        image.convertTo(image, CvType.CV_32F);
+        // 3.Mat 数组,第一个为扩展后的图像,一个为空图像,
+        List 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 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;
+    }
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
new file mode 100644
index 0000000..b8aac8b
--- /dev/null
+++ b/src/main/resources/application.properties
@@ -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
+#֧
+bsf.web.cors3.enabled=true
+#֧cookieĿʹ
+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
diff --git a/src/main/resources/lib/opencv-460.jar b/src/main/resources/lib/opencv-460.jar
new file mode 100644
index 0000000..0862f45
Binary files /dev/null and b/src/main/resources/lib/opencv-460.jar differ