package org.jcodec.scale;
import org.jcodec.common.model.Size;
/**
* Resamples image interpolating points using bicubic filter.
*
* The difference from Lanczoc resampler is that a separate set of taps are
* generated for each destination point position.
*
* @author Stanislav Vitvitskiy
*/
public class BicubicResampler extends BaseResampler {
private short[][] horizontalTaps;
private short[][] verticalTaps;
private static double alpha = 0.6;
public BicubicResampler(Size from, Size to) {
super(from, to);
horizontalTaps = buildFilterTaps(to.getWidth(), from.getWidth());
verticalTaps = buildFilterTaps(to.getHeight(), from.getHeight());
}
private static short[][] buildFilterTaps(int to, int from) {
double[] taps = new double[4];
short[][] tapsOut = new short[to][4];
double ratio = (double)from / to;
double toByFrom = (double) to / from;
double srcPos = 0;
for (int i = 0; i < to; i++) {
double fraction = srcPos - (int) srcPos;
for (int t = -1; t < 3; t++) {
double d = t - fraction;
if (to < from) {
d *= toByFrom;
}
double x = Math.abs(d);
double xx = x * x;
double xxx = xx * x;
if (d >= -1 && d <= 1) {
taps[t+1] = (2 - alpha) * xxx + (-3 + alpha) * xx + 1;
} else if (d < -2 || d > 2) {
taps[t+1] = 0;
} else {
taps[t+1] = -alpha * xxx + 5 * alpha * xx - 8 * alpha * x + 4 * alpha;
}
}
normalizeAndGenerateFixedPrecision(taps, 7, tapsOut[i]);
srcPos += ratio;
}
return tapsOut;
}
@Override
protected short[] getTapsX(int dstX) {
return horizontalTaps[dstX];
}
@Override
protected short[] getTapsY(int dstY) {
return verticalTaps[dstY];
}
@Override
protected int nTaps() {
return 4;
}
}