Java 写入JPEG文件后,像素数据会发生更改
我正在对JPEG图像执行隐写术。我正在使用Java 写入JPEG文件后,像素数据会发生更改,java,javax.imageio,steganography,dct,density-independent-pixel,Java,Javax.imageio,Steganography,Dct,Density Independent Pixel,我正在对JPEG图像执行隐写术。我正在使用DCT系数来隐藏数据。我执行以下步骤: 将输入图像读入buffereImage 从buffereImage 应用前向DCT得到DCT系数 在DCT系数中嵌入消息位 应用逆DCT并将块写回buffereImage 重复步骤2-5,直到没有消息位剩余,此时我将buffereImage写入名为output.jpg的JPEG文件。值得一提的是,我没有对整个图像应用DCT,而是只对嵌入消息位的块应用。我使用源代码进行DCT和隐写术 问题:我在output.jpg上
DCT
系数来隐藏数据。我执行以下步骤:
buffereImage
buffereImage
buffereImage
buffereImage
写入名为output.jpg
的JPEG文件。值得一提的是,我没有对整个图像应用DCT
,而是只对嵌入消息位的块应用。我使用源代码进行DCT和隐写术
问题:我在output.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)));
}
}
}
量化后嵌入数据前的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
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
嵌入数据后的量化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
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,但仍然遇到同样的问题。您可能误解了JPEG隐写术是什么。它不是DCT->embed secret->IDCT,而是遵循整个jpeg编码过程,并在中间步骤修改系数,如和。至于输出图像中的点,这可能是您如何应用步骤2-5的结果,您没有向我们展示代码。我没有执行在中提到的步骤4和步骤8。我认为哈夫曼编码不是必需的,所以我在第7步嵌入数据后直接转到IDCT。我对像素值重新居中的代码很长也不清楚,这就是我没有分享的原因。每个步骤的代码片段是否有效。向我们展示复制您的问题所需的代码。在您的例子中,应该从64个硬编码像素开始,DCT,手动修改一些系数和IDCT。如果您是基于出版物或其他内容的算法,请与我们共享源代码。您可能误解了jpeg隐写术是什么。它不是DCT->embed secret->IDCT,而是遵循整个jpeg编码过程,并在中间步骤修改系数,如和。至于输出图像中的点,这可能是您如何应用步骤2-5的结果,您没有向我们展示代码。我没有执行在中提到的步骤4和步骤8。我认为哈夫曼编码不是必需的,所以我在第7步嵌入数据后直接转到IDCT。我对像素值重新居中的代码很长也不清楚,这就是我没有分享的原因。每个步骤的代码片段是否有效。向我们展示复制您的问题所需的代码。在您的例子中,应该从64个硬编码像素开始,DCT,手动修改一些系数和IDCT。如果您是基于出版物或其他内容的算法,请与我们共享源代码。