Java 图片添加数字暗水印工具类。
package cnki.thesis.common.utils;
import org.opencv.core.*;
import java.util.ArrayList;
import java.util.List;
import static org.opencv.core.Core.*;
import static org.opencv.imgproc.Imgproc.*;
import static org.opencv.imgproc.Imgproc.FONT_HERSHEY_DUPLEX;
public class ImageDarkMarkUtils {
private static List<Mat> planes;
private static Mat complexImage;
private ImageDarkMarkUtils(){}
private static final ImageDarkMarkUtils dftUtil = new ImageDarkMarkUtils();
public static ImageDarkMarkUtils getInstance () {
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 image
Mat padded = this.optimizeImageDim(image);
padded.convertTo(padded, CvType.CV_32F);
// prepare the image planes to obtain the complex image
planes.add(padded);
planes.add(Mat.zeros(padded.size(), CvType.CV_32F));
// prepare a complex image for performing the dft
merge(planes, complexImage);
dft(complexImage, complexImage);
// optimize the 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 image
Mat padded = this.optimizeImageDim(image);
padded.convertTo(padded, CvType.CV_32F);
// prepare the image planes to obtain the complex image
planes.add(padded);
planes.add(Mat.zeros(padded.size(), CvType.CV_32F));
// prepare a complex image for performing the dft
merge(planes, complexImage);
dft(complexImage, complexImage);
// 频谱图上添加文本
putText(complexImage, watermarkText, point, FONT_HERSHEY_DUPLEX, fontSize, scalar,2);
flip(complexImage, complexImage, -1);
putText(complexImage, watermarkText, point, FONT_HERSHEY_DUPLEX, fontSize, scalar,2);
flip(complexImage, complexImage, -1);
planes.clear();
}
public Mat antitransformImage() {
Mat invDFT = new Mat();
idft(complexImage, invDFT, DFT_SCALE | 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 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 = getOptimalDFTSize(image.rows());
// get the optimal cols size for dft
int addPixelCols = getOptimalDFTSize(image.cols());
// apply the optimal cols and rows size to the 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 image obtained from the DFT, to
* improve its visualization
*
* @param complexImage
* the complex image obtained from the DFT
* @return the optimized image
*/
private Mat createOptimizedMagnitude(Mat complexImage) {
// init
List<Mat> newPlanes = new ArrayList<>();
Mat mag = new Mat();
// split the comples image in two planes
split(complexImage, newPlanes);
// compute the magnitude
magnitude(newPlanes.get(0), newPlanes.get(1), mag);
// move to a logarithmic scale
add(Mat.ones(mag.size(), CvType.CV_32F), mag, mag);
log(mag, mag);
// optionally reorder the 4 quadrants of the magnitude image
this.shiftDFT(mag);
// normalize the magnitude 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);
normalize(mag, mag, 0, 255, NORM_MINMAX, CvType.CV_8UC1);
return mag;
}
/**
* Reorder the 4 quadrants of the 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);
}
}
调用方法
public static void matDropTextToBuffer() {
Mat img11 = Imgcodecs.imread("C:\\Users\\WXL\\Desktop\\77.jpg");
ImageDarkMarkUtils pdf = ImageDarkMarkUtils.getInstance();
Mat s = pdf.transformImage(img11);
pdf.transformImageWithText(s,"1342536475869",new Point(img11.height()/3,img11.width()/3),12.0,new Scalar(0, 0, 0));
//Mat s = addImageWatermarkWithText(img11, "onejane");
Imgcodecs.imwrite("C:\\Users\\WXL\\Desktop\\3.jpg", s);
//Mat watermarkImg11 = getImageWatermarkWithText(img11);
Mat watermarkImg11 = pdf.transformImage(s);
Imgcodecs.imwrite("C:\\Users\\WXL\\Desktop\\4.jpg", watermarkImg11);
}
生成暗水印