双立方插值 - 正确分离

时间:2015-10-14 15:03:05

标签: c# image-processing interpolation spline bicubic

我试图用三次样条和插值的广义公式实现双立方图像插值 我能够通过使用所有16​​个周围像素来实现这一点,并从这16个函数值计算插值系数。但由于插值可以通过定义分离,我试图实现一个使用两个1-D插值的版本,以实现双三次插值。 对于广义插值公式,我使用例如{3}}第3章和1-D插值我使用了这个背后的想法:http://bigwww.epfl.ch/publications/thevenaz9901.pdf
我的系数是通过像http://www.vision-systems.com/articles/print/volume-12/issue-10/departments/wilsons-websites/understanding-image-interpolation-techniques.html

中的4x4矩阵一样对其进行计算

插值包含三个功能 插值函数本身(phi):

private float interpolate(float p_fValue)
    {
        p_fValue = Math.Abs(p_fValue);

        if (p_fValue >= 1 && p_fValue < 2)
        {
            return 1.0f / 6.0f * (2.0f - p_fValue) * (2.0f - p_fValue) * (2.0f - p_fValue);//-(p_fValue * p_fValue * p_fValue) / 6.0f + p_fValue * p_fValue - 2.0f * p_fValue + 4.0f / 3.0f;
        }
        else if (p_fValue < 1)
        {
            return 2.0f / 3.0f - p_fValue * p_fValue + 0.5f * (p_fValue * p_fValue * p_fValue);
        }
        else
        {
            return 0.0f;
        }
    }

从4个函数值计算4个系数:

private void calculateCoefficients(float p_f1, float p_f2, float p_f3, float p_f4, out float p_c1, out float p_c2, out float p_c3, out float p_c4)
    {
        p_c1 = 6.0f / 209.0f * (56.0f * p_f1 - 15.0f * p_f2 + 4.0f * p_f3 - p_f4);
        p_c2 = 6.0f / 209.0f * (-15.0f * p_f1 + 60.0f * p_f2 - 16.0f * p_f3 + 4.0f * p_f4);
        p_c3 = 6.0f / 209.0f * (4.0f * p_f1 - 16.0f * p_f2 + 60.0f * p_f3 - 15.0f * p_f4);
        p_c4 = 6.0f / 209.0f * (-p_f1 + 4.0f * p_f2 - 15.0f * p_f3 + 56.0f * p_f4);
    }

从较小的源图像中插入整个图像:

// p_siImage = original (smaller) image
    // p_iImageWidth, p_iImageHeight = Image size (pixel count) of the new image
    // Interpolation with standard formula u(x) = sum_{k to N} c_k * phi(x-k); For N function values
    public SampledImage InterpolateImage(SampledImage p_siImage, int p_iImageWidth, int p_iImageHeight)
    {
        // Create interpolated image
        SampledImage resultImage = new SampledImage((int)p_siImage.GetWidth(), (int)p_siImage.GetHeight(), p_iImageWidth, p_iImageHeight, p_siImage.GetPixelWidth(), p_siImage.GetPixelHeight());

        for (int iX = 0; iX < p_iImageWidth; iX++)
        {
            for (int iY = 0; iY < p_iImageHeight; iY++)
            {
                // Calculate pixel position "in space"
                float[] pixelSpace = resultImage.GetPixelInSpace(iX, iY);

                // Calculate the index in smaller image, as real number (pixel index between pixels)
                float[] pixelRealIndex = p_siImage.GetPixelRealFromSpace(pixelSpace[0], pixelSpace[1]);

                // Calculate X values of surrounding pixels
                int x_2 = (int)Math.Floor(pixelRealIndex[0]) - 1;
                int x_1 = (int)Math.Floor(pixelRealIndex[0]);
                int x1 = (int)Math.Floor(pixelRealIndex[0]) + 1;
                int x2 = (int)Math.Floor(pixelRealIndex[0]) + 2;

                // Calculate Y value of nearest pixel
                int y = (int)Math.Floor(pixelRealIndex[1]);

                // Arrays for "function values" (= color values)
                float[] red = new float[4];
                float[] green = new float[4];
                float[] blue = new float[4];

                // Create polynom for each column
                for (int iiX = -1; iiX < 3; iiX++)
                {
                    // Get column X-index
                    int x = (int)Math.Floor(pixelRealIndex[0]) + iiX;

                    // Used Y-Indices for polynom
                    int y_2 = (int)Math.Floor(pixelRealIndex[1]) - 1;
                    int y_1 = (int)Math.Floor(pixelRealIndex[1]);
                    int y1 = (int)Math.Floor(pixelRealIndex[1]) + 1;
                    int y2 = (int)Math.Floor(pixelRealIndex[1]) + 2;

                    // Get "function values" for each pixel in the column
                    Color fxy_2 = p_siImage.GetValueMirrored(x, y_2);
                    Color fxy_1 = p_siImage.GetValueMirrored(x, y_1);
                    Color fxy1 = p_siImage.GetValueMirrored(x, y1);
                    Color fxy2 = p_siImage.GetValueMirrored(x, y2);

                    // Coefficients c_k
                    float redC_2, redC_1, redC1, redC2;
                    float greenC_2, greenC_1, greenC1, greenC2;
                    float blueC_2, blueC_1, blueC1, blueC2;

                    // Calculate the coefficients for the column polynom
                    calculateCoefficients(fxy_2.R, fxy_1.R, fxy1.R, fxy2.R, out redC_2, out redC_1, out redC1, out redC2);
                    calculateCoefficients(fxy_2.G, fxy_1.G, fxy1.G, fxy2.G, out greenC_2, out greenC_1, out greenC1, out greenC2);
                    calculateCoefficients(fxy_2.B, fxy_1.B, fxy1.B, fxy2.B, out blueC_2, out blueC_1, out blueC1, out blueC2);

                    // Interpolate in each column at the same Y-Index as the actual interpolation position
                    red[iiX+1] = redC_2 * interpolate(pixelRealIndex[1] - (float)y_2) + redC_1 * interpolate(pixelRealIndex[1] - (float)y_1) +
                        redC1 * interpolate(pixelRealIndex[1] - (float)y1) + redC2 * interpolate(pixelRealIndex[1] - (float)y2);
                    green[iiX+1] = greenC_2 * interpolate(pixelRealIndex[1] - (float)y_2) + greenC_1 * interpolate(pixelRealIndex[1] - (float)y_1) +
                        greenC1 * interpolate(pixelRealIndex[1] - (float)y1) + greenC2 * interpolate(pixelRealIndex[1] - (float)y2);
                    blue[iiX+1] = blueC_2 * interpolate(pixelRealIndex[1] - (float)y_2) + blueC_1 * interpolate(pixelRealIndex[1] - (float)y_1) +
                        blueC1 * interpolate(pixelRealIndex[1] - (float)y1) + blueC2 * interpolate(pixelRealIndex[1] - (float)y2);
                }

                //Now: interpolate the actual value

                // Get "function values" for each pixel in the row
                Color fx_2y = p_siImage.GetValueMirrored(x_2, y);
                Color fx_1y = p_siImage.GetValueMirrored(x_1, y);
                Color fx1y = p_siImage.GetValueMirrored(x1, y);
                Color fx2y = p_siImage.GetValueMirrored(x2, y);

                // Coefficients c_k
                float redCX_2, redCX_1, redCX1, redCX2;
                float greenCX_2, greenCX_1, greenCX1, greenCX2;
                float blueCX_2, blueCX_1, blueCX1, blueCX2;

                // Calculate coefficients by using the interpolated values of each column
                calculateCoefficients(red[0], red[1], red[2], red[3], out redCX_2, out redCX_1, out redCX1, out redCX2);
                calculateCoefficients(green[0], green[1], green[2], green[3], out greenCX_2, out greenCX_1, out greenCX1, out greenCX2);
                calculateCoefficients(blue[0], blue[1], blue[2], blue[3], out blueCX_2, out blueCX_1, out blueCX1, out blueCX2);

                // Interpolate finally for the actual value
                float redResult = redCX_2 * interpolate(pixelRealIndex[0] - (float)x_2) + redCX_1 * interpolate(pixelRealIndex[0] - (float)x_1) +
                    redCX1 * interpolate(pixelRealIndex[0] - (float)x1) + redCX2 * interpolate(pixelRealIndex[0] - (float)x2);
                float greenResult = greenCX_2 * interpolate(pixelRealIndex[0] - (float)x_2) + greenCX_1 * interpolate(pixelRealIndex[0] - (float)x_1) +
                    greenCX1 * interpolate(pixelRealIndex[0] - (float)x1) + greenCX2 * interpolate(pixelRealIndex[0] - (float)x2);
                float blueResult = blueCX_2 * interpolate(pixelRealIndex[0] - (float)x_2) + blueCX_1 * interpolate(pixelRealIndex[0] - (float)x_1) +
                    blueCX1 * interpolate(pixelRealIndex[0] - (float)x1) + blueCX2 * interpolate(pixelRealIndex[0] - (float)x2);

                // Make sure to care for under/overshoots
                redResult = Math.Max(0, Math.Min(redResult, 255));
                greenResult = Math.Max(0, Math.Min(greenResult, 255));
                blueResult = Math.Max(0, Math.Min(blueResult, 255));

                // Set the pixel to the calculated value
                Color resultColor = Color.FromArgb((int)redResult, (int)greenResult, (int)blueResult);
                resultImage.SetValue(iX, iY, resultColor);
            }
        }

        return resultImage;
    }

对于这样的图像(15x15px): https://en.wikipedia.org/wiki/Spline_interpolation#Example

结果如下(缩放到80x80px): Source Image 15x15px

相反,如果我一次计算所有16个系数(80x80px),这就是结果的样子: Bicubic Spline interpolated separate 80x80

我现在的问题是: 分离是如何正确完成的?或者我完全错过了一些东西,我只能分离插值函数(phi)而不是系数的计算?

0 个答案:

没有答案