我正在对 JPEG 图像执行隐写术。我正在使用DCT
系数来隐藏数据。我执行以下步骤:
- 将输入图像读入
BufferedImage
- 从
BufferedImage
- 应用正向 DCT 以获得 DCT 系数
- 在 DCT 系数中嵌入消息位
- 应用逆 DCT 并将块写回
BufferedImage
重复步骤 2-5 直到没有剩余消息位,此时我写入BufferedImage
名为output.jpg
. 值得一提的是,我并不适用DCT
于整个图像,而仅适用于我嵌入消息位的块。我将这个源用于 DCT,这个源用于隐写术
问题:我最终ouput.jpg
得到表示像素数据发生巨大变化的随机线条。以下是图像写入代码:
static int[][] DCT_coefficients = new int[8][8];
static double[][] DCT_matrix = new double[8][8];
static int[][] Dequantized_m = new int[8][8];
static int[][] YBlock = new int[8][8];
static double[][] resultant = new double[8][8];
static int[][] red = new int[8][8];
static int[][] green = new int[8][8];
static int[][] blue = new int[8][8];
static int[][] Y = new int[8][8];
static int[][] Cb = new int[8][8];
static int[][] Cr = new int[8][8];
static int x = 0, y = 0;
public static void main(String args[]) {
//I retrieve a pixel block from **BufferedImage** and convert it to YCbCr
double temp1, temp2, temp3, temp4;
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
Color c = new Color(input_image.getRGB(y, x));
red = c.getRed();
green = c.getGreen();
blue = c.getBlue();
YCbCr = YCrCb_conversion(red, green, blue);
YBlock[i][j] = YCbCr[0];
Cb[i][j] = YCbCr[1];
Cr[i][j] = YCbCr[2];
y++;
}
x++;
}
//calculating DCT matrix
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
if (i == 0) {
DCT_matrix[i][j] = 1 / Math.sqrt(8.0);
}
if (i > 0) {
temp1 = 0.5;
Apfloat Atemp1 = new Apfloat(temp1, 15);
temp3 = ((2 * j) + 1) * i * java.lang.Math.PI;
temp2 = temp3 / 16;
Apfloat Atemp2 = new Apfloat(temp2, 15);
temp4 = Math.cos(java.lang.Math.toRadians(temp2));
Apfloat Atemp4 = ApfloatMath.cos(Atemp2);
Apfloat Atemp = Atemp4.multiply(Atemp1);
DCT_matrix[i][j] = Atemp.doubleValue();
}
}
}
//Leveling off Yblock
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
leveledoff[i][j] = pixel_block[i][j] - 128;
}
}
// multiplying DCT matrix and leveled off YBlock
resultant = matrix_multiply(DCT_matrix, leveledoff);
// taking transpose of DCT matrix
transpose = obj.transpose(DCT_matrix);
//multiplying transpose with resultant to get DCT coefficient block
DCT_Coefficients = matrix_multiply(resultant, trans);
//quantizing DCT coefficients using 50 % quantization matrix
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
quantized_matrix[i][j] = (int) Math.round(DCT_Coefficients[i][j] / quantzation_matrix[i][j]);
}
}
//Applying zigzag encoding
ZigZag_encoded = zigzag.ZigzagEncode(quantised_m);
//Encode data
ZigZag_encoded = embed_data(ZigZag_encoded, data_buffer);
//start IDCT
IDCT(ZigZag_Encoded);
//end main
}
//Method definitions
//Method to change LSB of integer value
public static int changeBit(int pixel, char bit) {
String s = Integer.toBinaryString(pixel);
char[] c = s.toCharArray();
c[c.length - 1] = bit;
// converting binary to integer
String n = "";
for (int y = 0; y < c.length; y++) {
n += "" + c[y];
}
int j = 0;
for (int i = 0; i < n.length(); i++) {
if (n.charAt(i) == '1') {
j = j + pow(2, n.length() - 1 - i);
}
}
return j;
}
// method to embed data
public static int[] embed_data(int encoded[], char buffer[]) {
for (int i = 0; i < buffer.length; i++) {
int newVal = changeBit(encoded[i], buffer[i]);
encoded[i] = newVal;
}
return encoded;
}
// Method to perform IDCT
public static void IDCT(ZigZag_encoded) {
//converting 1D zigzag array to 2D array
quantised_matrix = Zigzag_Decode(ZigZag_encoded);
//Dequantizing
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
Dequantized[i][j] = quantised_matrix[i][j] * quantzation_matrix[i][j];
}
}
// multiplying transpose of DCT matrix with Dequantized matrix
resultant = matrix_multiply(transpose, Dequantized);
//multiplying resultant with DCT matrix
resultant = matrix_multiply(resultant, dct_mat);
//adding 128 to each resultant entry and rounding off
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
block[i][j] = (int) Math.round(resultant[i][j] + 128);
}
}
//Converting Yblock to RGB block
YCrCbToRGB(block, Cb, Cr);
//writing RGB block to BufferedImage
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
newcolor = new Color(red[i][j], green[i][j], blue[i][j]);
input_image.setRGB(y, x, newcolor.getRGB());
y++;
}
x++;
}
}
//method to convert RGB block to YCbCr
public int[] YCrCb_conversion(int red, int green, int blue) {
int[] YCbCr = new int[3];
//Y = 0.257R+ 0.504G + 0.098B + 16
YCbCr[0] = (int)(0.257 * red + 0.504 * green + 0.098 * blue) + 16;
//Cb=–0.148R – 0.291G+ 0.439B + 128
YCbCr[1] = (int)((-0.148 * red - 0.291 * green + 0.439 * blue) + 128);
//Cr = 0.439R – 0.368G – 0.071B + 128
YCbCr[2] = (int)((0.539 * red - 0.368 * green - 0.071 * blue) + 128);
return value
// index 0 holds values of Y 1 holds Cb values and 2 holds Cr vlaues
return YCbCr;
}
//Method to convert YCbCr block to RGB block
public static void YCrCbToRGB(int y[][], int Cb[][], int Cr[][]) {
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
//R = 1.164(Y – 16) + 1.596(Cr – 128)
red[i][j] = (int)(1.164 * (y[i][j] - 16) + (1.596 * (Cr[i][j] - 128)));
//G = 1.164(Y – 16) – 0.813(Cr – 128) – 0.391(Cb – 128)
green[i][j] = (int)(1.164 * (y[i][j] - 16) - (0.813 * (Cr[i][j] - 128)) - (0.391 * (Cb[i][j] - 128)));
//B = 1.164(Y – 16) + 2.018(Cb – 128)
blue[i][j] = (int)(1.164 * (y[i][j] - 16) + (2.018 * (Cb[i][j] - 128)));
}
}
}
样本输入和输出:
pixel block in Y space as input to DCT
223 224 226 227 229 229 230 230
226 227 227 227 228 229 229 230
228 228 228 228 228 229 230 231
228 228 228 228 229 231 233 234
227 228 229 230 231 233 234 234
226 227 229 230 232 233 233 233
227 228 230 232 232 231 229 228
228 230 232 234 232 229 226 223
量化后和嵌入数据前的 DCT 系数矩阵:
51 -1 0 0 0 0 0 0
-1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
嵌入数据后的量化 DCT 系数:
50 -1 0 1 0 0 0 0
-1 0 1 0 0 0 0 0
1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
嵌入数据并应用 IDCT 后,Y 空间中的像素块:
232 227 223 223 227 231 232 231
230 226 222 223 226 230 230 229
228 224 221 222 226 229 229 227
226 223 221 223 227 229 228 225
226 224 223 225 229 230 228 225
227 225 225 228 232 233 230 226
228 227 228 231 235 236 232 228
230 229 230 234 237 238 233 229
我认为这是由于 JPEG 的有损性质,所以我尝试了 PNG,但仍然遇到同样的问题。