141 lines
4.9 KiB
C#
141 lines
4.9 KiB
C#
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<Mat> allPlanes);
|
|
padded.ConvertTo(padded, MatType.CV_32F);
|
|
|
|
List<Mat> planes = new List<Mat>();
|
|
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<Mat> unused);
|
|
padded.ConvertTo(padded, MatType.CV_32F);
|
|
|
|
List<Mat> planes = new List<Mat>();
|
|
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<Mat> allPlanes)
|
|
{
|
|
allPlanes = new List<Mat>();
|
|
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<Mat> 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<Mat> newPlanes = new List<Mat>();
|
|
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);
|
|
}
|
|
}
|
|
}
|