Данные пикселей изменяются после записи в файл JPEG
Я выполняю стеганографию на изображениях JPEG. я использую DCT
коэффициенты, чтобы скрыть данные. Я делаю следующие шаги:
- Читать входное изображение в
BufferedImage
- Получить блок 8 х 8 от
BufferedImage
- Применить форвард DCT, чтобы получить коэффициенты DCT
- Вставить биты сообщения в коэффициенты DCT
- Применить обратный DCT и записать блок обратно
BufferedImage
Шаги 2-5 повторяются до тех пор, пока в сообщении не останется ни одного сообщения BufferedImage
в файл JPEG с именем 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
Блок пикселей в пространстве Y после встраивания данных и применения IDCT:
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, но все еще получил ту же проблему.