我一直在试验AForge框架中出现的图像双三次重采样算法,并想要在我的图像处理解决方案中引入类似的东西。查看原始算法here和插值内核here
不幸的是我撞墙了。它看起来像我在某种程度上错误地计算样本目的地位置,可能是由于算法是为Format24bppRgb
图像而设计的,因为我正在使用Format32bppPArgb
格式。
这是我的代码:
public Bitmap Resize(Bitmap source, int width, int height)
{
int sourceWidth = source.Width;
int sourceHeight = source.Height;
Bitmap destination = new Bitmap(width, height, PixelFormat.Format32bppPArgb);
destination.SetResolution(source.HorizontalResolution, source.VerticalResolution);
using (FastBitmap sourceBitmap = new FastBitmap(source))
{
using (FastBitmap destinationBitmap = new FastBitmap(destination))
{
double heightFactor = sourceWidth / (double)width;
double widthFactor = sourceHeight / (double)height;
// Coordinates of source points
double ox, oy, dx, dy, k1, k2;
int ox1, oy1, ox2, oy2;
// Width and height decreased by 1
int maxHeight = height - 1;
int maxWidth = width - 1;
for (int y = 0; y < height; y++)
{
// Y coordinates
oy = (y * widthFactor) - 0.5;
oy1 = (int)oy;
dy = oy - oy1;
for (int x = 0; x < width; x++)
{
// X coordinates
ox = (x * heightFactor) - 0.5f;
ox1 = (int)ox;
dx = ox - ox1;
// Destination color components
double r = 0;
double g = 0;
double b = 0;
double a = 0;
for (int n = -1; n < 3; n++)
{
// Get Y cooefficient
k1 = Interpolation.BiCubicKernel(dy - n);
oy2 = oy1 + n;
if (oy2 < 0)
{
oy2 = 0;
}
if (oy2 > maxHeight)
{
oy2 = maxHeight;
}
for (int m = -1; m < 3; m++)
{
// Get X cooefficient
k2 = k1 * Interpolation.BiCubicKernel(m - dx);
ox2 = ox1 + m;
if (ox2 < 0)
{
ox2 = 0;
}
if (ox2 > maxWidth)
{
ox2 = maxWidth;
}
Color color = sourceBitmap.GetPixel(ox2, oy2);
r += k2 * color.R;
g += k2 * color.G;
b += k2 * color.B;
a += k2 * color.A;
}
}
destinationBitmap.SetPixel(
x,
y,
Color.FromArgb(a.ToByte(), r.ToByte(), g.ToByte(), b.ToByte()));
}
}
}
}
source.Dispose();
return destination;
}
应该代表Wikipedia
上给定方程的内核public static double BiCubicKernel(double x)
{
if (x < 0)
{
x = -x;
}
double bicubicCoef = 0;
if (x <= 1)
{
bicubicCoef = (1.5 * x - 2.5) * x * x + 1;
}
else if (x < 2)
{
bicubicCoef = ((-0.5 * x + 2.5) * x - 4) * x + 2;
}
return bicubicCoef;
}
这是500px x 667px的原始图像。
图像大小调整为400px x 543px。
从视觉上看,图像过度缩小,然后在我们到达特定点时重复应用相同的像素。
有人可以给我一些指示来解决这个问题吗?
注意 FastBitmap是Bitmap的包装器,它使用LockBits来操作内存中的像素。它适用于everything else我将其应用于。
修改
根据请求,这里涉及ToByte
public static byte ToByte(this double value)
{
return Convert.ToByte(ImageMaths.Clamp(value, 0, 255));
}
public static T Clamp<T>(T value, T min, T max) where T : IComparable<T>
{
if (value.CompareTo(min) < 0)
{
return min;
}
if (value.CompareTo(max) > 0)
{
return max;
}
return value;
}
答案 0 :(得分:2)
您将ox2
和oy2
限制为目标图片尺寸,而不是源尺寸。
改变这个:
// Width and height decreased by 1
int maxHeight = height - 1;
int maxWidth = width - 1;
到此:
// Width and height decreased by 1
int maxHeight = sourceHeight - 1;
int maxWidth = sourceWidth - 1;
答案 1 :(得分:1)
好吧,我遇到了一个非常奇怪的事情,可能是或可能不是问题的原因。 我开始尝试自己实现卷积矩阵并遇到奇怪的行为。我正在测试4x4像素的小图像上的代码。代码如下:
var source = Bitmap.FromFile(@"C:\Users\Public\Pictures\Sample Pictures\Безымянный.png");
using (FastBitmap sourceBitmap = new FastBitmap(source))
{
for (int TY = 0; TY < 4; TY++)
{
for (int TX = 0; TX < 4; TX++)
{
Color color = sourceBitmap.GetPixel(TX, TY);
Console.Write(color.B.ToString().PadLeft(5));
}
Console.WriteLine();
}
}
虽然我只打印出蓝色通道值,但它仍然显然不正确。
另一方面,你的解决方案部分起作用,是什么使得我发现的东西无关紧要。我还有一个猜测:你的系统的DPI是什么?
从我发现的帮助中,这里有一些链接:
到目前为止,这是我的答案,但我会进一步尝试。