[英]Image remains unchanged after convolution
我正在嘗試基於AForge框架中的源執行高斯模糊計算。 目前,盡管我的計算有問題,因為我在處理過程中得到的像素數據與輸入的相同。(有些事情,我認為是在計算除法器)
該過程分為兩個部分:
基於以設置的大小創建的內核創建高斯濾波器。
對像素數組(rgba結構)處理濾鏡,以返回轉換后的像素,這些像素隨后將轉換為位圖。
我用於創建原始內核並轉換為基於整數的內核的方法已針對其他程序進行了測試,並且其實現是正確的。
任何幫助將不勝感激。 最近12個小時,我一直在努力。
創建過濾器的方法
/// <summary>
/// Create a 2 dimensional Gaussian kernel using the Gaussian G(x y)
/// function for blurring images.
/// </summary>
/// <param name="kernelSize">Kernel Size</param>
/// <returns>A Gaussian Kernel with the given size.</returns>
public double[,] CreateGuassianBlurFilter(int kernelSize)
{
// Create kernel
double[,] kernel = this.CreateGaussianKernel2D(kernelSize);
double min = kernel[0, 0];
// Convert to integer blurring kernel. First of all the integer kernel
// is calculated from Kernel2D
// by dividing all elements by the element with the smallest value.
double[,] intKernel = new double[kernelSize, kernelSize];
int divider = 0;
for (int i = 0; i < kernelSize; i++)
{
for (int j = 0; j < kernelSize; j++)
{
double v = kernel[i, j] / min;
if (v > ushort.MaxValue)
{
v = ushort.MaxValue;
}
intKernel[i, j] = (int)v;
// Collect the divider
divider += (int)intKernel[i, j];
}
}
// Update filter
this.Divider = divider;
return intKernel;
}
以及執行卷積的方法:
/// <summary>
/// Processes the given kernel to produce an array of pixels representing a
/// bitmap.
/// </summary>
/// <param name="pixels">The raw pixels of the image to blur</param>
/// <param name="kernel">
/// The Gaussian kernel to use when performing the method</param>
/// <returns>An array of pixels representing the bitmap.</returns>
public Pixel[,] ProcessKernel(Pixel[,] pixels, double[,] kernel)
{
int width = pixels.GetLength(0);
int height = pixels.GetLength(1);
int kernelLength = kernel.GetLength(0);
int radius = kernelLength >> 1;
int kernelSize = kernelLength * kernelLength;
Pixel[,] result = new Pixel[width, height];
// For each line
for (int y = 0; y < height; y++)
{
// For each pixel
for (int x = 0; x < width; x++)
{
// The number of kernel elements taken into account
int processedKernelSize;
// Colour sums
double blue;
double alpha;
double divider;
double green;
double red = green = blue = alpha = divider =
processedKernelSize = 0;
// For each kernel row
for (int i = 0; i < kernelLength; i++)
{
int ir = i - radius;
int position = y + ir;
// Skip the current row
if (position < 0)
{
continue;
}
// Outwith the current bounds so break.
if (position >= height)
{
break;
}
// For each kernel column
for (int j = 0; j < kernelLength; j++)
{
int jr = j - radius;
position = x + jr;
// Skip the column
if (position < 0)
{
continue;
}
if (position < width)
{
double k = kernel[i, j];
Pixel pixel = pixels[x, y];
divider += k;
red += k * pixel.R;
green += k * pixel.G;
blue += k * pixel.B;
alpha += k * pixel.A;
processedKernelSize++;
}
}
}
// Check to see if all kernel elements were processed
if (processedKernelSize == kernelSize)
{
// All kernel elements are processed; we are not on the edge.
divider = this.Divider;
}
else
{
// We are on an edge; do we need to use dynamic divider or not?
if (!this.UseDynamicDividerForEdges)
{
// Apply the set divider.
divider = this.Divider;
}
}
// Check and apply the divider
if ((long)divider != 0)
{
red /= divider;
green /= divider;
blue /= divider;
alpha /= divider;
}
// Add any applicable threshold.
red += this.Threshold;
green += this.Threshold;
blue += this.Threshold;
alpha += this.Threshold;
result[x, y].R = (byte)((red > 255)
? 255 : ((red < 0) ? 0 : red));
result[x, y].G = (byte)((green > 255)
? 255 : ((green < 0) ? 0 : green));
result[x, y].B = (byte)((blue > 255)
? 255 : ((blue < 0) ? 0 : blue));
result[x, y].A = (byte)((alpha > 255)
? 255 : ((alpha < 0) ? 0 : alpha));
}
}
return result;
}
問題在於選擇要乘以內核值的正確像素。 我選擇了相同的像素,而不是適當的偏移量。
校正后的方法如下。
/// <summary>
/// Processes the given kernel to produce an array of pixels representing a
/// bitmap.
/// </summary>
/// <param name="pixels">The raw pixels of the image to blur</param>
/// <param name="kernel">
/// The Gaussian kernel to use when performing the method</param>
/// <returns>An array of pixels representing the bitmap.</returns>
public Pixel[,] ProcessKernel(Pixel[,] pixels, double[,] kernel)
{
int width = pixels.GetLength(0);
int height = pixels.GetLength(1);
int kernelLength = kernel.GetLength(0);
int radius = kernelLength >> 1;
int kernelSize = kernelLength * kernelLength;
Pixel[,] result = new Pixel[width, height];
// For each line
for (int y = 0; y < height; y++)
{
// For each pixel
for (int x = 0; x < width; x++)
{
// The number of kernel elements taken into account
int processedKernelSize;
// Colour sums
double blue;
double alpha;
double divider;
double green;
double red = green = blue = alpha = divider =
processedKernelSize = 0;
// For each kernel row
for (int i = 0; i < kernelLength; i++)
{
int ir = i - radius;
int iposition = y + ir;
// Skip the current row
if (iposition < 0)
{
continue;
}
// Outwith the current bounds so break.
if (iposition >= height)
{
break;
}
// For each kernel column
for (int j = 0; j < kernelLength; j++)
{
int jr = j - radius;
int jposition = x + jr;
// Skip the column
if (jposition < 0)
{
continue;
}
if (jposition < width)
{
double k = kernel[i, j];
Pixel pixel = pixels[jposition, iposition];
divider += k;
red += k * pixel.R;
green += k * pixel.G;
blue += k * pixel.B;
alpha += k * pixel.A;
processedKernelSize++;
}
}
}
// Check to see if all kernel elements were processed
if (processedKernelSize == kernelSize)
{
// All kernel elements are processed; we are not on the edge.
divider = this.Divider;
}
else
{
// We are on an edge; do we need to use dynamic divider or not?
if (!this.UseDynamicDividerForEdges)
{
// Apply the set divider.
divider = this.Divider;
}
}
// Check and apply the divider
if ((long)divider != 0)
{
red /= divider;
green /= divider;
blue /= divider;
alpha /= divider;
}
// Add any applicable threshold.
red += this.Threshold;
green += this.Threshold;
blue += this.Threshold;
alpha += this.Threshold;
result[x, y].R = (byte)((red > 255)
? 255 : ((red < 0) ? 0 : red));
result[x, y].G = (byte)((green > 255)
? 255 : ((green < 0) ? 0 : green));
result[x, y].B = (byte)((blue > 255)
? 255 : ((blue < 0) ? 0 : blue));
result[x, y].A = (byte)((alpha > 255)
? 255 : ((alpha < 0) ? 0 : alpha));
}
}
return result;
}
找出原因的唯一快速方法是設置斷點並跟蹤值的變化。 這可以幫助您有效地捕獲有錯誤的代碼。 您可能會忘記一些計算,或者方法可能會返回未修改的副本而不是修改后的結果,或者修改后的計算可能會降低精度 ,無論如何,這不是委托給其他人的問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.