手機觀景窗上自動降噪挺好玩的,於是研究了一下,但具體的演算法都沒找到。於是自己想了一下,使用平均對比度方法,降低圖元顏色的差別。
原理如下:
在相片一定範圍內計算平均值(修正半徑)
得出平均值後,對沒個圖元進行修正(修正強度:0.0到1.0)
假設下圖是圖像顏色曲線:

100P32U9-0  

通過修正強度值為0.5修正後曲線如下:

100P35D4-1  

這時,圖像圖元點間對比對會減小,從而實現降噪的效果。
當然,這種方法缺點也比較明顯,修正後,相片模糊失真。
主要代碼如下:

 

/// <summary>
/// 圖像降噪
/// </summary>
/// <param name="srcBmp">原圖像</param>
/// <param name="radius">半徑</param>
/// <param name="strength">強度</param>
/// <returns></returns>
public WriteableBitmap ClsNoise(WriteableBitmap srcBmp, int radius, double strength)
{
WriteableBitmap newBitmap = new WriteableBitmap(srcBmp.PixelWidth, srcBmp.PixelHeight);
Color pixelPercent, pixelSrc;

 

byte r, g, b;

 

for (int yRow = 0; yRow < srcBmp.PixelHeight; yRow++)
{
for (int xCol = 0; xCol < srcBmp.PixelWidth; xCol++)
{
pixelSrc = srcBmp.GetPixel(xCol, yRow);
pixelPercent = this.GetPercentileColor(srcBmp, yRow, xCol, radius);

 

if (pixelSrc == pixelPercent)
{
newBitmap.SetPixel(xCol, yRow, pixelSrc);
}
else
{
r = (byte)(pixelSrc.R + (pixelPercent.R - pixelSrc.R) * strength);
g = (byte)(pixelSrc.G + (pixelPercent.G - pixelSrc.G) * strength);
b = (byte)(pixelSrc.B + (pixelPercent.B - pixelSrc.B) * strength);

 

newBitmap.SetPixel(xCol, yRow, Color.FromArgb(255, r, g, b));
}
}
}

 

return newBitmap;
}

 

/// <summary>
/// 獲取平均值
/// </summary>
/// <param name="srcBmp"></param>
/// <param name="yRow"></param>
/// <param name="xCol"></param>
/// <param name="radius"></param>
/// <returns></returns>
private Color GetPercentileColor(WriteableBitmap srcBmp, int yRow, int xCol, int radius)
{
int r = 0, g = 0, b = 0, start_yRow, end_yRow, start_xCol, end_xCol, c = 0;

 

start_yRow = yRow - radius;
if (start_yRow < 0)
{
start_yRow = 0;
}

 

end_yRow = yRow + radius;
if (end_yRow > srcBmp.PixelHeight - 1)
{
end_yRow = srcBmp.PixelHeight - 1;
}

 

start_xCol = xCol - radius;
if (start_xCol < 0)
{
start_xCol = 0;
}

 

end_xCol = xCol + radius;
if (end_xCol > srcBmp.PixelWidth - 1)
{
end_xCol = srcBmp.PixelWidth - 1;
}

 

for (int y = start_yRow; y <= end_yRow; y++)
{
for (int x = start_xCol; x <= end_xCol; x++)
{
Color color = srcBmp.GetPixel(x, y);
r += color.R;
b += color.B;
g += color.G;
c++;
}
}

 

if (c == 0)
{
return srcBmp.GetPixel(xCol, yRow);
}
else
{
return Color.FromArgb(255, (byte)(r / c), (byte)(g / c), (byte)(b / c));
}
}

 

如果你用過WriteableBitmap 類,就會發現沒有 GetPixel 和 SetPixel 方法的,我是通過擴充方法提供的,如:
public static class WriteableBitmapExtension
{
public static Color GetPixel(this WriteableBitmap bitmap, int xCol, int yRow)
{
byte[] bytes = BitConverter.GetBytes(bitmap.Pixels[bitmap.PixelWidth * yRow + xCol]);
return Color.FromArgb(bytes[3], bytes[2], bytes[1], bytes[0]);
}

 

public static void SetPixel(this WriteableBitmap bitmap, int xCol, int yRow, Color color)
{
byte[] bytes = new byte[] { color.B, color.G, color.R, color.A };
bitmap.Pixels[bitmap.PixelWidth * yRow + xCol] = BitConverter.ToInt32(bytes, 0);
}
}

 

最終效果如下:
 100P349D-2  
創作者介紹
創作者 shadow 的頭像
shadow

資訊園

shadow 發表在 痞客邦 留言(0) 人氣()