2

画像を取得してグレースケールに変換し、押されたボタンに応じて画像操作を行うコードに取り組んでいます。ボタンが押されると (例: Average 3x3、Prewitt 5x5)、2D 乗算関数が呼び出され、グレースケール イメージがループされ、カーネルがループされ、マトリックス内のすべての値が加算されます。いずれかの値が 255 を超える場合は、それを 255 に設定します。次に、一時的なビットマップ変数で SetPixel を使用し、最終的にピクチャ ボックスに配置します。プログラムを実行すると、画像を選択すると (グレースケールとして) 表示されますが、フィルターの 1 つを選択した後、プログラムは約 30 秒間フリーズし、その後何も変化せず、フィルターも適用されません。私はデバッグを試みましたが、問題が何であるかを特定することはできません!

編集:最初の質問は解決されました(新しい画像を正しく表示するには、ピクチャボックスを更新する必要がありました。しかし、ここで prewitt カーネルに関して別の問題に直面しています。

「追加情報: '-6' の値は 'red' には無効です。'red' は 0 以上 255 以下である必要があります。」というエラーが表示されます。

そして、これを修正するためにコードで何を変更すればよいかわかりません。

初期化中:

public partial class Form1 : Form
{
    private Image img;
    Bitmap grayscaleimage;
    double[][] AVGKernel = new double[11][];
    double[][] PrewittKernel = new double[11][];
    int[] AVGKernal1DH = new int[11];
    int[] AVGKernal1DV = new int[11];

    Bitmap tempBitmap;

    public Form1()
    {
        InitializeComponent();
        for (int i = 0; i < 11; i++)
        {
            AVGKernel[i] = new double[11];
            PrewittKernel[i] = new double[11];
            for (int j = 0; j < 11; j++)
            {
                AVGKernel[i][j] = 0;
                PrewittKernel[i][j] = 0;
                AVGKernal1DH[j] = 0;
                AVGKernal1DV[j] = 0;
            }
        }
}

[開く] ボタンと画像をグレースケールに変換:

private void OpenImageButton(object sender, EventArgs e)
    {
        OpenFileDialog openFileDialog = new OpenFileDialog();
        if (openFileDialog.ShowDialog() == DialogResult.OK)
        {
            this.img = Image.FromFile(openFileDialog.FileName);

            grayscaleimage = new Bitmap(img);
            int rgb;
            Color c;

            for (int y = 0; y < grayscaleimage.Height; y++)
                for (int x = 0; x < grayscaleimage.Width; x++)
                {
                    c = grayscaleimage.GetPixel(x, y);
                    rgb = (int)((c.R + c.G + c.B) / 3);
                    grayscaleimage.SetPixel(x, y, Color.FromArgb(rgb, rgb, rgb));
                }
            this.pictureBox1.BackgroundImage = grayscaleimage;
            pictureBox1.BackgroundImageLayout = ImageLayout.Zoom;
        }
    }

利用可能な多くのボタンの例:

private void button5_Click(object sender, EventArgs e)
    {
        AVGKernel[0][0] = 1; AVGKernel[0][1] = 1; AVGKernel[0][2] = 1; AVGKernel[0][3] = 1; AVGKernel[0][4] = 1;
        AVGKernel[1][0] = 1; AVGKernel[1][1] = 1; AVGKernel[1][2] = 1; AVGKernel[1][3] = 1; AVGKernel[1][4] = 1;
        AVGKernel[2][0] = 1; AVGKernel[2][1] = 1; AVGKernel[2][2] = 1; AVGKernel[2][3] = 1; AVGKernel[2][4] = 1;
        AVGKernel[3][0] = 1; AVGKernel[3][1] = 1; AVGKernel[3][2] = 1; AVGKernel[3][3] = 1; AVGKernel[3][4] = 1;
        AVGKernel[4][0] = 1; AVGKernel[4][1] = 1; AVGKernel[4][2] = 1; AVGKernel[4][3] = 1; AVGKernel[4][4] = 1;

        kernal2DMultiplication(AVGKernel, 5);
        this.pictureBox1.BackgroundImage = tempBitmap;

    }

Prewitt 5x5 カーネル

 private void button13_Click(object sender, EventArgs e)
    {
        PrewittKernel[0][0] = 2; PrewittKernel[0][1] = 1; PrewittKernel[0][2] = 0; PrewittKernel[0][3] = -1; PrewittKernel[0][4] = -2;
        PrewittKernel[1][0] = 2; PrewittKernel[1][1] = 1; PrewittKernel[1][2] = 0; PrewittKernel[1][3] = -1; PrewittKernel[1][4] = -2;
        PrewittKernel[2][0] = 2; PrewittKernel[2][1] = 1; PrewittKernel[2][2] = 0; PrewittKernel[2][3] = -1; PrewittKernel[2][4] = -2;
        PrewittKernel[3][0] = 2; PrewittKernel[3][1] = 1; PrewittKernel[3][2] = 0; PrewittKernel[3][3] = -1; PrewittKernel[3][4] = -2;
        PrewittKernel[4][0] = 2; PrewittKernel[4][1] = 1; PrewittKernel[4][2] = 0; PrewittKernel[4][3] = -1; PrewittKernel[4][4] = -2;

        kernal2DMultiplication(PrewittKernel, 5);
        this.pictureBox1.BackgroundImage = tempBitmap;
        this.pictureBox1.Refresh();
    }

最後に、呼び出される関数:

private void kernal2DMultiplication(double[][] kernel, int size)
    {
        tempBitmap = grayscaleimage;
        double nrgb = 0;

        for (int i = 0; i < grayscaleimage.Width - size / 2; i++)
        {
            for (int j = 0; j < grayscaleimage.Height - size / 2; j++)
            {
                if (i >= size / 2 && j >= size / 2)
                {
                    for (int k = 0; k < size; k++)
                        for (int l = 0; l < size; l++)

                            nrgb += grayscaleimage.GetPixel(i + k - (size / 2), j + l - (size / 2)).R * kernel[k][l];
                            nrgb = nrgb / (size * size);

                    if (nrgb > 255)
                        nrgb = 255;

                    tempBitmap.SetPixel(i, j, Color.FromArgb((int)nrgb, (int)nrgb, (int)nrgb));

                }

            }

        }
    }
4

1 に答える 1

1

問題はBackgroundImage、コピーするのではなく、ビットマップをインプレースで変更し、コピーを変更してから、コピーを次のように設定することBackgroundImageです。

    this.pictureBox1.BackgroundImage = grayscaleimage; // initially

    tempBitmap = grayscaleimage; 

    // Make changes to tempBitmap

    this.pictureBox1.BackgroundImage = tempBitmap; // actually still the same pointer

このBackgroundImage場合、セッターはコントロールの再描画を強制していません。これを自分で強制するには、次のように呼び出しますRefresh()

    this.pictureBox1.Refresh();

パフォーマンスを改善するには、 への複数回の呼び出しを へSetPixelの 1回の呼び出しに置き換えることを検討してくださいLockBits。たとえばここを参照してください。

于 2014-11-03T19:50:31.183 に答える