public static bool GetWatermarkDctForBlock(MatrixBase<Color> block, int bitIndex, ZigZagAccessorFactory<double> zigzagAccessorFactory, Double[,] quantizationTable, ChannelType channelType, bool log = false) { var yCbCrColorBlock = block.ToYCbCr(); var yChannel = yCbCrColorBlock.GetChannel(channelType); var shiftetBlock = yChannel - 128; var dctBlockTransform = (DiscreteCosineTransform.ForwardDct8Block(shiftetBlock).CrossDivide(quantizationTable)).Round(); if (log) { _debugDecodeStringBuilder.AppendLine(dctBlockTransform.ToString()); } var accessor = zigzagAccessorFactory.Access(dctBlockTransform); var coefficient = accessor[bitIndex]; var curentElelement = (int) Math.Round(coefficient); bool isEven = curentElelement%2 == 0; return isEven; }
private static MatrixBase<Color> WatermarkDctBlock(MatrixBase<Color> block, ZigZagAccessorFactory<Double> accessorFactory, double[,] quantizationTable, bool canEncrypt, byte[] secretMessage, ref int embeddingSecretMessageBitIndex, int byteIndexForEncryption, ChannelType channelType) { if (!canEncrypt) { return block; } var byteIndex = embeddingSecretMessageBitIndex / 8; if (embeddingSecretMessageBitIndex % 8 == 0) { byteIndex = embeddingSecretMessageBitIndex / 8; _debugEncodeStringBuilder.AppendLine("Appending byte:" + (byteIndex + 1)); } var correction = 1; bool embeddCorrectly; MatrixBase<Color> ret; //#region Convert block var yCbCrColorBlock = block.ToYCbCr(); var channel = yCbCrColorBlock.GetChannel(channelType); channel = channel - 128; DoubleMatrix dctBlockTransform = null; //#endregion do { // For luminance channel yMax = 127, ymin = -128 DoubleMatrix stegoBlock; bool redo = false; var nextSecretBit = MathUtilities.GetBit(secretMessage, embeddingSecretMessageBitIndex); bool changed = false; dctBlockTransform = DiscreteCosineTransform.ForwardDct8Block(channel); dctBlockTransform = (dctBlockTransform.CrossDivide(quantizationTable)); dctBlockTransform = dctBlockTransform.Round(); var accessor = accessorFactory.Access(dctBlockTransform); var curentElelement = accessor[byteIndexForEncryption]; bool isEven = ((int) Math.Round(curentElelement))%2 == 0; double possibleValue = curentElelement; DoubleMatrix oldStegoBlock = null; do { if ((isEven && nextSecretBit) || (!isEven && !nextSecretBit)) { if (!redo) { possibleValue = isEven ? curentElelement - correction : curentElelement + correction; } else { possibleValue = isEven ? curentElelement + correction : curentElelement - correction; } changed = true; } accessor[byteIndexForEncryption] = possibleValue; stegoBlock = dctBlockTransform.CrossProduct(quantizationTable); stegoBlock = DiscreteCosineTransform.InverseDct8Block(stegoBlock); if (!redo && changed) { for (var i = 0; i < 8; i++) { for (var j = 0; j < 8; j++) { var value = Math.Round(stegoBlock[i, j]); if (value < -128 || value > 127) { redo = true; oldStegoBlock = stegoBlock; break; } } if (redo) { break; } } } else { if (changed) { var maximumValue = oldStegoBlock.MaximumValue; var minimumValue = oldStegoBlock.MinimumValue; var currentMaximumValue = stegoBlock.MaximumValue; var currentMinimumValue = stegoBlock.MinimumValue; if (currentMinimumValue < -128 || currentMaximumValue > 127) { if ((currentMinimumValue < -128 && minimumValue > currentMinimumValue) || (currentMaximumValue > 127 && maximumValue < currentMaximumValue)) { stegoBlock = oldStegoBlock; } } } redo = false; } } while (redo); stegoBlock = stegoBlock + 128; // var tmpyCbCrColorBlock = yCbCrColorBlock.Copy; tmpyCbCrColorBlock.UpdateChannel(channelType, stegoBlock); ret = tmpyCbCrColorBlock.ToRgb(); #region Verification (check if embeddding is correctly (rounding problems might occurs)) if (changed) { embeddCorrectly = !GetWatermarkDctForBlock(ret, byteIndexForEncryption, accessorFactory, quantizationTable, channelType) == nextSecretBit; if (!embeddCorrectly) { correction = correction + 2; } else { correction = 1; } } else { embeddCorrectly = true; correction = 1; } #endregion } while (!embeddCorrectly); _debugEncodeStringBuilder.AppendLine(dctBlockTransform.ToString()); embeddingSecretMessageBitIndex++; return ret; }