2014-11-03 3 views
2

Ive работал над кодом, который принимает изображение, превращает его в оттенки серого, а затем обрабатывает изображения в зависимости от того, какая кнопка нажата. Когда нажимается кнопка (например, средняя 3x3, Prewitt 5x5), она вызывает функцию двумерного умножения, которая перебирает изображение в оттенках серого, а цикл - через ядро, добавляя все значения в матрице. Если какое-либо значение превышает 255, оно устанавливает значение 255. Затем используйте SetPixel для временной переменной bitmap, которая, наконец, помещается в окно изображения. Когда я запускаю программу, я выбираю изображение, и он показывает его (в оттенках серого), но после выбора одного из фильтров программа замерзает около 30 секунд, а затем ничего не меняется, фильтр не применяется. Ive попробовал отладку, и я не могу найти, в чем проблема!Манипуляция изображения с использованием среднего ядра

EDIT:.. Первоначальный вопрос был решен (я должен был обновить PictureBox для нового изображения, чтобы показать правильно Но я столкнулся с другой проблемой здесь по отношению к ядру Прюитт

я получаю эту ошибку "Дополнительная информация: Значение '-6' недопустимо для 'красного'. '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)); 

       } 

      } 

     } 
    } 
+0

Если вы сохраните изображение с серой шкалой, «grayscaleimage», в файл и откройте его, скажем, Paint (или аналогичный), видите ли вы серое изображение или оно черное? – Sjips

+0

@Sjips его серый –

+0

Хммм, GetPixel/SetPixel - относительно медленные операции. Возможно, добавив инструкции 'Debug.WriteLine', вы увидите, какой код выполняется и где вы заканчиваете бесконечный цикл (если это произойдет). – Sjips

ответ

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 с одним вызовом LockBits. См. here.

Смежные вопросы