Лаплас с помощью c # Где я ошибся? - PullRequest
0 голосов
/ 09 октября 2018

Я пытаюсь реализовать фильтр Лапласа, но мой вывод всегда неверен:

enter image description here

Я отлаживал в течение 4 часов ... кто-то может датьмне какой-то намек?Спасибо !!

Это мой код:

private void button1_Click(object sender, EventArgs e)
    {
        Lap1();
    }
    void Lap1()
    {
        Bitmap img = new Bitmap(pictureBox1.Image);
        Bitmap image = new Bitmap(img);
        for (int x = 1; x < image.Width - 1; x++)
        {
            for (int y = 1; y < image.Height - 1; y++)
            {
                Color color2, color4, color5, color6, color8;
                color2 = image.GetPixel(x, y - 1);
                color4 = image.GetPixel(x - 1, y);
                color5 = image.GetPixel(x, y);
                color6 = image.GetPixel(x + 1, y);
                color8 = image.GetPixel(x, y + 1);
                int r = color2.R + color4.R + color5.R * (-4) + color6.R + color8.R;
                int g = color2.G + color4.G + color5.G * (-4) + color6.G + color8.G;
                int b = color2.B + color4.B + color5.B * (-4) + color6.B + color8.B;




                int avg = (r + g + b) / 3;
                if (avg > 255) avg = 255;
                if (avg < 0) avg = 0;
                image.SetPixel(x, y, Color.FromArgb(avg, avg, avg));
            }
        }
        pictureBox2.Image = image;


    }

Вот как это должно работать.

Ответы [ 3 ]

0 голосов
/ 09 октября 2018

Как указано выше, ваша проблема заключается в том, что вы обновляете то же изображение, с которого читаете.

Ниже приведена программа Linqpad, показывающая, как работает ваша функция при обновлении копии изображения:

void Main()
{
    Bitmap image = LoadPicture("https://i.stack.imgur.com/ti7Ij.png");

    using (Graphics g = Graphics.FromImage(image))
    {
        g.DrawRectangle(new Pen(Color.DarkOliveGreen), new Rectangle(11, 11, 33, 44));
        g.DrawRectangle(new Pen(Color.DarkOliveGreen), new Rectangle(33, 33, 33, 22));
        g.DrawRectangle(new Pen(Color.DarkOliveGreen), new Rectangle(33, 11, 22, 44));
    }

    image.Dump();
    Bitmap image2 = Lap1(image);
    image2.Dump();
}

Bitmap Lap1(Bitmap image)
{
    var image2 = new Bitmap(image);
    for (int x = 1; x < image.Width - 1; x++)
    {
        for (int y = 1; y < image.Height - 1; y++)
        {
            Color color2, color4, color5, color6, color8;
            color2 = image.GetPixel(x, y - 1);
            color4 = image.GetPixel(x - 1, y);
            color5 = image.GetPixel(x, y);
            color6 = image.GetPixel(x + 1, y);
            color8 = image.GetPixel(x, y + 1);
            int r = color2.R + color4.R + color5.R * (-4) + color6.R + color8.R;
            int g = color2.G + color4.G + color5.G * (-4) + color6.G + color8.G;
            int b = color2.B + color4.B + color5.B * (-4) + color6.B + color8.B;
            int avg = (r + g + b) / 3;
            if (avg > 255) avg = 255;
            if (avg < 0) avg = 0;
            image2.SetPixel(x, y, Color.FromArgb(avg, avg, avg));
        }
    }
    return image2;
}

private Bitmap LoadPicture(string url)
{
    HttpWebRequest wreq;
    HttpWebResponse wresp;
    Stream mystream;
    Bitmap bmp;

    bmp = null;
    mystream = null;
    wresp = null;
    try
    {
        wreq = (HttpWebRequest)WebRequest.Create(url);
        wreq.AllowWriteStreamBuffering = true;
        wresp = (HttpWebResponse)wreq.GetResponse();

        if ((mystream = wresp.GetResponseStream()) != null)
            bmp = new Bitmap(mystream);
    }
    finally
    {
        if (mystream != null)
            mystream.Close();

        if (wresp != null)
            wresp.Close();
    }
    return (bmp);
}

И результат,

До фильтра: before

После фильтра: after

0 голосов
/ 09 октября 2018

Я обработал ваш образец с помощью быстрой обработки изображений.Конечно, это еще далеко от идеального кода.Должны быть методы загрузки, обработки и сохранения.Потребовалось некоторое время, чтобы выяснить, что шаг иногда не равен ширине * bytesPerPixel.

Кроме того, усреднение r, g, b не является правильным преобразованием ToGray, поскольку глаз воспринимает цвета по-разному.

Согласно вашему коду вы должны получить GetPixel из img, устанавливая пиксель в изображение.

Рекомендуется также обрабатывать изображения в нормализованных двойных значениях от 0 до 1, но об этом не может быть и речи.

Также странно получать пиксели для реализации фильтра ядра.Лучше передавать матрицу и вычислять значения на основе матрицы, но не жестко кодировать.

Также плохо блокировать поток пользовательского интерфейса.Например, используйте TaskFactory.

(byte r, byte g, byte b) GetPixel(byte[] image,int x, int y, int bytesPerPixel,int stride)
{
      if (bytesPerPixel < 3) throw new ArgumentException(nameof(bytesPerPixel));
      byte b = image[x * bytesPerPixel + y * stride + 0];
      byte g = image[x * bytesPerPixel + y * stride + 1];
      byte r = image[x * bytesPerPixel + y * stride + 2];
      return (r, g, b);
}

byte ToGray((byte r, byte g, byte b) pixel)
{
   return NearestByte((int)(pixel.r * 0.3 + pixel.g * 0.59 + pixel.b * 0.11));
}

byte NearestByte(int a)
{
   return (byte)(Math.Min(255, Math.Max(0, a)));
}

void SetPixel(byte[] image, byte intensity, int x, int y, int bytesPerPixel, int stride)
{
    if (bytesPerPixel < 3) throw new ArgumentException(nameof(bytesPerPixel));
    image[x * bytesPerPixel + y * stride + 0] = intensity;
    image[x * bytesPerPixel + y * stride + 1] = intensity;
    image[x * bytesPerPixel + y * stride + 2] = intensity;
}

Bitmap ApplyLaplacianFilter(Bitmap input)
{            
    Bitmap img = new Bitmap(input);         
    // Lock the bitmap's bits.  
    Rectangle rect = new Rectangle(0, 0, img.Width, img.Height);
    System.Drawing.Imaging.BitmapData bmpData =
     img.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly,
     img.PixelFormat);

    IntPtr ptr = bmpData.Scan0;
    var stride = bmpData.Stride;
    int bytesPerPixel = bmpData.Stride / img.Width;
    int bytes = img.Width * img.Height * bytesPerPixel;
    byte[] rgbValues = new byte[bytes];
    System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
    img.UnlockBits(bmpData);
    int resultBytesPerPixel = 3;
    Bitmap resultBitmap = new Bitmap(img.Width, img.Height, PixelFormat.Format24bppRgb);            
    var bitmapData = resultBitmap.LockBits(rect, ImageLockMode.ReadWrite, resultBitmap.PixelFormat);

    int resultStride = bitmapData.Stride;              
    int resultBytes = resultStride * img.Height;    
    byte[] result = new byte[resultBytes];

    for (int y = 1; y < img.Height - 1; y++)
    {
       for (int x = 1; x < img.Width - 1; x++)
       {

         var left = GetPixel(rgbValues, x - 1, y, bytesPerPixel, stride);
         var right = GetPixel(rgbValues, x + 1, y, bytesPerPixel, stride);
         var top = GetPixel(rgbValues, x, y - 1, bytesPerPixel, stride);
         var bottom = GetPixel(rgbValues, x, y + 1, bytesPerPixel, stride);
         var center = GetPixel(rgbValues, x, y, bytesPerPixel, stride);

         var resultIntensity = NearestByte(
             ToGray(left) + ToGray(top) + ToGray(center) * (-4) + ToGray(right) + ToGray(bottom));
         SetPixel(result, resultIntensity, x, y, resultBytesPerPixel, resultStride);
       }
    }


   IntPtr resultPtr = bitmapData.Scan0;
   System.Runtime.InteropServices.Marshal.Copy(result, 0, resultPtr, resultBytes);
   resultBitmap.UnlockBits(bitmapData);            
   return resultBitmap;
}

private async void button1_Click(object sender, EventArgs e)
{
   pictureBox2.Image = await new TaskFactory().StartNew((image) => ApplyLaplacianFilter((Bitmap)image), pictureBox1.Image);                       
}
0 голосов
/ 09 октября 2018

Прежде всего (только по практическим соображениям) используйте логические имена.GetPixel () возвращает пиксель, а не цвет.И может быть полезно добавить суффикс, который относится к относительному положению пикселя, с которым вы хотите сравнить (N, NW, W, SW, S, SE, E).

То, что вы хотите получить - это нечтокак это:

var detlaRed = Math.Abs((pixel_E.R + pixel_W.R + pixel_N.R + pixel_S.R) - 4* pixel);

Так что я думаю, что вы хотите иметь абсолютное значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...