2

LSB を使用すると、イメージ キャリア サイズの約 12% でメッセージを保存できることを意味します。メッセージを n 個のフラグメントに分割し、12% がすべて占有されるまでイメージ キャリアをこれらのフラグメントで埋める Java プログラムを作成しました。問題は、結果の画像が歪んでおり、元の画像とは異なることです。画像の 12%、より正確には画像の LSB だけを塗りつぶすと、画像は歪まないだろうと考えました。

    int numHides = imLen/(totalLen*DATA_SIZE); // the number of messages I can store in the image
    int offset = 0;
    for(int h=0; h < numHides; h++) //hide all frags, numHides times
    for(int i=0; i < NUM_FRAGS; i++) {//NUM_FRAGS ..the number of fragments 
          hideStegoFrag(imBytes, stegoFrags[i], offset);//the method that hides the fragment into the picture starting at the offset position
          offset += stegoFrags[i].length*DATA_SIZE;
    }

   private static boolean hideStegoFrag(byte[] imBytes,byte[] stego,int off){
     int offset=off;
     for (int i = 0; i < stego.length; i++) { // loop through stego
      int byteVal = stego[i];
      for(int j=7; j >= 0; j--) { // loop through 8 bits of stego byte
         int bitVal = (byteVal >>> j) & 1;
         // change last bit of image byte to be the stego bit
         imBytes[offset] = (byte)((imBytes[offset] & 0xFE) | bitVal);
         offset++;
      }
    }
    return true;
}

バッファリングされたイメージをビットに変換するためのコード

       private static byte[] accessBytes(BufferedImage image)
       {
        WritableRaster raster = image.getRaster();
        DataBufferByte buffer = (DataBufferByte) raster.getDataBuffer();
        return buffer.getData();
       }

指定された名前とソース画像のバッファリングされた画像を使用して新しい画像を作成するコード

      public static boolean writeImageToFile(String imFnm , BufferedImage im){
    try {
        ImageIO.write(im, "png", new File(imFnm));
    } catch (IOException ex) {
        Logger.getLogger(MultiSteg.class.getName()).log(Level.SEVERE, null, ex);
    }
return true;

} 元の画像 修正後の画像

4

1 に答える 1

4

投稿した出力画像は、16 色の​​パレット画像です。

私が見ているデータは、実際に変更を画像の色ではなく、パレット インデックスに適用したことを示しています。歪みが見られる理由は、パレットの編成方法によるものです。色の LSB を変更しているのではなく、インデックスの LSB を変更しているため、完全に異なるものに変更される可能性があります (非常に目立つ)。 、ご覧のとおり)色。(実際には、他のすべてのインデックスの LSB を変更しています。16 色の​​形式は、1 ピクセルあたり 4 ビット、1 バイトあたり 2 ピクセルです。)

生の画像データを読み込んで、RGB カラー情報にデコードしなかったようです。アルゴリズムは生の RGB (または生のグレースケール) データに対してのみ機能します。ピクセルあたり 3 バイト (グレースケールの場合は 1)。画像を操作する前に、画像を RGB888 などに変換する必要があります。保存するときは、損失のないフルカラー (実際にすべての色をパレットに収めることができない場合) 形式でも保存する必要があります。そうしないと、情報が失われる危険があります。

あなたの問題は、実際にはプログラムのステガノグラフィ部分ではなく、画像データ自体の読み込みと保存にあります。

画像データを読み込むときは、RGB 形式に変換する必要があります。アプリケーションにとって最も便利な形式は、BufferedImage.TYPE_3BYTE_BGR各ピクセルを青、緑、赤の順序で 3 バイトとして格納する です (したがって、バイト配列は B、G、R、B、G、R、B、G、R になります。 ..)。次のようにできます。

public static BufferedImage loadRgbImage (String filename) {
    // load the original image
    BufferedImage originalImage = ImageIO.read(filename); 
    // create buffer for converted image in RGB format
    BufferedImage rgbImage = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
    // render original image into buffer, changes to destination format
    rgbImage.getGraphics().drawImage(originalImage, 0, 0, null);
    return rgbImage; 
}

とにかく、すでに BGR 形式のソース画像を頻繁に使用している場合は、画像が既に必要な形式になっている場合は、画像を変換しない簡単な最適化を行うことができます。

public static BufferedImage loadRgbImage (String filename) {
    BufferedImage originalImage = ImageIO.read(filename); 
    BufferedImage rgbImage;
    if (originalImage.getType() == BufferedImage.TYPE_3BYTE_BGR) {
        rgbImage = originalImage; // no need to convert, just return original
    } else {
        rgbImage = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
        rgbImage.getGraphics().drawImage(originalImage, 0, 0, null);
    }
    return rgbImage; 
}

その後、変換されたイメージをすべての操作に使用できます。変換されたイメージのバイト配列には3 * rgbImage.getWidth() * rgbImage.getHeight()バイトが含まれることに注意してください。

現在の画像保存コードを変更する必要はありません。ImageIO画像が RGB であることを検出し、24 ビット PNG を書き込みます。

于 2013-08-16T11:46:45.593 に答える