GithubHelp home page GithubHelp logo

bicubic-image-resize's People

Contributors

shawlleyw avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

bicubic-image-resize's Issues

No border?

Hi @shawlleyw .

Use "no border" variant:

#ifndef RESIZE_H_
#define RESIZE_H_

#include "utils.hpp"

float BiCubicWeightCoeff(float x, float a)
{
    if (x <= 1.0f)
    {
        return (1.0f - ((a + 3.0f) - (a + 2.0f) * x) * x * x);
    }
    else if (x < 2.0f)
    {
        return ((-4.0f + (8.0f - (5.0f - x) * x) * x) * a);
    }
    return 0.0f;
}

void BiCubicCoeff4x4(float y, float x, float *coeff)
{
    const float a = -0.5f;

    float u = y - (int)y;
    float v = x - (int)x;

    u += 1.0f;
    v += 1.0f;

    int k = 0;
    for (int i = 0; i < 4; i++)
    {
        float du = (u > i) ? (u - i) : (i - u);
        for (int j = 0; j < 4; j++)
        {
            float dv = (v > j) ? (v - j) : (j - v);
            coeff[k] =
                BiCubicWeightCoeff(du, a) * BiCubicWeightCoeff(dv, a);
            k++;
        }
    }
}

void BGRAfterBiCubic(unsigned char *pix, RGBImage src, float y_float, float x_float,
                              int channels)
{
    float coeff[16];

    int y0 = (int)y_float - 1;
    int x0 = (int)x_float - 1;
    BiCubicCoeff4x4(y_float, x_float, coeff);

    float sum[channels] = {0.0f};
    size_t k = 0, l;
    for (int i = 0; i < 4; i++)
    {
        int yf = ((y0 + i) < 0) ? 0 : ((y0 + i) < src.rows) ? (y0 + i) : (src.rows - 1);
        for (int j = 0; j < 4; j++)
        {
            int xf = ((x0 + j) < 0) ? 0 : ((x0 + j) < src.cols) ? (x0 + j) : (src.cols - 1);
            l = (yf * src.cols + xf) * channels;
            for (int d = 0; d < channels; d++)
            {
                sum[d] += coeff[k] * src.data[l + d];
            }
            k++;
        }
    }
    for (int d = 0; d < channels; d++)
    {
        pix[d] = (unsigned char)((sum[d] < 0.0f) ? 0 : (sum[d] < 255.0f) ? sum[d] : 255);
    }
}

RGBImage ResizeImage(RGBImage src, float ratio)
{
    const int channels = src.channels;
    Timer timer("resize image");
    int resize_rows = src.rows * ratio;
    int resize_cols = src.cols * ratio;
    unsigned char pix[channels];

    printf("resize to: %d x %d\n", resize_cols, resize_rows);

    unsigned char *res = new unsigned char[channels * resize_rows * resize_cols];

    size_t k = 0;
    for (int i = 0; i < resize_rows; i++)
    {
        float src_y = ((float)i + 0.5f) / ratio - 0.5f;
        for (int j = 0; j < resize_cols; j++)
        {
            float src_x = ((float)j + 0.5f) / ratio - 0.5f;
            BGRAfterBiCubic(pix, src, src_y, src_x, channels);
            for (int d = 0; d < channels; d++)
            {
                res[k] = pix[d];
                k++;
            }
            // k += channels;
        }
    }
    return RGBImage{resize_cols, resize_rows, channels, res};
}

#endif /* RESIZE_H_ */

PS: Lead time *= 0.65

You variant:

time ./resize tree.jpg 
image height: 2434, width: 3314
resize to: 12170 x 16570
>>> resize image by 5x: 38610ms
save image tree_5x.jpg

real    0m44,045s
user    0m43,800s
sys     0m0,244s

My variant:

time ./resize tree.jpg tree_x5.jpg 5 
image 3314 x 2434
resize to: 16570 x 12170
>>> resize image: 23882ms
save image tree_x5.jpg

real    0m29,393s
user    0m29,070s
sys     0m0,244s

BiAkima?

Hi @shawlleyw .

Besides BiCubic (4x4) there is an implementation of BiAkima (6x6). Wouldn't it be more interesting to test a more time-consuming resize besides BiCubic.

Implementation in Qt:

int SelectChannelPixel(QRgb pix, int channel)
{
    int value[5] = {qRed(pix), qGreen(pix), qBlue(pix), qAlpha(pix), 0};
    return value[channel];
}

QRgb InterpolateBiAkima (QImage img, float y, float x)
{
    int i, j, d, dn, xi, yi, xf, yf;
    float dx, dy, zp, zf, a, b;
    float Cc, C[6], m[6], t[2];
    int Ci, pt[4];
    int height = img.height();
    int width = img.width();;
    QRgb *row, imgpix;

    yi = (int)y;
    dy = y - yi;
    yi = (yi < 0) ? 0 : (yi < height) ? yi : (height - 1);
    xi = (int)x;
    dx = x - xi;
    xi = (xi < 0) ? 0 : (xi < width) ? xi : (width - 1);
    dn = (img.hasAlphaChannel()) ? 4 : 3;
    for(d = 0; d < dn; d++)
    {
        if (dy > 0.0f)
        {
            for(i = -2; i < 4; i++)
            {
                yf = (int)y + i;
                yf = (yf < 0) ? 0 : (yf < height) ? yf : (height - 1);
                row = (QRgb*)img.constScanLine(yf);
                if (dx > 0.0f)
                {
                    zp = 0.0f;
                    for(j = -2; j < 4; j++)
                    {
                        xf = (int)x + j;
                        xf = (xf < 0) ? 0 : (xf < width) ? xf : (width - 1);
                        zf = SelectChannelPixel(row[xf], d);
                        m[j + 2] = zf - zp;
                        zp = zf;
                    }
                    for(j = 0; j < 2; j++)
                    {
                        a = (m[j + 3] > m[j + 4]) ? (m[j + 3] - m[j + 4]) : (m[j + 4] - m[j + 3]);
                        b = (m[j + 2] > m[j + 1]) ? (m[j + 2] - m[j + 1]) : (m[j + 1] - m[j + 2]);
                        t[j] = ((a + b) > 0) ? ((a * m[j + 2] + b * m[j + 3]) / (a + b)) : (0.5f * (m[j + 2] + m[j + 3]));
                    }
                    zf = SelectChannelPixel(row[xi], d);
                    C[i + 2] = zf + (t[0] + ((m[3] + m[3] + m[3] - t[0] - t[0] - t[1]) + (t[0] + t[1] - m[3] - m[3]) * dx) * dx) * dx;
                }
                else
                {
                    xf = xi;
                    C[i + 2] = SelectChannelPixel(row[xf], d);
                }
            }
            zp = 0.0f;
            for(i = -2; i < 4; i++)
            {
                m[i + 2] = C[i + 2] - zp;
                zp = C[i + 2];
            }
            for(i = 0; i < 2; i++)
            {
                a = (m[i + 3] > m[i + 4]) ? (m[i + 3] - m[i + 4]) : (m[i + 4] - m[i + 3]);
                b = (m[i + 2] > m[i + 1]) ? (m[i + 2] - m[i + 1]) : (m[i + 1] - m[i + 2]);
                t[i] = ((a + b) > 0) ? ((a * m[i + 2] + b * m[i + 3]) / (a + b)) : (0.5f * (m[i + 2] + m[i + 3]));
            }
            Cc = C[2] + (t[0] + ((m[3] + m[3] + m[3] - t[0] - t[0] - t[1]) + (t[0] + t[1] - m[3] - m[3]) * dy) * dy) * dy;
        }
        else
        {
            yf = yi;
            row = (QRgb*)img.constScanLine(yf);
            if (dx > 0.0f)
            {
                zp = 0.0f;
                for(j = -2; j < 4; j++)
                {
                    xf = (int)x + j;
                    xf = (xf < 0) ? 0 : (xf < width) ? xf : (width - 1);
                    zf = SelectChannelPixel(row[xf], d);
                    m[j + 2] = zf - zp;
                    zp = zf;
                }
                for(j = 0; j < 2; j++)
                {
                    a = (m[j + 3] > m[j + 4]) ? (m[j + 3] - m[j + 4]) : (m[j + 4] - m[j + 3]);
                    b = (m[j + 2] > m[j + 1]) ? (m[j + 2] - m[j + 1]) : (m[j + 1] - m[j + 2]);
                    t[j] = ((a + b) > 0) ? ((a * m[j + 2] + b * m[j + 3]) / (a + b)) : (0.5f * (m[j + 2] + m[j + 3]));
                }
                zf = SelectChannelPixel(row[xi], d);
                Cc = zf + (t[0] + ((m[3] + m[3] + m[3] - t[0] - t[0] - t[1]) + (t[0] + t[1] - m[3] - m[3]) * dx) * dx) * dx;
            }
            else
            {
                xf = xi;
                Cc = SelectChannelPixel(row[xf], d);
            }
        }
        Ci = (int)(Cc + 0.5f);
        pt[d] = (Ci < 0) ? 0 : (Ci > 255) ? 255 : Ci;
    }
    imgpix = (dn > 3) ? qRgba(pt[0], pt[1], pt[2],  pt[3]) : qRgb(pt[0], pt[1], pt[2]);

    return imgpix;
}

Good luck.

PS: Compare BiAkima and other: Scaler biAkima demo.

See also: stb-image-resize.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.