Monday, 20 November 2017

Use image filters to perform edge detection, smoothing, embossing, and more in C#

public Bitmap32 ApplyFilter(Filter filter, bool lock_result)
{
    // Make a copy of this Bitmap32.
    Bitmap32 result = this.Clone();

    // Lock both bitmaps.
    bool was_locked = this.IsLocked;
    this.LockBitmap();
    result.LockBitmap();

    // Apply the filter.
    int xoffset = -(int)(filter.Kernel.GetUpperBound(1) / 2);
    int yoffset = -(int)(filter.Kernel.GetUpperBound(0) / 2);
    int xmin = -xoffset;
    int xmax = Bitmap.Width - filter.Kernel.GetUpperBound(1);
    int ymin = -yoffset;
    int ymax = Bitmap.Height - filter.Kernel.GetUpperBound(0);
    int row_max = filter.Kernel.GetUpperBound(0);
    int col_max = filter.Kernel.GetUpperBound(1);

    for (int x = xmin; x <= xmax; x++)
    {
        for (int y = ymin; y <= ymax; y++)
        {
            // Skip the pixel if any under the kernel
            // is completely transparent.
            bool skip_pixel = false;

            // Apply the filter to pixel (x, y).
            float red = 0, green = 0, blue = 0;
            for (int row = 0; row <= row_max; row++)
            {
                for (int col = 0; col <= col_max; col++)
                {
                    int ix = x + col + xoffset;
                    int iy = y + row + yoffset;
                    byte new_red, new_green, new_blue, new_alpha;
                    this.GetPixel(ix, iy, out new_red, out new_green, out new_blue, out new_alpha);

                    // See if we should skip this pixel.
                    if (new_alpha == 0)
                    {
                        skip_pixel = true;
                        break;
                    }

                    red   += new_red   * filter.Kernel[row, col];
                    green += new_green * filter.Kernel[row, col];
                    blue  += new_blue  * filter.Kernel[row, col];
                }
                if (skip_pixel) break;
            }

            if (!skip_pixel)
            {
                // Divide by the weight, add the offset, and
                // make sure the result is between 0 and 255.
                red = filter.Offset + red / filter.Weight;
                if (red < 0) red = 0;                 if (red > 255) red = 255;

                green = filter.Offset + green / filter.Weight;
                if (green < 0) green = 0;                 if (green > 255) green = 255;

                blue = filter.Offset + blue / filter.Weight;
                if (blue < 0) blue = 0;                 if (blue > 255) blue = 255;

                // Set the new pixel's value.
                result.SetPixel(x, y, (byte)red, (byte)green, (byte)blue,
                    this.GetAlpha(x, y));
            }
        }
    }

    // Unlock the bitmaps.
    if (!lock_result) result.UnlockBitmap();
    if (!was_locked) this.UnlockBitmap();

    // Return the result.
    return result;
}

// A standard embossing filter.
public static Filter EmbossingFilter
{
    get
    {
        return new Filter()
        {
            Weight = 1,
            Offset = 127,
            Kernel = new float[,]
            {
                {-1, 0, 0},
                {0, 0, 0},
                {0, 0, 1},
            }
        };
    }
}

// Apply a filter.
private void ApplyFilter(Bitmap32.Filter filter)
{
    Bitmap bm = new Bitmap(picVisible.Image);
    this.Cursor = Cursors.WaitCursor;
    DateTime start_time = DateTime.Now;

    // Make a Bitmap24 object.
    Bitmap32 bm32 = new Bitmap32(bm);

    // Apply the filter.
    Bitmap32 new_bm32 = bm32.ApplyFilter(filter, false);

    // Display the result.
    picVisible.Image = new_bm32.Bitmap;

    DateTime stop_time = DateTime.Now;
    this.Cursor = Cursors.Default;

    TimeSpan elapsed_time = stop_time - start_time;
    lblElapsed.Text = elapsed_time.TotalSeconds.ToString("0.000000");
}

No comments:

Post a Comment