我正在尝试完成DCT隐写术项目,但出现了一些问题。有人能帮我吗?我所做的:
1( 将图像拆分为8x8像素
public BufferedImage[] getBlocksOfImage(BufferedImage image){
int width = image.getWidth();
int height = image.getHeight();
int arrayIndex = 0;
//TODO specify dynamic length
//TODO for 512x512 --> 4096 (8x8 block)
BufferedImage[] blocksOfImage = new BufferedImage[4096];
for (int i = 0; i<width; i=i+8) {
for (int j = 0; j<height; j=j+8) {
blocksOfImage[arrayIndex] = image.getSubimage(i,j,8,8);
arrayIndex++;
}
}
return blocksOfImage;
}
2( 使用计算每个块的矩阵
//get matrix of pixels (used in DCT]
public int[][] getMatrixPixels(BufferedImage image){
int[][] matrixPixels = new int[image.getWidth()][image.getHeight()];
for (int i = 0; i < matrixPixels[0].length; i++) {
for (int j = 0; j < matrixPixels.length; j++) {
matrixPixels[i][j] = image.getRGB(i, j);
}
}
return matrixPixels;
}
3( 从这个块,我得到了计算DCT矩阵使用:
public double[][] getDTCTransformMatrix(int[][] imageMatrix){
double[][] dctTransformMatrix = new double[m][n];
double ci, cj, tmpDCTValue, tmpSum;
tmpSum = 0;
//TODO simplify 4x for --> BAD
//TODO consulting
for(int i = 0; i<m; i++) {
for(int j = 0; j<n; j++) {
if (i == 0){
ci = 1 / Math.sqrt(m);
} else {
ci = Math.sqrt(2) / Math.sqrt(m);
}
if (j == 0){
cj = 1 / Math.sqrt(n);
} else {
cj = Math.sqrt(2) / Math.sqrt(m);
}
for (int i_image = 0; i_image < m; i_image++) {
for (int j_image = 0; j_image < n; j_image++) {
tmpDCTValue = imageMatrix[i_image][j_image] *
Math.cos((2 * i_image + 1) * i * Math.PI / (2 * m)) *
Math.cos((2 * j_image + 1) * j * Math.PI / (2 * n));
tmpSum += tmpDCTValue;
}
}
dctTransformMatrix[i][j] = ci * cj * tmpSum;
}
}
return dctTransformMatrix;
}
以下是我的问题:
1( 我应该向getDTCTransformMatrix((函数传递什么?现在我正在传递像素的整数值,我认为这是错误的。我看到一些例子,其中的家伙传递值从0-255,所以我应该转换成灰度图像?或者我应该对每种颜色(R、G、B(都这样做?
2( 在执行getDTCTransformMatrix((之后,我得到了double的矩阵。如何编辑双值LSB?这是一个正确的方法吗?
3( 在我将LSB更改为双值之后,我下一步该怎么办?如何确保信息将存储在图像中。
谢谢大家的回答:(
---编辑---
我已经编辑了代码,现在我将分别传递每个通道(R、G、B(,并添加了以下功能:
public int[][] getQuantiseCoefficients(double[][] DTCTransformMatrix) {
int[][] quantiseResult = new int[DTCTransformMatrix.length][DTCTransformMatrix[1].length];
int[][] quantiseMatrix = {{16, 11, 10, 16, 24, 40, 51, 61},
{12, 12, 14, 19, 26, 58, 60, 55},
{14, 13, 16, 24, 40, 57, 69, 56},
{14, 17, 22, 29, 51, 87, 80, 62},
{18, 22, 37, 56, 68, 109, 103, 77},
{24, 35, 55, 64, 81, 104, 113, 92},
{49, 64, 78, 87, 103, 121, 120, 101},
{72, 92, 95, 98, 112, 100, 103, 99}};
//TODO delete static 8
for (int i = 0; i<8; i++) {
for (int j = 0; j<8; j++) {
//Bij = round(Gij/Qij)
quantiseResult[i][j] = (int)Math.round(DTCTransformMatrix[i][j]/quantiseMatrix[i][j]);
}
}
return quantiseResult;
}
以及用于添加消息:
public ArrayList<int[][]> addMessageFirst(ArrayList<int[][]> quantiseMatrixRGB, String message) {
Utils utils = new Utils();
int bitTextShift = 7;
int byteTextShift = 0;
byte[] textByteArray = text.getBytesFromText(message);
for (int i = 0; i < textByteArray.length*8; i++) {
byte[] firstValueByte = utils.integerToByte(quantiseMatrixRGB.get(i)[0][0]);
firstValueByte[3] = (byte) ((firstValueByte[3] & 0xFE) | ((int) textByteArray[byteTextShift] >>> bitTextShift) & 1);
if (bitTextShift <= 0) {
bitTextShift = 7;
byteTextShift++;
} else {
bitTextShift--;
}
}
return quantiseMatrixRGB;
}
一切似乎都很好,但现在我正在努力把一张照片重新组合起来。我所做的代码如下,但我认为这相当困难。难道没有更简单的方法吗?
例如,使用一些已经创建的JPEG编码器?
public int[][] revertGetQuantiseCoefficients (int[][] quantiseMatrixRGB) {
int[][] quantiseMatrix = {{16, 11, 10, 16, 24, 40, 51, 61},
{12, 12, 14, 19, 26, 58, 60, 55},
{14, 13, 16, 24, 40, 57, 69, 56},
{14, 17, 22, 29, 51, 87, 80, 62},
{18, 22, 37, 56, 68, 109, 103, 77},
{24, 35, 55, 64, 81, 104, 113, 92},
{49, 64, 78, 87, 103, 121, 120, 101},
{72, 92, 95, 98, 112, 100, 103, 99}};
for (int j = 0; j<8; j++) {
for (int k = 0; k<8; k++) {
quantiseMatrixRGB[j][k]=quantiseMatrixRGB[j][k]*quantiseMatrix[j][k];
}
}
return quantiseMatrixRGB;
}
public int[][] revertGetDTCTransformMatrix(int[][] quantiseMatrixRGB) {
double[][] dctTransformMatrix = new double[m][n];
double ck, cl, tmpDCTValue, tmpSum;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
tmpSum = 0;
for (int i_image = 0; i_image < m; i_image++) {
for (int j_image = 0; j_image < n; j_image++) {
if (i_image == 0) {
ck = 1 / Math.sqrt(m);
} else {
ck = Math.sqrt(2) / Math.sqrt(m);
}
if (j_image == 0) {
cl = 1 / Math.sqrt(n);
} else {
cl = Math.sqrt(2) / Math.sqrt(n);
}
tmpDCTValue = quantiseMatrixRGB[i_image][j_image] *
Math.cos((2 * i_image + 1) * i * pi / (2 * m)) *
Math.cos((2 * j_image + 1) * j * pi / (2 * n));
tmpSum = tmpSum + ck*cl*tmpDCTValue;
}
}
dctTransformMatrix[i][j] = tmpSum;
}
}
return quantiseMatrixRGB;
}
public int[][] getMergeRGB (int[][] r, int[][] g, int[][] b) {
int[][] mergeRGB = new int[r.length][r[1].length];
for (int i = 0; i<8; i++) {
for(int j = 0; j<8; j++) {
mergeRGB[i][j] = r[i][j];
mergeRGB[i][j] = (mergeRGB[i][j]<<8) + g[i][j];
mergeRGB[i][j] = (mergeRGB[i][j]<<8) + b[i][j];
}
}
return mergeRGB;
}
public BufferedImage getPixelBlock (int[][] mergeRGB) {
BufferedImage bi = new BufferedImage( 8, 8, BufferedImage.TYPE_INT_RGB );
final int[] a = ( (DataBufferInt) bi.getRaster().getDataBuffer() ).getData();
System.arraycopy(mergeRGB, 0, a, 0, mergeRGB.length);
return bi;
}
public BufferedImage joinImages (BufferedImage subImage) {
return null;
}
}
我正在努力将BufferedImage子图像重新组合在一起。有什么想法吗?
非常感谢您抽出时间并负担得起。
您似乎在尝试JPEG隐写术。编写jpeg编码器的标准非常复杂,因此可以更容易地借用已经编写好的编码器,并进行任何小的修改以在其中注入隐藏算法。
我已经回答了一个类似的问题,我简要总结了算法的要点,并用java展示了一个例子。
了解这个过程的一个好的开始是在维基百科上了解JPEG编码。这应该可以回答你提出的所有问题,但我也会在这里解决它们。
我应该向getDTCTransformMatrix((函数传递什么?现在我正在传递像素的整数值,我认为这是错误的。我看到一些例子,其中的家伙传递值从0-255,所以我应该转换成灰度图像?或者我应该对每种颜色(R、G、B(都这样做?
是的,您可以分别对每个颜色平面的整数值进行传递。它可以是RGB或YCrCb。它也可以是0-255,或者以0为中心,即-127128。YCrCb之所以被首选,是因为一些通道可以被压缩得更多,而不会因为我们的眼睛工作方式而导致任何明显的质量损失。并且将数字的范围移位到以0为中心意味着所得到的DCT系数将具有更小的值并且将花费更少的比特来存储。
在执行getDTCTransformMatrix((之后,我得到了二重矩阵。如何编辑双值LSB?这是一个正确的方法吗?
这是JPEG编码的要点。你应该用一个特定的量化矩阵来量化系数(把它们变成整数(。虽然有一个默认程序,但各种程序都选择使用自定义程序。其想法是低频系数不会受到很大影响,而大多数高频系数可能会变为0,这有助于最终文件大小变小。这是一个有损的过程,你应该在量化系数后嵌入你的信息,因为剩下的步骤都是无损的。
在我将以双倍值更改LSB之后,我接下来应该做什么?如何确保信息将存储在图像中。
在1D中以Z字形排列系数,以便低频系数优先。然后使用游程长度和霍夫曼编码的组合将信息存储在文件中。文件的二进制数据与原始像素(显然(或DCT系数的值都不相似。它是系数的压缩数据。