();
+ /**
+ *
+ * 添加图片文字水印
+ *
+ * @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