4

c でバイキュービック画像補間を処理しようとしています。したがって、この小さなスクリプトを作成しました。

1. 「resize_image」関数:

    void resize_image(PPMImage *source_image, PPMImage *destination_image, float scale) {

        uint8_t sample[3];
        int y, x;

        destination_image->x = (long)((float)(source_image->x)*scale);
        destination_image->y = (long)((float)(source_image->y)*scale);

        for (y = 0; y < destination_image->y; y++) {

            float v = (float)y / (float)(destination_image->y - 1);

            for (x = 0; x < destination_image->x; ++x) {

                float u = (float)x / (float)(destination_image->x - 1);
                sample_bicubic(source_image, u, v, sample);

                destination_image->data[x+((destination_image->y)*y)].red   = sample[0];
                destination_image->data[x+((destination_image->y)*y)].green = sample[1];  
                destination_image->data[x+((destination_image->y)*y)].blue  = sample[2];  
            }
        }
    }

2.「sample_bicubic」関数

    void sample_bicubic(PPMImage *source_image, float u, float v, uint8_t sample[]) {

        float x = (u * source_image->x)-0.5;
        int xint = (int)x;
        float xfract = x-floor(x);

        float y = (v * source_image->y) - 0.5;
        int yint = (int)y;
        float yfract = y - floor(y);

        int i;

        uint8_t p00[3];
        uint8_t p10[3];
        uint8_t p20[3];
        uint8_t p30[3];

        uint8_t p01[3];
        uint8_t p11[3];
        uint8_t p21[3];
        uint8_t p31[3];

        uint8_t p02[3];
        uint8_t p12[3];
        uint8_t p22[3];
        uint8_t p32[3];

        uint8_t p03[3];
        uint8_t p13[3];
        uint8_t p23[3];
        uint8_t p33[3];

        // 1st row
        get_pixel_clamped(source_image, xint - 1, yint - 1, p00);   
        get_pixel_clamped(source_image, xint + 0, yint - 1, p10);
        get_pixel_clamped(source_image, xint + 1, yint - 1, p20);
        get_pixel_clamped(source_image, xint + 2, yint - 1, p30);

        // 2nd row
        get_pixel_clamped(source_image, xint - 1, yint + 0, p01);
        get_pixel_clamped(source_image, xint + 0, yint + 0, p11);
        get_pixel_clamped(source_image, xint + 1, yint + 0, p21);
        get_pixel_clamped(source_image, xint + 2, yint + 0, p31);

        // 3rd row
        get_pixel_clamped(source_image, xint - 1, yint + 1, p02);
        get_pixel_clamped(source_image, xint + 0, yint + 1, p12);
        get_pixel_clamped(source_image, xint + 1, yint + 1, p22);
        get_pixel_clamped(source_image, xint + 2, yint + 1, p32);

        // 4th row
        get_pixel_clamped(source_image, xint - 1, yint + 2, p03);
        get_pixel_clamped(source_image, xint + 0, yint + 2, p13);
        get_pixel_clamped(source_image, xint + 1, yint + 2, p23);
        get_pixel_clamped(source_image, xint + 2, yint + 2, p33);

        // interpolate bi-cubically!
        for (i = 0; i < 3; i++) {

            float col0 = cubic_hermite(p00[i], p10[i], p20[i], p30[i], xfract);
            float col1 = cubic_hermite(p01[i], p11[i], p21[i], p31[i], xfract);
            float col2 = cubic_hermite(p02[i], p12[i], p22[i], p32[i], xfract);
            float col3 = cubic_hermite(p03[i], p13[i], p23[i], p33[i], xfract);

            float value = cubic_hermite(col0, col1, col2, col3, yfract);

            CLAMP(value, 0.0f, 255.0f);

            sample[i] = (uint8_t)value;

            printf("sample[%d]=%d\n",i,sample[i]);      

        }
    }

3.「補間ヘルパー」

    float cubic_hermite(float A, float B, float C, float D, float t) {

        float a = -A / 2.0f + (3.0f*B) / 2.0f - (3.0f*C) / 2.0f + D / 2.0f;
        float b = A - (5.0f*B) / 2.0f + 2.0f*C - D / 2.0f;
        float c = -A / 2.0f + C / 2.0f;
        float d = B;

        return a*t*t*t + b*t*t + c*t + d;
    }

    void get_pixel_clamped(PPMImage *source_image, int x, int y, uint8_t temp[])  {

        CLAMP(x, 0, source_image->x - 1);
        CLAMP(y, 0, source_image->y - 1);

        temp[0] = source_image->data[x+(W*y)].red;
        temp[1] = source_image->data[x+(W*y)].green;
        temp[2] = source_image->data[x+(W*y)].blue;
    }

ここにすべてのものを含む完全なコードをアップロードしました。

このコードを実行しても構文エラーはありません。

しかし、出力画像は私を混乱させました。

入力画像 (21x20Pixel):

入力画像: 21x20ピクセル

この入力画像は 2 倍 (42x40 ピクセル) に拡大されます。

出力画像: 42x40ピクセル

補間はいくつかの点でうまく機能しているように見えますが、画像はピクセルがずれているように見えます。

誰かが私が間違っていることを教えてもらえますか? このスクリプトは次の助けを借りて作成されました: http://blog.demofox.org/2015/08/15/resizing-images-with-bicubic-interpolation/

みんなありがとう!

(このコードの効率を考慮しないでください...私が知っている恐ろしいことです)

4

2 に答える 2

3

resize_image() 関数から:

destination_image->data[x+((destination_image->y)*y)].red   = sample[0];

それはおそらくそうあるべきです

destination_image->data[x+((destination_image->x)*y)].red   = sample[0];

このようなケースのデバッグに役立つのは、実際のデータには存在しない「魔法の色」で宛先イメージを初期化することです (たとえば、ひどいピンク :-))。次に、 resize_image() 呼び出しの後、一部の宛先ピクセルがまだその色を持っていることに気付くでしょう。これは問題を示唆しています。

于 2016-01-05T23:27:47.413 に答える
1

コードをテストしたところ、別の問題があることに気付きました。

init_destination_image() 関数から:

img->data = (PPMPixel*)malloc(W * H * (int)scale * sizeof(PPMPixel));

次のようにする必要があります。

img->data = (PPMPixel*)malloc(W * H * (int)scale * (int)scale * sizeof(PPMPixel));

両方など、WHがスケーリングされています。

于 2021-04-09T18:07:20.490 に答える