2016-07-31 3 views
-1

次の2つのルーチンを考えてみましょう。ビットマップからint [、]への変換とその逆

//Tested 
    ///Working fine. 
    public static Bitmap ToBitmap(int [,] image) 
    { 
     int Width = image.GetLength(0); 
     int Height = image.GetLength(1); 
     int i, j; 
     Bitmap bitmap = new Bitmap(Width, Height); 
     BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, Width, Height), 
           ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 
     unsafe 
     { 
      byte* address = (byte*)bitmapData.Scan0; 

      for (i = 0; i < bitmapData.Height; i++) 
      { 
       for (j = 0; j < bitmapData.Width; j++) 
       { 
        // write the logic implementation here 
        address[0] = (byte)image[j, i]; 
        address[1] = (byte)image[j, i]; 
        address[2] = (byte)image[j, i]; 
        address[3] = (byte)255; 
        //4 bytes per pixel 
        address += 4; 
       }//end for j 

       //4 bytes per pixel 
       address += (bitmapData.Stride - (bitmapData.Width * 4)); 
      }//end for i 
     }//end unsafe 
     bitmap.UnlockBits(bitmapData); 
     return bitmap;// col; 
    } 

    //Tested 
    ///Working fine. 
    public static int[,] ToInteger(Bitmap bitmap) 
    { 
     int[,] array2D = new int[bitmap.Width, bitmap.Height]; 

     BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), 
               ImageLockMode.ReadWrite, 
               PixelFormat.Format32bppRgb); 

     unsafe 
     { 
      byte* address = (byte*)bitmapData.Scan0; 

      int paddingOffset = bitmapData.Stride - (bitmap.Width * 4);//4 bytes per pixel 

      for (int i = 0; i < bitmap.Width; i++) 
      { 
       for (int j = 0; j < bitmap.Height; j++) 
       { 
        byte[] temp = new byte[4]; 
        temp[0] = address[0]; 
        temp[1] = address[1]; 
        temp[2] = address[2]; 
        temp[3] = address[3]; 

        array2D[j, i] = BitConverter.ToInt32(temp, 0); 

        //4-bytes per pixel 
        address += 4;//4-channels 
       } 
       address += paddingOffset; 
      } 
     } 
     bitmap.UnlockBits(bitmapData); 

     return array2D; 
    } 

これらの2つのルーチンは、32bppイメージで正常に動作します。これらのルーチンは、ピクセル形式がPixelFormat.Format32bppに設定されている場合にのみ機能します。 PixelFormat.Format8bppIndexedを使用すると、例外が生成されます。 、Iが32ビットBitmapにすることが階調をint[,]バック変換するたびに変換する必要がある(また、Iはbyte及びためのアドレス計算の問題のint間のシームレスな変換を達成することができなかった)その例外を回避するために

Bitmapに私はこの問題を取り除きたい。

 Bitmap grayscale = Grayscale.ToGrayscale(InputImage); 

     //Here, the Bitmap is treated as a 32bit image 
     //to avoid the exception eventhough it is already 
     //an 8bpp grayscale image. 
     int[,] i1 = ImageDataConverter.ToInteger(grayscale); 

     Complex[,] comp = ImageDataConverter.ToComplex(i1); 

     int[,] i2 = ImageDataConverter.ToInteger(comp); 

     Bitmap b2 = ImageDataConverter.ToBitmap(i2); 

     //It is already a Grayscale image. 
     //But, the problem is, b2.PixelFormat is set to 
     //PixelFormat.Formap32bpp because of those routines. 
     //Hence the unnecessay conversion. 
     b2 = Grayscale.ToGrayscale(b2); 

8bppインデックス付き(グレースケール)イメージでのみ動作するように修正する必要があります。

どうすれば実現できますか?

+0

あなたはどのような操作をしたいですか?あなたは 'int [、]'の代わりに 'byte [、]'を渡すことを望んでいるのですか?そうでなければ、 'int [、]'はどのように解釈されますか?各32ビット値は0から255の間の値を保存するだけでしょうか?彼らは実際にあなたが書くように索引付けされていますか?もしそうなら、どんなパレットを使うべきですか?または、彼らは本当にグレースケールですか(あなたも書いたように)?各32ビット値に4つのピクセルがパックされますか?いずれにしても、8ビットの値はどのように解釈されますか? 32bppイメージを出力するか、出力も8bppにする必要がありますか?あなたは、仕様の重要な部分をすべて除外しました。 –

答えて

0
public static int[,] ToInteger(Bitmap bitmap) 
{ 
    int[,] array2D = new int[bitmap.Width, bitmap.Height]; 

    BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), 
              ImageLockMode.ReadWrite, 
              PixelFormat.Format8bppIndexed); 
    int bytesPerPixel = sizeof(byte); 

    unsafe 
    { 
     byte* address = (byte*)bitmapData.Scan0; 

     int paddingOffset = bitmapData.Stride - (bitmap.Width * bytesPerPixel); 

     for (int i = 0; i < bitmap.Width; i++) 
     { 
      for (int j = 0; j < bitmap.Height; j++) 
      { 
       byte[] temp = new byte[bytesPerPixel]; 

       for (int k = 0; k < bytesPerPixel; k++) 
       { 
        temp[k] = address[k]; 
       } 

       int iii = 0; 

       if (bytesPerPixel >= sizeof(int)) 
       { 
        iii = BitConverter.ToInt32(temp, 0); 
       } 
       else 
       { 
        iii = (int)temp[0]; 
       } 

       array2D[j, i] = iii; 

       address += bytesPerPixel; 
      } 
      address += paddingOffset; 
     } 
    } 
    bitmap.UnlockBits(bitmapData); 

    return array2D; 
} 

public static Bitmap ToBitmap(int[,] image) 
{ 
    int Width = image.GetLength(0); 
    int Height = image.GetLength(1); 
    int i, j; 

    Bitmap bitmap = new Bitmap(Width, Height, PixelFormat.Format8bppIndexed); 

    BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, Width, Height), 
          ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed); 

    int bytesPerPixel = sizeof(byte); 

    unsafe 
    { 
     byte* address = (byte*)bitmapData.Scan0; 

     for (i = 0; i < bitmapData.Height; i++) 
     { 
      for (j = 0; j < bitmapData.Width; j++) 
      { 
       byte[] bytes = BitConverter.GetBytes(image[j, i]); 

       for (int k = 0; k < bytesPerPixel; k++) 
       { 
        address[k] = bytes[k]; 
       } 

       address += bytesPerPixel; 
      } 

      address += (bitmapData.Stride - (bitmapData.Width * bytesPerPixel)); 
     } 
    } 
    bitmap.UnlockBits(bitmapData); 

    Grayscale.SetGrayscalePalette(bitmap); 

    return bitmap; 
} 
+0

説明のビットがいいだろう – TheLethalCoder

1

インデックス付きビットマップを処理する場合は、イメージの各バイトを読み込み、パレットから色をルックアップする必要があります。あなたは画像を保存するときは、逆のロジックを実行する必要があります:

public static Bitmap ToBitmap(int[,] image) 
{ 
    int width = image.GetLength(0); 
    int height = image.GetLength(1); 
    Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format8bppIndexed); 
    BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), 
           ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); 
    int stride = bitmapData.Stride; 

    // A dictionary of colors to their index values 
    Dictionary<int, int> palette = new Dictionary<int, int>(); 
    // A flat list of colors 
    List<Color> paletteList = new List<Color>(); 

    unsafe 
    { 
     byte* address = (byte*)bitmapData.Scan0; 

     for (int x = 0; x < width; x++) 
     { 
      for (int y = 0; y < height; y++) 
      { 
       // Get the color from the Bitmap 
       int color = image[x, y]; 
       if (!palette.ContainsKey(color)) 
       { 
        // This color isn't in the palette, go ahead and add it 
        palette.Add(color, palette.Count); 
        paletteList.Add(Color.FromArgb(color)); 
        if (palette.Count >= 256) 
        { 
         // The palette is too big. Ideally this function would 
         // dither some pixels so it could handle this condition 
         // but that would make this example overly complicated 
         throw new InvalidOperationException("Too many colors in image"); 
        } 
       } 

       // And lookup the index of the color in the palette and 
       // add it to the BitmapData's memory 
       address[stride * y + x] = (byte)palette[color]; 
      } 
     } 
    } 

    bitmap.UnlockBits(bitmapData); 

    // Each time you call Bitmap.Palette it actually returns 
    // a Clone of the object, so we need to ask for a cloned 
    // copy here. 
    var newPalette = bitmap.Palette; 

    // For each one of our colors, add it to the palette object 
    for (int i = 0; i < paletteList.Count; i++) 
    { 
     newPalette.Entries[i] = paletteList[i]; 
    } 

    // And since this is a clone, assign it back to the bitmap 
    // so it'll take effect. 
    bitmap.Palette = newPalette; 

    return bitmap; 
} 

public static int[,] ToInteger(Bitmap bitmap) 
{ 
    if (bitmap.Palette.Entries.Length == 0) 
    { 
     // This doesn't appear to have a palette, so this operation doesn't 
     // make sense 
     throw new InvalidOperationException("bitmap is not an indexed bitmap"); 
    } 

    int width = bitmap.Width; 
    int height = bitmap.Height; 
    int[,] array2D = new int[width, height]; 

    BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), 
               ImageLockMode.ReadOnly, 
               PixelFormat.Format8bppIndexed); 

    unsafe 
    { 
     // Pull out the stride to prevent asking for it many times 
     int stride = bitmapData.Stride; 
     byte* address = (byte*)bitmapData.Scan0; 

     for (int x = 0; x < width; x++) 
     { 
      for (int y = 0; y < height; y++) 
      { 
       // Lookup the color based off the pixel, and set it's value 
       // to the return array 
       array2D[x, y] = bitmap.Palette.Entries[address[stride * y + x]].ToArgb(); 
      } 
     } 
    } 

    bitmap.UnlockBits(bitmapData); 

    return array2D; 
} 
+0

非常に遅い!実行に時間がかかります。 – anonymous

+1

はい。私はあなたの問題へのプロセスと解決策を提示しようとしていましたが、最も効果的な解決策を可能にするものではありませんでした。 –

関連する問題