0

写真でいくつかの数学演算を実行する必要があります。そのためには、画像の浮動小数点グレースケール バージョンが必要です (これは、さまざまな色深度の JPG、PNG、または BMP ファイルから取得される可能性があります)。

PIL以前は Python でandを使用してそれを行っていましたが、グレースケールに変換してから を使用して浮動小数点数の配列にscipy.ndimage変換するのは非常に簡単でしたが、今では C# で同様のことを行う必要があり、どうすればよいか混乱しています。そうする。PILnumpy

私はこの非常に素晴らしいチュートリアルを読みました。これは繰り返し参照されているようですが、「グレースケールに変換」の部分しかカバーしていません。ビットマップから double の配列を取得する方法がわかりません。表示用に System.Drawing.Bitmap に変換します。

4

2 に答える 2

2

これを行うための最適な方法がたくさんあると確信しています。

@Groo がコメント セクションで完全に指摘しているように、たとえばLockBitsメソッドを使用して、インスタンスとの間でピクセルの色を読み書きできBitmapます。さらに進んで、コンピューターのグラフィックカードを使用して実際の計算を行うこともできます。

さらに、Color ToGrayscaleColor(Color color)色をグレースケール バージョンに変換する方法は、光学的に正しくありません。色成分の強度に実際に適用する必要がある比率のセットがあります。1、1、1 の比率を使用しました。それは私にとっては許容できることですが、アーティストや科学者にとってはおそらく恐ろしいことです。

コメント セクションで、@plinth は、解剖学的に正しい変換を行いたい場合に確認する必要があるこの質問を指摘してくれて非常に良かったです: Converting RGB to grayscale/intensity

この非常に理解しやすく実装しやすいソリューションを共有したかっただけです。

まず、Color をグレースケール バージョンに変換する小さなヘルパー:

    public static Color ToGrayscaleColor(Color color) {
        var level = (byte)((color.R + color.G + color.B) / 3);
        var result = Color.FromArgb(level, level, level);
        return result;
    }

次に、カラー ビットマップをグレースケール ビットマップに変換します。

    public static Bitmap ToGrayscale(Bitmap bitmap) {
        var result = new Bitmap(bitmap.Width, bitmap.Height);
        for (int x = 0; x < bitmap.Width; x++)
            for (int y = 0; y < bitmap.Height; y++) {
                var grayColor = ToGrayscaleColor(bitmap.GetPixel(x, y));
                result.SetPixel(x, y, grayColor);
            }
        return result;
    }

ダブルスの部分はかなり簡単です。Bitmapオブジェクトは、さまざまな操作で使用できる実際のイメージのメモリ表現です。Bitmap色深度と画像形式の詳細は、 のインスタンスをストリームまたはファイルにロードおよび保存する場合にのみ関係します。この時点では、それらについて気にする必要はありません。

    public static double[,] FromGrayscaleToDoubles(Bitmap bitmap) {
        var result = new double[bitmap.Width, bitmap.Height];
        for (int x = 0; x < bitmap.Width; x++)
            for (int y = 0; y < bitmap.Height; y++)
                result[x, y] = (double)bitmap.GetPixel(x, y).R / 255;
        return result;
    }

そして、double 配列をグレースケール イメージに戻します。

    public static Bitmap FromDoublesToGrayscal(double[,] doubles) {
        var result = new Bitmap(doubles.GetLength(0), doubles.GetLength(1));
        for (int x = 0; x < result.Width; x++)
            for (int y = 0; y < result.Height; y++) {
                int level = (int)Math.Round(doubles[x, y] * 255);
                if (level > 255) level = 255; // just to be sure
                if (level < 0) level = 0; // just to be sure
                result.SetPixel(x, y, Color.FromArgb(level, level, level));
            }
        return result;
    }

次の行:

    if (level > 255) level = 255; // just to be sure
    level < 0) level = 0; // just to be sure

ダブルスで操作し、小さなミスの余地を残したい場合に備えて、本当にそこにあります。

于 2013-09-12T13:57:28.567 に答える
1

主にコメントから得たヒントに基づいた最終的なコード、具体的にはそのLockBits部分 (ここのブログ投稿) と R、G、B 値の間の知覚的なバランス (ここでは重要ではありませんが、知っておくべきこと):

    private double[,] TransformaImagemEmArray(System.Drawing.Bitmap imagem) {
        // Transforma a imagem de entrada em um array de doubles
        // com os valores grayscale da imagem

        BitmapData bitmap_data = imagem.LockBits(new System.Drawing.Rectangle(0,0,_foto_franjas_original.Width,_foto_franjas_original.Height),
                                            ImageLockMode.ReadOnly, _foto_franjas_original.PixelFormat);

        int pixelsize = System.Drawing.Image.GetPixelFormatSize(bitmap_data.PixelFormat)/8;

        IntPtr pointer = bitmap_data.Scan0;
        int nbytes = bitmap_data.Height * bitmap_data.Stride;
        byte[] imagebytes = new byte[nbytes];
        System.Runtime.InteropServices.Marshal.Copy(pointer, imagebytes, 0, nbytes);

        double red;
        double green;
        double blue;
        double gray;

        var _grayscale_array = new Double[bitmap_data.Height, bitmap_data.Width];

        if (pixelsize >= 3 ) {
            for (int I = 0; I < bitmap_data.Height; I++) {
                for (int J = 0; J < bitmap_data.Width; J++ ) {
                    int position = (I * bitmap_data.Stride) + (J * pixelsize);
                    blue = imagebytes[position];
                    green = imagebytes[position + 1];
                    red = imagebytes[position + 2];
                    gray = 0.299 * red + 0.587 * green + 0.114 * blue;
                    _grayscale_array[I,J] = gray;
                }
            }
        }

        _foto_franjas_original.UnlockBits(bitmap_data);

        return _grayscale_array;
    }
于 2013-10-08T13:37:18.853 に答える