public DwtDctSvdAlgorithm() { _imageArrayConverter = new ImageArrayConverter(); _stringArrayConverter = new StringToArrayConverter(); _matrixService = new MatrixService(); _dwtHandler = new DwtPrecisionAlgorithm(); _svdHandler = new SvdAlgorithm(); _iterations = 1; _quarter = QuarterSymbol.HH; _channel = EmbeddingChanel.R; }
private int[,] GetPixelValues(Bitmap image, EmbeddingChanel embeddingChannel) { int[,] values = new int[image.Height, image.Width]; for (int y = 0; y < image.Height; y++) { for (int x = 0; x < image.Width; x++) { values[y, x] = getValueOfRgbChannel(image.GetPixel(x, y), embeddingChannel); } } return(values); }
private void SetChannelFromConfiguration(DwtSvdConfiguration config) { if (config.EmbeddingChanels.Contains(EmbeddingChanel.R)) { _channel = EmbeddingChanel.R; } if (config.EmbeddingChanels.Contains(EmbeddingChanel.G)) { _channel = EmbeddingChanel.G; } if (config.EmbeddingChanels.Contains(EmbeddingChanel.B)) { _channel = EmbeddingChanel.B; } }
private byte getValueOfRgbChannel(Color pixel, EmbeddingChanel rgbChannel) { switch (rgbChannel) { case EmbeddingChanel.R: return(pixel.R); case EmbeddingChanel.G: return(pixel.G); case EmbeddingChanel.B: return(pixel.B); default: throw new Exception("Assertion error! Illegal RGB channel!"); } }
public Tuple <Bitmap, string> TryDecodeImageForChannel(Bitmap inputImage, EmbeddingChanel embeddingChanel, DifferenceExpansionBruteForceConfiguration bruteForceConfiguration) { foreach (Direction direction in Enum.GetValues(typeof(Direction))) { if (bruteForceConfiguration.EmbeddingDirections.Contains(direction)) { // For given RGB channel algorith tries to decode payload with each embedding direction allowed in configuration Tuple <Bitmap, string> imageAndPayload = TryDecodeImageForDirectionAndChannel(inputImage, Direction.Horizontal, embeddingChanel); if (isDecodingSuccessfull(imageAndPayload)) { // If decoding with given embedding channel and direction was successfull then image and payload chunk is returned // If there was no success other embedding direction for given channel is used return(imageAndPayload); } } } return(null); }
private void EncodePayloadIntoImage(Bitmap image, string payload, Direction embeddingDirection, int threeshold, EmbeddingChanel embeddingChanel) { // Calculation of averages for pixel pairs l = (x + y) / 2 // Depending on embedding direction below arrays has size [image.Height, image.Width / 2] or [image.Height / 2, image.Width] int[,] averages = Calculate(image, CalculateAverage, embeddingDirection, embeddingChanel); // Calcualtion of differences for pixel pairs h = x - y int[,] differences = Calculate(image, CalculateDifference, embeddingDirection, embeddingChanel); // Preparing array for locality map containting 1 if pixel pair belongs to set EZ and 0 if it belongs to set EN1 int[,] localityMap = GetEmptyArrayAdjustedToImageSize(image, embeddingDirection); // Indicates to which encoding set pixel pair belongs EncodingSetName[,] setsIds = new EncodingSetName[localityMap.GetLength(0), localityMap.GetLength(1)]; int EZSize = 0; int EN1Size = 0; List <int> EN2AndCN = new List <int>(); // Divison of pixel pairs into 5 encoding sets (EZ, EN1, EN2, CN, NC) and construction of locality map. // We also store difference values for pixel pairs belonging to EN2 and CN. for (int i = 0; i < setsIds.GetLength(0); i++) { for (int j = 0; j < setsIds.GetLength(1); j++) { if (IsExpandable(i, j, differences, averages)) { if (differences[i, j] == 0 || differences[i, j] == -1) { // Pixel pairs with expandable differences with values equal 0 or -1 are // assigned to EZ - expandable zeros set localityMap[i, j] = 1; EZSize++; setsIds[i, j] = EncodingSetName.EZ; } else if (Math.Abs(differences[i, j]) <= threeshold) { // Pixel pairs with expandable differences with values other than 0 or -1 // but with abs less than configured threeshold are assigned to EN1 set localityMap[i, j] = 1; EN1Size++; setsIds[i, j] = EncodingSetName.EN1; } else { // Pixel pairs with expandable differences with values other than 0 or -1 // and with abs greater than configured threeshold are assigned to EN2 set EN2AndCN.Add(differences[i, j]); localityMap[i, j] = 0; setsIds[i, j] = EncodingSetName.EN2; } } else if (IsChangeable(i, j, differences, averages)) { // Pixel pairs with non-expandable but changable differences are assigned to CN set EN2AndCN.Add(differences[i, j]); localityMap[i, j] = 0; setsIds[i, j] = EncodingSetName.CN; } else { // Non-expandable and non-changeable pixel pairs are assigned to NC set localityMap[i, j] = 0; setsIds[i, j] = EncodingSetName.NC; } } } // For convinience of performing operations localityMap is hold as int array, but their values are // always 0 or 1 so convert int array to stream of last signifacant bits and divide those bits into bytes // so after operation one byte holds values of 8 subsequent LSBs List <byte> localityVector = GetLeastSignificatBits(ConvertToList(localityMap)); // differnece with values -2 and 1 can be restored on decoding and there is no need to save them List <int> filteredEN2AndCN = EN2AndCN.Where(x => x != -2 && x != 1).ToList(); // We obtain lsb of differences of pixel pairs from set EN2 and CN List <byte> LSBs = GetLeastSignificatBits(filteredEN2AndCN); int embeddingCapacity = EZSize + EN1Size + EN2AndCN.Count; // Calculation of locality map bits stream size byte[] localityVectorSize = BitConverter.GetBytes((uint)localityVector.Count); // Calculation of bit stream size for original LSBs of differences for pixel pairs from EN2 and CN byte[] LSBsSize = BitConverter.GetBytes((uint)LSBs.Count); // Calculation of payload size byte[] payloadSize = BitConverter.GetBytes(payload.Length); // Stroing information about sizes in header, this informations will be retrived on decoding byte[] header = ConcatArrays(localityVectorSize, LSBsSize, payloadSize); // Bits of locality map, LSBs and payload represented as byte array byte[] data = ConcatArrays(localityVector.ToArray(), LSBs.ToArray(), Encoding.ASCII.GetBytes(payload)); // Compresion of data with run length encoding byte[] compressedData = RLE <byte> .Encode(new List <byte>(data)).ToArray(); // Non-compressed header bits are added at the begining of embedding stream byte[] embeddingStream = ConcatArrays(header, compressedData); // For convenience array of bytes (where each byte contains 8 subsequent LSBs) is converted to array of // bool, where each value represents LSB bool[] bits = embeddingStream.SelectMany(GetBits).ToArray(); // Calculation of new difference values - data embedding int bitNumber = 0; for (int p = 0; p < setsIds.GetLength(0) && bitNumber < bits.Length; p++) { for (int q = 0; q < setsIds.GetLength(1) && bitNumber < bits.Length; q++) { if (setsIds[p, q] == EncodingSetName.EZ || setsIds[p, q] == EncodingSetName.EN1) { differences[p, q] = 2 * differences[p, q] + GetIntValue(bits[bitNumber]); bitNumber++; } else if (setsIds[p, q] == EncodingSetName.EN2 || setsIds[p, q] == EncodingSetName.CN) { differences[p, q] = 2 * DivideAndFloor(differences[p, q], 2) + GetIntValue(bits[bitNumber]); bitNumber++; } } } // Recalculation of pixel values based on new differences values RecalculateImagePixels(image, averages, differences, embeddingDirection, embeddingChanel); }
public Tuple <Bitmap, string> TryDecodeImageForDirectionAndChannel(Bitmap inputImage, Direction embeddingDirection, EmbeddingChanel embeddingChannel) { Bitmap image = new Bitmap(inputImage); try { // If no error occurs then decoding is successfull and image and payload chunk is returned return(new Tuple <Bitmap, string>(image, DecodeImage(image, embeddingDirection, embeddingChannel))); } catch { } // In case of failure exception is supressed and null value (failure indicator) is returned return(null); }
private string DecodeImage(Bitmap image, Direction embeddingDirection, EmbeddingChanel embeddingChannel) { // Calculation of averages for pixel pairs l = (x + y) / 2 // Depending on embedding direction below arrays has size [image.Height, image.Width / 2] or [image.Height / 2, image.Width] int[,] averages = Calculate(image, CalculateAverage, embeddingDirection, embeddingChannel); // Calcualtion of differences for pixel pairs h = x - y int[,] differences = Calculate(image, CalculateDifference, embeddingDirection, embeddingChannel); // Preparing array for locality map containting 1 if pixel pair belongs to set EZ and 0 if it belongs to set EN1 int[,] localityMap = GetEmptyArrayAdjustedToImageSize(image, embeddingDirection); // Indicates to which of two decoding set pixel pair belongs DecodingSetName[,] setsIds = new DecodingSetName[localityMap.GetLength(0), localityMap.GetLength(1)]; List <int> changeableDifferences = new List <int>(); // Pixel pairs are dividen into two sets - pixel pairs with changeable differences (CH) // and non-changeable differences (NC). Changeable differences contains data embedded during // encoding (it corresponds to encoding sets EZ, EN1, EN2, CN) for (int i = 0; i < setsIds.GetLength(0); i++) { for (int j = 0; j < setsIds.GetLength(1); j++) { if (IsChangeable(i, j, differences, averages)) { // Pixel pairs with changeable differences are assigned to CH set and // its difference value is collected changeableDifferences.Add(differences[i, j]); setsIds[i, j] = DecodingSetName.CH; } else { // Pixel pairs with non-changeable differences are assigned to NC set setsIds[i, j] = DecodingSetName.NC; } } } // Changeable differences are converted to stream of LSBs represented as byte list // each byte holds 8 subsequent LSBs. This list contains data embedded during encoding. List <byte> LSBs = GetLeastSignificatBits(changeableDifferences); // At the beginging of data there is header with sizes of locality map // oryginal LSBs and payload byte[] localityVectorSizeBytes = LSBs.GetRange(0, 4).ToArray(); byte[] originalLSBsSizeBytes = LSBs.GetRange(4, 4).ToArray(); byte[] payloadSizeBytes = LSBs.GetRange(8, 4).ToArray(); // locality map, original LSBs, and payload are compressed and placed 12 bits after header byte[] compressedData = LSBs.GetRange(12, LSBs.Count - 12).ToArray(); // bytes are interpreted as int values representing size int localityVectorSize = BitConverter.ToInt32(localityVectorSizeBytes, 0); int originalLSBsSize = BitConverter.ToInt32(originalLSBsSizeBytes, 0); int payloadSize = BitConverter.ToInt32(payloadSizeBytes, 0); // to retrieve locality map, original LSBs and payload we perform decompression byte[] originalData = RLE <byte> .Decode(compressedData).ToArray(); // after decporession original data is dividen into locality map, orginal LSBs and payload byte[] localityVector = new List <byte>(originalData).GetRange(0, localityVectorSize).ToArray(); byte[] originalLSBsVector = new List <byte>(originalData).GetRange(localityVectorSize, originalLSBsSize).ToArray(); byte[] payload = new List <byte>(originalData).GetRange(localityVectorSize + originalLSBsSize, payloadSize).ToArray(); // For convenience locality map, original LSBs and paload bits are represented as bool // conversion from byte array (each element containing 8 subsequent LSBs) is performed bool[] localityVectorBits = new List <byte>(localityVector).SelectMany(GetBits).ToArray(); bool[] originalLSBsVectorBits = new List <byte>(originalLSBsVector).SelectMany(GetBits).ToArray(); bool[] payloadBits = new List <byte>(payload).SelectMany(GetBits).ToArray(); // Calculation of original differences values int bitNumber = 0; for (int i = 0; i < differences.GetLength(0); i++) { for (int j = 0; j < differences.GetLength(1); j++) { if (setsIds[i, j] == DecodingSetName.CH) { if (localityVectorBits[i * differences.GetLength(1) + j]) { differences[i, j] = DivideAndFloor(differences[i, j], 2); } else { if (differences[i, j] == 0 || differences[i, j] == 1) { differences[i, j] = 1; } else if (differences[i, j] == -2 || differences[i, j] == -1) { differences[i, j] = -2; } else { differences[i, j] = 2 * DivideAndFloor(differences[i, j], 2) + GetIntValue(originalLSBsVectorBits[bitNumber]); bitNumber++; } } } } } // Recalculation of pixel values based on new values of differences RecalculateImagePixels(image, averages, differences, embeddingDirection, embeddingChannel); return(Encoding.ASCII.GetString(payload)); }
private void RecalculatePixelsVertically(Bitmap image, int[,] averages, int[,] newDifferences, EmbeddingChanel embeddingChannel) { for (int y = 0; y < image.Height / 2; y++) { for (int x = 0; x < image.Width; x++) { Color currentPixelX = image.GetPixel(x, 2 * y); int newX = averages[y, x] + DivideAndFloor(newDifferences[y, x] + 1, 2); image.SetPixel(x, 2 * y, getPixelWithNewValueForSpecifiedRgbChannel(currentPixelX, newX, embeddingChannel)); int newY = averages[y, x] - DivideAndFloor(newDifferences[y, x], 2); Color currentPixelY = image.GetPixel(x, 2 * y + 1); image.SetPixel(x, 2 * y + 1, getPixelWithNewValueForSpecifiedRgbChannel(currentPixelY, newY, embeddingChannel)); } } }
private Color getPixelWithNewValueForSpecifiedRgbChannel(Color oldPixel, int newValueForChannel, EmbeddingChanel embeddingChanel) { switch (embeddingChanel) { case EmbeddingChanel.R: return(Color.FromArgb(oldPixel.A, newValueForChannel, oldPixel.G, oldPixel.B)); case EmbeddingChanel.G: return(Color.FromArgb(oldPixel.A, oldPixel.R, newValueForChannel, oldPixel.B)); case EmbeddingChanel.B: return(Color.FromArgb(oldPixel.A, oldPixel.R, oldPixel.G, newValueForChannel)); default: throw new Exception("Assertion error! Illegal RGB channel!"); } }
private void RecalculateImagePixels(Bitmap image, int[,] averages, int[,] newDifferences, Direction direction, EmbeddingChanel embeddingChanel) { if (direction == Direction.Horizontal) { RecalculatePixelsHorizontally(image, averages, newDifferences, embeddingChanel); } else { RecalculatePixelsVertically(image, averages, newDifferences, embeddingChanel); } }
private int[,] CalculateVertically(Bitmap image, Func <int, int, int> operation, EmbeddingChanel embeddingChanel) { int[,] result = new int[image.Height / 2, image.Width]; for (int y = 0; y < image.Height / 2; y++) { for (int x = 0; x < image.Width; x++) { result[y, x] = operation(getValueOfRgbChannel(image.GetPixel(x, 2 * y), embeddingChanel), getValueOfRgbChannel(image.GetPixel(x, 2 * y + 1), embeddingChanel)); } } return(result); }
private int [,] CalculateHorizontally(Bitmap image, Func <int, int, int> operation, EmbeddingChanel embeddingChannel) { int[,] result = new int[image.Height, image.Width / 2]; for (int y = 0; y < image.Height; y++) { for (int x = 0; x < image.Width / 2; x++) { result[y, x] = operation(getValueOfRgbChannel(image.GetPixel(2 * x, y), embeddingChannel), getValueOfRgbChannel(image.GetPixel(2 * x + 1, y), embeddingChannel)); } } return(result); }
private int [,] Calculate(Bitmap image, Func <int, int, int> operation, Direction direction, EmbeddingChanel embeddingChanel) { if (direction == Direction.Horizontal) { return(CalculateHorizontally(image, operation, embeddingChanel)); } return(CalculateVertically(image, operation, embeddingChanel)); }
public Tuple <double[][, ], double[, ]> ExtractPayloadSVD(double[][,] watermarkedMatrix, EmbeddingChanel channel)//double[][,] originalMatrix, string channel) { var decodingVector = ImportDecodingVector(); _inMemorySo = ArrayPayloadToDiagonalArray(decodingVector, decodingVector.GetLength(0), decodingVector.GetLength(0)); var newImage = watermarkedMatrix.DeepClone(); Tuple <double[][, ], double[, ]> result = null; switch (channel) { case EmbeddingChanel.R: var tempRed = ExtractPayload(watermarkedMatrix[0]); newImage[0] = tempRed.Item1; result = new Tuple <double[][, ], double[, ]>(newImage, tempRed.Item2); break; case EmbeddingChanel.G: var tempGreen = ExtractPayload(watermarkedMatrix[1]); newImage[0] = tempGreen.Item1; result = new Tuple <double[][, ], double[, ]>(newImage, tempGreen.Item2); break; case EmbeddingChanel.B: var tempBlue = ExtractPayload(watermarkedMatrix[2]); newImage[0] = tempBlue.Item1; result = new Tuple <double[][, ], double[, ]>(newImage, tempBlue.Item2); break; default: Tuple <double[, ], double[, ]> temp; double[,] payload = new double[watermarkedMatrix[0].GetLength(0), watermarkedMatrix[0].GetLength(1)]; for (int k = 0; k < watermarkedMatrix.GetLength(0); k++) { temp = ExtractPayload(watermarkedMatrix[k]); newImage[k] = temp.Item1; payload = CombinePayloads(payload, temp.Item2); result = new Tuple <double[][, ], double[, ]>(newImage, payload); } break; } return(result); }
public double[][,] HidePayloadSVD(double[][,] hostMatrics, double[] payloadVector, EmbeddingChanel channel) { switch (channel) { case EmbeddingChanel.R: hostMatrics[0] = HidePayload(hostMatrics[0], payloadVector); break; case EmbeddingChanel.G: hostMatrics[1] = HidePayload(hostMatrics[1], payloadVector); break; case EmbeddingChanel.B: hostMatrics[2] = HidePayload(hostMatrics[2], payloadVector); break; default: for (int k = 0; k < hostMatrics.Length; k++) { HidePayload(hostMatrics[k], payloadVector); } break; } return(hostMatrics); }