65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 C# 实现膨胀算法

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.17/5 (9投票s)

2009年3月4日

CPOL

2分钟阅读

viewsIcon

66789

downloadIcon

2966

此代码有助于使用 C# 实现膨胀算法。

DilationProject.PNG

引言

我是一名 C# 开发者,我的领域是图像处理。在 C# 中,执行膨胀操作非常困难。膨胀算法是一种数学形态学,在医学成像项目中是必需的。这篇文章将帮助那些尝试膨胀图像的人。代码中使用了指针,因此速度更快。

什么是膨胀?

膨胀是数学形态学领域中的两个基本算子之一。膨胀是对图像进行单次处理。在通过图像的过程中,结构元素应用于图像的每个像素,使得结构元素的原点应用于该特定像素。在这种情况下,输出图像的相应像素包含其周围像素的最大值。在这种情况下,只有结构元素包含的像素才相互比较。

Using the Code

此函数接受源位图并返回膨胀后的位图。GetPixelSetPixel 函数存在一些缺点,因此我们使用指针。我们使用指针访问和修改像素值。下一个示例利用 C# 中的“unsafe”块。在 unsafe 块内部,我们可以访问 C# 中的指针。结论是,unsafe 块中的指针比 GetPixelSetPixel 函数更快。

public Bitmap Dilate(Bitmap SrcImage)
{
    // Create Destination bitmap.
    Bitmap tempbmp = new Bitmap(SrcImage.Width,SrcImage.Height);

    // Take source bitmap data.
    BitmapData SrcData = SrcImage.LockBits(new Rectangle(0, 0,
        SrcImage.Width, SrcImage.Height), ImageLockMode.ReadOnly,
        PixelFormat.Format24bppRgb);

    // Take destination bitmap data.
    BitmapData DestData = tempbmp.LockBits(new Rectangle(0, 0, tempbmp.Width,
        tempbmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

    // Element array to used to dilate.
    byte[,] sElement = new byte[5, 5] { 
        {0,0,1,0,0},
        {0,1,1,1,0},
        {1,1,1,1,1},
        {0,1,1,1,0},
        {0,0,1,0,0}
    };

    // Element array size.
    int size = 5;
    byte max, clrValue;
    int radius = size / 2;
    int ir, jr;

    unsafe
    {

        // Loop for Columns.
        for (int colm = radius; colm < DestData.Height - radius; colm++)
        {
            // Initialise pointers to at row start.
            byte* ptr = (byte*)SrcData.Scan0 + (colm * SrcData.Stride);
            byte* dstPtr = (byte*)DestData.Scan0 + (colm * SrcData.Stride);

            // Loop for Row item.
            for (int row = radius; row < DestData.Width - radius; row++)
            {
                max = 0;
                clrValue = 0;

                // Loops for element array.
                for (int eleColm = 0; eleColm < 5; eleColm++)
                {
                    ir = eleColm - radius;
                    byte* tempPtr = (byte*)SrcData.Scan0 + 
                        ((colm + ir) * SrcData.Stride);

                    for (int eleRow = 0; eleRow < 5; eleRow++)
                    {
                        jr = eleRow - radius;

                        // Get neightbour element color value.
                        clrValue = (byte)((tempPtr[row * 3 + jr] + 
                            tempPtr[row * 3 + jr + 1] + tempPtr[row * 3 + jr + 2]) / 3);

                        if (max < clrValue)
                        {
                            if (sElement[eleColm, eleRow] != 0)
                                max = clrValue;
                        }
                    }
                }

                dstPtr[0] = dstPtr[1] = dstPtr[2] = max;

                ptr += 3;
                dstPtr += 3;
            }
        }
    }

    // Dispose all Bitmap data.
    SrcImage.UnlockBits(SrcData);
    tempbmp.UnlockBits(DestData);

    // return dilated bitmap.
    return tempbmp;
}

在这个函数中,我们将图像结构的起始和结束地址计算出来,认为它是一个一维线性数组。我们从起始地址到结束地址递增指针,并获取中间的值。计算周围像素的最大值,并将最大像素值赋给膨胀图像指针。

关注点

像素与其相邻像素的膨胀效果非常好。该算法还帮助我使用 C# 实现腐蚀算法。

历史

  • 2009 年 3 月 4 日:初始发布
© . All rights reserved.