private void GenerateWatermarkDiff() { double[,] gray = new double[DiffWidth, DiffHeight]; for (int i = 0; i < DiffWidth; i++) { for (int j = 0; j < DiffHeight; j++) { gray[i, j] = 0; } } var rgbData = new RgbData(gray); var yuv = rgbData.ToYuv(); EmbedWatermark(yuv.U); var rgb = yuv.ToRgb(); double[,] red = new double[DiffWidth, DiffHeight]; double[,] green = new double[DiffWidth, DiffHeight]; double[,] blue = new double[DiffWidth, DiffHeight]; for (int i = 0; i < DiffWidth; i++) { for (int j = 0; j < DiffHeight; j++) { red[i, j] = 128 - rgb.R[i, j]; green[i, j] = 128 - rgb.G[i, j]; blue[i, j] = 128 - rgb.B[i, j]; } } _watermarkDiff = _imageHelper.SavePixels(new RgbData(red, green, blue)); }
public byte[] SavePixels(RgbData data) { var width = data.R.GetUpperBound(0) + 1; var height = data.R.GetUpperBound(1) + 1; var pixelSize = PixelFormats.Bgr32.BitsPerPixel / 8; byte[] pixels = new byte[width * pixelSize * height]; Parallel.For(0, height, h => { var hPos = h * width * pixelSize; for (int w = 0; w < width; w++) { var i = hPos + (w * pixelSize); pixels[i] = ToByte(data.B[w, h]); pixels[i + 1] = ToByte(data.G[w, h]); pixels[i + 2] = ToByte(data.R[w, h]); } }); var frame = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgr32, BitmapPalettes.WebPalette); frame.WritePixels(new Int32Rect(0, 0, width, height), pixels, width * pixelSize, 0); using (var encoderMemoryStream = new MemoryStream()) { var encoder = new JpegBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(frame)); encoder.Save(encoderMemoryStream); return(encoderMemoryStream.ToArray()); } }
/// <summary> /// Creates a new watermarking class. /// <para>This class caches some watermark data, so it's more efficient to keep an instance rather than create a new one for every embed operation.</para> /// <para>Defaults clipping sizes are 1024x768, 911x683, 832x624, 800x600, 744x558, 700x525, 640x480, 600x450, 568x426, 508x373, 480x360, 448x336, 400x300, 360x270, 333x250.</para> /// </summary> /// <param name="watermarkBytes">32x32 watermark image</param> /// <param name="clipSupport">Whether the algorithm should support clipping</param> /// <param name="clippingWidths">Custom clipping widths</param> /// <param name="clippingHeights">Custom clipping heights</param> public Watermark(byte[] watermarkBytes, bool clipSupport = false, IEnumerable <int> clippingWidths = null, IEnumerable <int> clippingHeights = null) { _imageHelper = new ImageHelpers(clipSupport, clippingWidths, clippingHeights); _watermarkPixels = _imageHelper.ReadPixels(watermarkBytes); if (_watermarkPixels.Height != WatermarkSize || _watermarkPixels.Width != WatermarkSize) { throw new WatermarkException("Watermark must be 32x32 image"); } GenerateWatermarkDiff(); }
public YuvData(RgbData rgb) { Y = new double[rgb.Width, rgb.Height]; U = new double[rgb.Width, rgb.Height]; V = new double[rgb.Width, rgb.Height]; for (int i = 0; i < rgb.Width; i++) { for (int j = 0; j < rgb.Height; j++) { Y[i, j] = ColorSpaceConversion.RgbToY(rgb.R[i, j], rgb.G[i, j], rgb.B[i, j]); U[i, j] = ColorSpaceConversion.RgbToU(rgb.R[i, j], rgb.G[i, j], rgb.B[i, j]); V[i, j] = ColorSpaceConversion.RgbToV(rgb.R[i, j], rgb.G[i, j], rgb.B[i, j]); } } }
private WatermarkResult RetrieveWatermark(double[,] data) { var origWidth = data.GetUpperBound(0) + 1; var origHeight = data.GetUpperBound(1) + 1; if (DiffWidth - origWidth > 0 || DiffHeight - origHeight > 0) { var top = (DiffHeight - origHeight) / 2; var left = (DiffWidth - origWidth) / 2; var bottom = (DiffHeight - origHeight) - top; var right = (DiffWidth - origWidth) - left; data = data.Pad(left, top, right, bottom); } double[,] recoveredWatermarkData = new double[_watermarkPixels.Width, _watermarkPixels.Height]; ParallelHaar.FWT(data, 2); var subband = LL2(data); var width = subband.GetUpperBound(0) + 1; var height = subband.GetUpperBound(1) + 1; Parallel.For(0, _watermarkPixels.Height, y => { for (int x = 0; x < _watermarkPixels.Width; x++) { if (x * BlockSize + BlockSize > width) { return; } if (y * BlockSize + BlockSize > height) { return; } var block = subband.Submatrix(x * BlockSize, x * BlockSize + BlockSize - 1, y * BlockSize, y * BlockSize + BlockSize - 1); CosineTransform.DCT(block); recoveredWatermarkData[x, y] = (MidBand(block).Sum() > 0) ? 255 : 0; } }); double similiar = 0; double total = (width / 4) * (height / 4); for (int x = 0; x < _watermarkPixels.Width; x++) { for (int y = 0; y < _watermarkPixels.Height; y++) { var oldValue = _watermarkPixels.R[x, y] > 125 ? 255 : 0; if (recoveredWatermarkData[x, y] == oldValue) { similiar++; } } } var similarity = Math.Round((similiar / total) * 100); var recoveredData = new RgbData(recoveredWatermarkData); var recoveredWatermarkBytes = _imageHelper.SavePixels(recoveredData); return(new WatermarkResult(similarity, recoveredWatermarkBytes)); }