using System.Collections.Generic; using OpenCvSharp; namespace Com.Lmc.ShuiYin { public class ImgWatermarkUtil { // Changed from static fields to local to avoid thread safety issues, // but to match structure I will keep them but re-initialize them or just use locals if possible. // The Java code reused static lists which is buggy. I will use locals. public static Mat AddImageWatermarkWithText(Mat image, string watermarkText) { Mat complexImage = new Mat(); Mat padded = SplitSrc(image, out List allPlanes); padded.ConvertTo(padded, MatType.CV_32F); List planes = new List(); planes.Add(padded); planes.Add(Mat.Zeros(padded.Size(), MatType.CV_32F)); Cv2.Merge(planes.ToArray(), complexImage); Cv2.Dft(complexImage, complexImage); Scalar scalar = new Scalar(0, 0, 0); Point point = new Point(40, 40); Cv2.PutText(complexImage, watermarkText, point, HersheyFonts.HersheyDuplex, 1.0, scalar); Cv2.Flip(complexImage, complexImage, FlipMode.XY); Cv2.PutText(complexImage, watermarkText, point, HersheyFonts.HersheyDuplex, 1.0, scalar); Cv2.Flip(complexImage, complexImage, FlipMode.XY); return AntitransformImage(complexImage, allPlanes); } public static Mat GetImageWatermarkWithText(Mat image) { Mat complexImage = new Mat(); Mat padded = SplitSrc(image, out List unused); padded.ConvertTo(padded, MatType.CV_32F); List planes = new List(); planes.Add(padded); planes.Add(Mat.Zeros(padded.Size(), MatType.CV_32F)); Cv2.Merge(planes.ToArray(), complexImage); Cv2.Dft(complexImage, complexImage); return CreateOptimizedMagnitude(complexImage); } private static Mat SplitSrc(Mat mat, out List allPlanes) { allPlanes = new List(); mat = OptimizeImageDim(mat); Cv2.Split(mat, out Mat[] splitPlanes); allPlanes.AddRange(splitPlanes); Mat padded = new Mat(); if (allPlanes.Count > 1) { padded = allPlanes[0]; } else { padded = mat; } return padded; } private static Mat AntitransformImage(Mat complexImage, List allPlanes) { Mat invDFT = new Mat(); Cv2.Idft(complexImage, invDFT, DftFlags.Scale | DftFlags.RealOutput); Mat restoredImage = new Mat(); invDFT.ConvertTo(restoredImage, MatType.CV_8U); if (allPlanes.Count == 0) { allPlanes.Add(restoredImage); } else { allPlanes[0] = restoredImage; } Mat lastImage = new Mat(); Cv2.Merge(allPlanes.ToArray(), lastImage); return lastImage; } private static Mat OptimizeImageDim(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; } private static Mat CreateOptimizedMagnitude(Mat complexImage) { List newPlanes = new List(); Mat mag = new Mat(); Cv2.Split(complexImage, out Mat[] splitPlanes); newPlanes.AddRange(splitPlanes); Cv2.Magnitude(newPlanes[0], newPlanes[1], mag); Cv2.Add(Mat.Ones(mag.Size(), MatType.CV_32F), mag, mag); Cv2.Log(mag, mag); ShiftDFT(mag); mag.ConvertTo(mag, MatType.CV_8UC1); Cv2.Normalize(mag, mag, 0, 255, NormTypes.MinMax, (int)MatType.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); } } }