using System.Collections.Generic; using OpenCvSharp; namespace Com.Lmc.ShuiYin.Two.Utils { public class WaterMarkDFT { public static void Embed(string imagePath, string watermark, string outputPath) { Mat image = Cv2.ImRead(imagePath); List allPlanes = new List(); Cv2.Split(image, out Mat[] splitPlanes); allPlanes.AddRange(splitPlanes); Mat processImage = allPlanes[0]; processImage.ConvertTo(processImage, MatType.CV_32F); List planes = new List(); planes.Add(processImage); planes.Add(Mat.Zeros(processImage.Size(), MatType.CV_32F)); Mat complexImage = new Mat(); Cv2.Merge(planes.ToArray(), complexImage); Cv2.Dft(complexImage, complexImage); Scalar scalar = new Scalar(2, 2, 2); Point point = new Point(40, 40); Cv2.PutText(complexImage, watermark, point, HersheyFonts.HersheyComplex, 1.5, scalar, 3, LineTypes.Link8, false); // Java: 20 -> bottomLeftOrigin? No, putText last arg is bottomLeftOrigin. Java code says 20?? // Java putText signature: (img, text, org, fontFace, fontScale, color, thickness, lineType, bottomLeftOrigin) // Java code: putText(complexImage, watermark, point, FONT_HERSHEY_COMPLEX, 1.5, scalar, 3, 20); // Wait, 20 is not boolean. // Check Java params: // putText(Mat img, String text, Point org, int fontFace, double fontScale, Scalar color, int thickness) // or // putText(Mat img, String text, Point org, int fontFace, double fontScale, Scalar color, int thickness, int lineType, boolean bottomLeftOrigin) // The code has 8 arguments. // putText(complexImage, watermark, point, FONT_HERSHEY_COMPLEX, 1.5, scalar,3, 20); // Arg 8 is 20? 20 is not boolean. // Maybe they mean lineType=20? But lineType is usually 8, 4, CV_AA (16). // Maybe it is calling a different overload? // Actually, in the Java code: `putText(complexImage, watermark, point, FONT_HERSHEY_COMPLEX, 1.5, scalar,3, 20);` // If I assume 20 is lineType? CV_AA? No. // Let's assume standard parameters: thickness=3, lineType=20? // I will use standard LineTypes.Link8 and false for bottomLeftOrigin. Cv2.Flip(complexImage, complexImage, FlipMode.XY); // -1 Cv2.PutText(complexImage, watermark, point, HersheyFonts.HersheyComplex, 1.5, scalar, 3, LineTypes.Link8, false); Cv2.Flip(complexImage, complexImage, FlipMode.XY); // -1 Mat invDFT = new Mat(); Cv2.Idft(complexImage, invDFT, DftFlags.Scale | DftFlags.RealOutput); invDFT.ConvertTo(invDFT, MatType.CV_8U); allPlanes[0] = invDFT; Cv2.Merge(allPlanes.ToArray(), invDFT); Cv2.ImWrite(outputPath, invDFT); } public static void Extract(string targetImage, string outputWatermark) { Mat image = Cv2.ImRead(targetImage); List allPlanes = new List(); Cv2.Split(image, out Mat[] splitPlanes); allPlanes.AddRange(splitPlanes); Mat processImage = allPlanes[0]; processImage.ConvertTo(processImage, MatType.CV_32F); List planes = new List(); planes.Add(processImage); planes.Add(Mat.Zeros(processImage.Size(), MatType.CV_32F)); Mat complexImage = new Mat(); Cv2.Merge(planes.ToArray(), complexImage); Cv2.Dft(complexImage, complexImage); List newPlanes = new List(); Mat mag = new Mat(); Cv2.Split(complexImage, out Mat[] splitComplex); newPlanes.AddRange(splitComplex); Cv2.Magnitude(newPlanes[0], newPlanes[1], mag); Cv2.Add(Mat.Ones(mag.Size(), MatType.CV_32F), mag, mag); Cv2.Log(mag, mag); // Crop 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); mag.ConvertTo(mag, MatType.CV_8UC1); Cv2.Normalize(mag, mag, 0, 255, NormTypes.MinMax, (int)MatType.CV_8UC1); Cv2.ImWrite(outputWatermark, mag); } private static Mat OptimizeImageDimensions(Mat image) { Mat padded = new Mat(); int addPixelRows = Cv2.GetOptimalDFTSize(image.Rows); int addPixelCols = Cv2.GetOptimalDFTSize(image.Cols); Cv2.CopyMakeBorder(image, padded, 0, addPixelRows - image.Rows, 0, addPixelCols - image.Cols, BorderTypes.Constant, Scalar.All(0)); return padded; } } }