heptagonhust / bicubic-image-resize Goto Github PK
View Code? Open in Web Editor NEWCodebase for recruitment of 2022 autumn.
Codebase for recruitment of 2022 autumn.
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
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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.