正确执行两次立方取样 [英] Correctly executing bicubic resampling

查看:226
本文介绍了正确执行两次立方取样的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试与图像双三次重采样算法present在AForge框架引入类似的东西在我的图像处理解决方案的想法。查看原始算法<一href="https://github.com/cureos/aforge/blob/033d09e64b371f994ad19b3347156311e17a88a2/Sources/Imaging/Filters/Transform/ResizeBicubic.cs"相对=nofollow>这里和插值内核<一href="https://github.com/cureos/aforge/blob/033d09e64b371f994ad19b3347156311e17a88a2/Sources/Imaging/Interpolation.cs"相对=nofollow>这里

不幸的是,我碰了壁。它看起来对我来说,不知何故,我计算了样目标位置不正确,可能是由于算法被设计为 Format24bppRgb 图像那里,因为我使用的是 Format32bppPArgb 格式。

下面是我的code:

 公共位图调整大小(位图源,诠释的宽度,高度INT)
{
    INT sourceWidth = source.Width;
    INT sourceHeight = source.Height;

    位图目标=新位图(宽度,高度,PixelFormat.Format32bppPArgb);
    destination.SetResolution(source.Horizo​​ntalResolution,source.VerticalResolution);

    使用(FastBitmap = sourceBitmap中新FastBitmap(源))
    {
        使用(FastBitmap destinationBitmap =新FastBitmap(目标))
        {
            双heightFactor = sourceWidth /(双)宽度;
            双widthFactor = sourceHeight /(双)高度;

            //坐标源点
            双牛,OY,DX,DY,K1,K2;
            INT OX1,oy1,OX 2,oy2;

            //宽度和高度下降了1
            INT =了maxHeight高度 -  1;
            INT =了maxWidth宽度 -  1;

            对于(INT Y = 0; Y&LT;高度; Y ++)
            {
                // y坐标
                OY =(Y * widthFactor) -  0.5;

                oy1 =(INT)OY;
                DY = OY  -  oy1;

                对于(INT X = 0,X&LT;宽度; X ++)
                {
                    // X坐标
                    牛=(X * heightFactor) -  0.5F;
                    OX1 =(INT)牛;
                    DX =牛 -  OX1;

                    //目标颜色分量
                    双使r = 0;
                    双G = 0;
                    双B = 0;
                    双一= 0;

                    对于(INT N = -1; N 3;; N ++)
                    {
                        //获取ÿcooefficient
                        K1 = Interpolation.BiCubicKer​​nel(DY  -  N);

                        oy2 = oy1 + N;
                        如果(oy2℃,)
                        {
                            oy2 = 0;
                        }

                        如果(oy2&GT;了maxHeight)
                        {
                            oy2 =了maxHeight;
                        }

                        为(中间体米= -1;米3;;米++)
                        {
                            //得到对X cooefficient
                            K2 = K1 * Interpolation.BiCubicKer​​nel(M  -  DX);

                            OX 2 = OX1 +米;
                            如果(OX2℃,)
                            {
                                OX2 = 0;
                            }

                            如果(OX 2&GT;了maxWidth)
                            {
                                OX 2 =了maxWidth;
                            }

                            色色= sourceBitmap.GetPixel(OX 2,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();
    返回目的地;
}
 

和它应该重新present在维基百科 <给定的公式内核/ P>

 公共静态双BiCubicKer​​nel(双X)
{
    如果(X℃,)
    {
        X = -x;
    }

    双bicubicCoef = 0;

    如果(X LT; = 1)
    {
        bicubicCoef =(1.5 * X  -  2.5)* X * X + 1;
    }
    否则如果(X 2)
    {
        bicubicCoef =((-0.5 * X + 2.5)* X  -  4)* X + 2;
    }

    返回bicubicCoef;
}
 

下面是在500px的x 667px原始图像。

一棵树画面

和调整为400像素x 543px图像。

树双三次算法应用

目视看来该图像是过度还原然后同一像素被重复施加一旦我们击中一个特定点。

任何人都可以给我一些指点这里解决此问题?

注意 FastBitmap是使用LockBits来操纵内存像素的包装,位图。它可以很好地一切我申请到。

修改

根据要求这里的参与 ToByte

方法

 公共静态字节ToByte(这双值)
{
    返回Convert.ToByte(ImageMaths.Clamp(值0,255));
}

公共静态牛逼钳&LT; T&GT;(吨价,T最小,T最大),其中T:IComparable的&LT; T&GT;
{
    如果(value.CompareTo(分钟)小于0)
    {
        返回分钟;
    }

    如果(value.CompareTo(最大)大于0)
    {
        返回最大值;
    }

    返回值;
}
 

解决方案

正在限制你的 OX 2 oy2 目标图片尺寸,而不是源尺寸。

更改此:

  //宽度和高度下降了1
INT =了maxHeight高度 -  1;
INT =了maxWidth宽度 -  1;
 

这样:

  //宽度和高度下降了1
INT =了maxHeight sourceHeight  -  1;
INT =了maxWidth sourceWidth  -  1;
 

I've been experimenting with the image bicubic resampling algorithm present in the AForge framework with the idea of introducing something similar into my image processing solution. See the original algorithm here and interpolation kernel here

Unfortunately I've hit a wall. It looks to me like somehow I am calculating the sample destination position incorrectly, probably due to the algorithm being designed for Format24bppRgb images where as I am using a Format32bppPArgb format.

Here's my code:

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;
}

And the kernel which should represent the given equation on 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;
}

Here's the original image at 500px x 667px.

And the image resized to 400px x 543px.

Visually it appears that the image is over reduced and then the same pixels are repeatedly applied once we hit a particular point.

Can anyone give me some pointers here to solve this?

Note FastBitmap is a wrapper for Bitmap that uses LockBits to manipulate pixels in memory. It works well with everything else I apply it to.

Edit

As per request here's the methods involved in 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;
}

解决方案

You are limiting your ox2 and oy2 to destination image dimensions, instead of source dimensions.

Change this:

// Width and height decreased by 1
int maxHeight = height - 1;
int maxWidth = width - 1;

to this:

// Width and height decreased by 1
int maxHeight = sourceHeight - 1;
int maxWidth = sourceWidth - 1;

这篇关于正确执行两次立方取样的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆