我正在研究频域隐写术。我的任务是使用FFT隐藏JPEG图片中的文本信息。我用 C# 编写了一些代码,用于拍摄图片,为 FFT 算法做好准备,并使用 FFT 计算其频域。输入图片为,FFT算法的结果为。然后此代码获取文本消息,从图片中获取复数值并更改该复数值的 LeastSignificantBit (LSB)。之后我们修改了中的频域,正如你所看到的,有一条从中心到右加密的消息。但是当我尝试在修改后的图片中使用 IFFT 时,其输出只是一个。很明显,我在改变频域的过程中以某种方式损坏了图像。这段代码可能有什么问题?
带有详细注释的代码如下:
// Uploading image
var image = AForge.Imaging.Image.FromFile("input.jpg");
// Find the nearest power of 2 dimensions
int width = (int)Math.Pow(2, Math.Ceiling(Math.Log(image.Width, 2)));
int height = (int)Math.Pow(2, Math.Ceiling(Math.Log(image.Height, 2)));
// Resize the image to the nearest power of 2 dimensions
Bitmap resizedImage = new Bitmap(image, width, height);
// Converting image to grayscale
Grayscale filter = new Grayscale(0.2125, 0.7154, 0.0721);
Bitmap grayImage = filter.Apply(resizedImage);
// Converting image to the ComplexImage
ComplexImage complexImage = ComplexImage.FromBitmap(grayImage);
// Applying FFT
complexImage.ForwardFourierTransform();
// Saving result of FFT
complexImage.ToBitmap().Save("fourier.jpg");
// -------------------------------------------------------------------------
// Converting text message to binary
string textMessage = "Hello world";
byte[] messageBytes = Encoding.Unicode.GetBytes(textMessage);
BitArray messageBits = new BitArray(messageBytes);
// Embedding text bits into the frequency domain
int bitIndex = 0;
for (int y = complexImage.Height / 2; y < complexImage.Height; y++)
{
for (int x = complexImage.Width / 2; x < complexImage.Width; x++)
{
if (bitIndex >= messageBits.Length)
{
break;
}
// Getting complex value of frequency
Complex complexValue = complexImage.Data[y, x];
// Replacing the LSB of the real and imaginary parts with a bit from the message
complexValue.Re = SetLeastSignificantBit(complexValue.Re, messageBits[bitIndex++]);
complexValue.Im = SetLeastSignificantBit(complexValue.Im, messageBits[bitIndex++]);
// Applying new value
complexImage.Data[y, x] = complexValue;
}
}
// Setting LSB
static float SetLeastSignificantBit(double value, bool bit)
{
int intValue = BitConverter.ToInt32(BitConverter.GetBytes(value), 0);
intValue = bit ? (intValue | 1) : (intValue & ~1);
return BitConverter.ToSingle(BitConverter.GetBytes(intValue), 0);
}
// -------------------------------------------------------------------------
complexImage.ToBitmap().Save("fourier222.jpg");
// Applying IFFT
complexImage.BackwardFourierTransform();
complexImage.ToBitmap().Save("output.jpg");
经过一些研究,我发现最好不要使用LSB方法,而是改变频域的“空”值并添加或减去频率数据的实部。 “空”值是从频率数据中获取的
ComplexImage[x, y]
的实际值,等于零。在此代码中,我使用左上角来查找“空”值。此外,在穿过频域时,最好避免频域中间,因为它可能会导致麻烦和不正确的编码数据。一些加密代码示例:
public static ComplexImage EmbedData(ComplexImage freqDomain, byte[] data)
{
ComplexImage modifiedFreqDomain = freqDomain;
int xCoordinate = 0;
int yCoordinate = 0;
if (data.Length * 8 > modifiedFreqDomain.Data.Length)
{
throw new Exception("Data too large to embed into the frequency domain");
}
int bitIndex = 0;
for (int k = 0; k < data.Length; k++)
{
for (int i = 0; i < 8; i++)
{
int bit = (data[k] >> i) & 1;
double realPart = modifiedFreqDomain.Data[xCoordinate, yCoordinate].Re;
if (bit == 1)
{
realPart += 0.00025;
}
else
{
realPart -= 0.00025;
}
modifiedFreqDomain.Data[xCoordinate, yCoordinate] = new Complex(realPart, modifiedFreqDomain.Data[xCoordinate, yCoordinate].Im);
yCoordinate += 1;
if (yCoordinate >= freqDomain.Width / 2.5)
{
yCoordinate = 0;
xCoordinate += 1;
}
bitIndex++;
}
}
return modifiedFreqDomain;
}
当我使用此代码进行加密时,图像可能会略有变化,但这并不重要。此外,该算法应该检查“非空”值,因为我们无法从中获取数据。所以有一些方法可以改进这个方法,但基本上是有效的。