ASP.NET中Bitmap图像模糊效果实现求助:现有代码效果不佳求资料
Hey there! The approach you're using right now (offsetting and overlaying semi-transparent copies) is a quick-and-dirty pseudo-blur, but it's prone to edge artifacts, uneven blurring, and poor performance as your BlurSize increases. Let's fix that with proper, high-quality blur methods tailored for Bitmap images in VB.NET:
Why Your Current Code Isn't Working
Your current method works by drawing the same image multiple times with slight offsets and reduced opacity. This creates a "smudged" look, but it has major drawbacks:
- Uneven blur: Pixels near the edge get clipped, leading to distorted edges
- No natural diffusion: It doesn't mimic the human eye's perception of blur (Gaussian blur is the industry standard)
- Performance issues: The number of draw calls scales with
BlurSize², which gets slow fast for larger values
Option 1: Built-in Blur Effect (.NET 5+ / .NET Core)
If you're working with .NET 5 or later (or using the System.Drawing.Common NuGet package), you can leverage GDI+'s native BlurEffect for clean, fast blurs with minimal code.
Code Example:
Imports System.Drawing.Imaging Imports System.Drawing.Drawing2D Public Function ApplyHighQualityBlur(ByVal sourceBitmap As Bitmap, ByVal blurRadius As Integer) As Bitmap ' Create a new bitmap to hold the blurred result Dim blurredBitmap As New Bitmap(sourceBitmap.Width, sourceBitmap.Height) Using g As Graphics = Graphics.FromImage(blurredBitmap) ' Enable high-quality rendering settings g.SmoothingMode = SmoothingMode.HighQuality g.InterpolationMode = InterpolationMode.HighQualityBicubic g.PixelOffsetMode = PixelOffsetMode.HighQuality ' Configure the blur effect Dim blurEffect As New BlurEffect With { .Radius = blurRadius, ' Controls blur intensity (1-20 is ideal) .Optimization = BlurOptimization.Balanced ' Balances speed and quality } ' Draw the original image and apply the blur effect g.DrawImage(sourceBitmap, New Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height)) g.DrawImage( sourceBitmap, New Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), 0, 0, sourceBitmap.Width, sourceBitmap.Height, GraphicsUnit.Pixel, Nothing, AddressOf BlurEffectCallback, blurEffect ) End Using Return blurredBitmap End Function ' Callback to apply the blur effect during rendering Private Sub BlurEffectCallback(ByVal callbackData As Object, ByVal effect As Effect) Dim blurEffect As BlurEffect = DirectCast(callbackData, BlurEffect) effect.Apply(blurEffect) End Sub
Option 2: Manual Gaussian Blur (Compatible with .NET Framework)
For older .NET Framework projects, you'll need to implement Gaussian blur manually. This method uses a convolution kernel weighted by a Gaussian distribution to create natural, smooth blurs.
Code Example:
Imports System.Drawing Imports System.Runtime.InteropServices Public Module BitmapBlurExtensions ''' <summary> ''' Applies Gaussian blur to a Bitmap ''' </summary> ''' <param name="source">Source Bitmap to blur</param> ''' <param name="radius">Blur radius (1-20 recommended)</param> ''' <returns>Blurred Bitmap</returns> Public Function GaussianBlur(ByVal source As Bitmap, ByVal radius As Integer) As Bitmap If radius < 1 Then Return DirectCast(source.Clone(), Bitmap) Dim width As Integer = source.Width Dim height As Integer = source.Height Dim blurred As New Bitmap(width, height) ' Lock bitmap data for fast pixel access Dim sourceData As BitmapData = source.LockBits( New Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb ) Dim blurredData As BitmapData = blurred.LockBits( New Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb ) Dim stride As Integer = sourceData.Stride Dim sourceBuffer As Byte() = New Byte(stride * height - 1) {} Dim blurredBuffer As Byte() = New Byte(stride * height - 1) {} ' Copy pixel data to buffers Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, sourceBuffer.Length) ' Generate Gaussian convolution kernel Dim kernel As Double() = CreateGaussianKernel(radius) Dim kernelSize As Integer = kernel.Length ' Apply horizontal then vertical blur (separable convolution) HorizontalBlur(sourceBuffer, blurredBuffer, width, height, stride, kernel, kernelSize) VerticalBlur(blurredBuffer, sourceBuffer, width, height, stride, kernel, kernelSize) ' Copy processed data back to the blurred bitmap Marshal.Copy(sourceBuffer, 0, blurredData.Scan0, sourceBuffer.Length) ' Unlock bitmap data source.UnlockBits(sourceData) blurred.UnlockBits(blurredData) Return blurred End Function ''' <summary> ''' Creates a normalized Gaussian kernel ''' </summary> Private Function CreateGaussianKernel(ByVal radius As Integer) As Double() Dim size As Integer = radius * 2 + 1 Dim kernel As Double() = New Double(size - 1) {} Dim sigma As Double = radius / 3.0 ' Standard deviation for Gaussian curve Dim sum As Double = 0.0 ' Calculate Gaussian weights For i As Integer = -radius To radius kernel(i + radius) = Math.Exp(-(i * i) / (2 * sigma * sigma)) sum += kernel(i + radius) Next ' Normalize kernel so total weight equals 1 For i As Integer = 0 To size - 1 kernel(i) /= sum Next Return kernel End Function ''' <summary> ''' Applies horizontal blur using the convolution kernel ''' </summary> Private Sub HorizontalBlur(ByVal source As Byte(), ByVal dest As Byte(), ByVal width As Integer, ByVal height As Integer, ByVal stride As Integer, ByVal kernel As Double(), ByVal kernelSize As Integer) Dim radius As Integer = (kernelSize - 1) \ 2 For y As Integer = 0 To height - 1 For x As Integer = 0 To width - 1 Dim r, g, b, a As Double Dim offset As Integer = y * stride + x * 4 ' Convolve with kernel For k As Integer = -radius To radius Dim nx As Integer = Math.Max(0, Math.Min(width - 1, x + k)) ' Clamp to image bounds Dim kernelOffset As Integer = k + radius Dim pixelOffset As Integer = y * stride + nx * 4 r += source(pixelOffset + 2) * kernel(kernelOffset) g += source(pixelOffset + 1) * kernel(kernelOffset) b += source(pixelOffset) * kernel(kernelOffset) a += source(pixelOffset + 3) * kernel(kernelOffset) Next ' Write clamped pixel values to destination dest(offset) = CByte(Math.Max(0, Math.Min(255, b))) dest(offset + 1) = CByte(Math.Max(0, Math.Min(255, g))) dest(offset + 2) = CByte(Math.Max(0, Math.Min(255, r))) dest(offset + 3) = CByte(Math.Max(0, Math.Min(255, a))) Next Next End Sub ''' <summary> ''' Applies vertical blur using the convolution kernel ''' </summary> Private Sub VerticalBlur(ByVal source As Byte(), ByVal dest As Byte(), ByVal width As Integer, ByVal height As Integer, ByVal stride As Integer, ByVal kernel As Double(), ByVal kernelSize As Integer) Dim radius As Integer = (kernelSize - 1) \ 2 For x As Integer = 0 To width - 1 For y As Integer = 0 To height - 1 Dim r, g, b, a As Double Dim offset As Integer = y * stride + x * 4 ' Convolve with kernel For k As Integer = -radius To radius Dim ny As Integer = Math.Max(0, Math.Min(height - 1, y + k)) ' Clamp to image bounds Dim kernelOffset As Integer = k + radius Dim pixelOffset As Integer = ny * stride + x * 4 r += source(pixelOffset + 2) * kernel(kernelOffset) g += source(pixelOffset + 1) * kernel(kernelOffset) b += source(pixelOffset) * kernel(kernelOffset) a += source(pixelOffset + 3) * kernel(kernelOffset) Next ' Write clamped pixel values to destination dest(offset) = CByte(Math.Max(0, Math.Min(255, b))) dest(offset + 1) = CByte(Math.Max(0, Math.Min(255, g))) dest(offset + 2) = CByte(Math.Max(0, Math.Min(255, r))) dest(offset + 3) = CByte(Math.Max(0, Math.Min(255, a))) Next Next End Sub End Module
Usage Tips
- Blur radius: Stick to values between 1 and 20. Larger radiuses create more intense blur but will slow down processing.
- Performance optimization: For large images, resize the image to a smaller resolution before blurring, then scale it back up. This drastically reduces the number of pixels to process.
- Dispose of objects: Always wrap
BitmapandGraphicsobjects inUsingstatements to avoid memory leaks.
内容的提问来源于stack exchange,提问作者Geo Concepts

