Reputation: 1148
Seems that bicubic interpolation works only for upscale. I have tried these functions: http://jsperf.com/pixel-interpolation/4 and http://www.reddit.com/r/javascript/comments/jxa8x/bicubic_interpolation/
Also I've tried an algorithm for Bicubic Interpolation from Gernot Hoffmann's book "Interpolations for Image Warping".
But all images after scaling down using above methods looks like they were interpolated by near neighbor.
Maybe am I wrong in something?
I've also noticed that in Photoshop there are two separate options for bicubic interpolation: Bicubic Smoother (for upscale) and Bicubic Sharper (for downscale).
So maybe somebody knows an algorithm of bicubic interpolation for downscale?
Upvotes: 2
Views: 3380
Reputation: 2399
I just wrote an algorithm for bicubic interpolition... I works well. before you run it, changes the some values according to your image;
ROW & COLUMN
#define ROW 218 //change 218 to your image's horizantol pixels
#define COLUMN 329` //change 329 to your image's vertical pixels
ZOOM_RATE & ZOOM_NUM
ZOOM_RATE is the rate of your image's resizing if you want to dublicate it then make it "2"
ZOOM_NUM=1/ZOOM_RATE -> ZOOM_NUM is equal to 1 over ZOOM_RATE
the name name and extension of image
in the int main() function change
readPpm("irfan.ppm"); //change irfan to your image's name
here is the source code:(this codes has also bilinear interpolition, so you can compare your results)
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <string.h>
#include <string>
#include <sstream>
#include <string.h>
#include <vector>
#include <math.h>
using namespace std;
#define ROW 218
#define COLUMN 329
#define ZOOM_RATE 2
#define ZOOM_NUM 1/2
struct POINT { // Declare POINT structure
int x; // Define members x and y
int y;
int renk;
} ; // Variable spot has
// values x = 20, y = 40
typedef struct POINT coordinate; // Variable there has POINT type
int int_arr[ROW][COLUMN*3];
int int_arr_simple[ROW][COLUMN];
int zoom_photo[(int)(ROW*ZOOM_RATE)][(int)(COLUMN*ZOOM_RATE)];
int zoom_photo_bicubic[(int)(ROW*ZOOM_RATE)][(int)(COLUMN*ZOOM_RATE)];
string filetype;
string comment;
string size;
string colorrange;
int line_find(int ,int,int,int,float);
void save2Ppm(string filename,int pixel[ROW][COLUMN*3],int size);
void save2Pgm(string filename,int pixel[ROW][COLUMN],int size);
void save2Pgm_zoom(string filename,int pixel[ROW*ZOOM_RATE][COLUMN*ZOOM_RATE],int size);
void readPpm(string);
void zooming();
void zooming_bilinear();
void zooming_bicubic();
int bicubic_function(float x_cor,float y_cor);
void save2Pgm_zoom(string filename,int pixel[ROW*ZOOM_RATE][COLUMN*ZOOM_RATE],int size){
ofstream Picture;
Picture.open(filename);
Picture<<"P2\n#"<<filename<<"\n"<<(int)(COLUMN*ZOOM_RATE)<<" "<<(int)(ROW*ZOOM_RATE)<<"\n"<<size<<"\n";
for(int i=0 ; i<ROW*ZOOM_RATE ; i++)
{
for(int j=0; j<COLUMN*ZOOM_RATE; j++){
Picture<<pixel[i][j]<<" ";
}
}
Picture.close();
}
void zooming(){
for(int i=0;i<ROW*ZOOM_RATE;i++){
for(int j=0;j<COLUMN*ZOOM_RATE;j++){
zoom_photo[i][j]=int_arr_simple[i*ZOOM_NUM][j*ZOOM_NUM];
}
}
}
void save2Pgm(string filename,int pixel[ROW][COLUMN],int size){
ofstream Picture;
Picture.open(filename);
Picture<<"P2\n#"<<filename<<"\n"<<COLUMN<<" "<<ROW<<"\n"<<size<<"\n";
for(int i=0 ; i<ROW ; i++)
{
for(int j=0; j<COLUMN; j++){
Picture<<pixel[i][j]<<" ";
}
}
Picture.close();
}
void save2Ppm(string filename,int pixel[ROW][COLUMN*3],int size){
ofstream Picture;
Picture.open(filename);
Picture<<"P3\n#"<<filename<<"\n"<<COLUMN<<" "<<ROW<<"\n"<<size<<"\n";
for(int i=0 ; i<ROW ; i++)
{
for(int j=0; j<COLUMN*3; j++){
Picture<<pixel[i][j]<<" ";
}
}
Picture.close();
}
void readPpm(string filename){
ifstream Picture(filename);
//Picture.open(filename);
char take[10000];
if(!Picture)
printf("FILE NOT OPEN!!!!!!\n");
else
{
Picture.getline( take, 10000 );
for(int i = 0; take[i] != 0; i++)
filetype += take[i];
Picture.getline( take, 10000 );
for(int i = 0; take[i] != 0; i++)
comment += take[i];
Picture.getline( take, 10000 );
for(int i = 0; take[i] != 0; i++)
size += take[i];
Picture.getline( take, 10000 );
for(int i = 0; take[i] != 0; i++)
colorrange += take[i];
Picture.getline( take, 10000 ,' ');
int_arr[0][0]=atoi(take);
for(int i=1,j=0,t=0;i<ROW*COLUMN*3;i++){
Picture.getline( take, 10000 ,' ');
t=i%(COLUMN*3);
if(i%(COLUMN*3)==0)
j++;
int_arr[j][t]=atoi(take);
int_arr_simple[j][t/3]=int_arr[j][t];
}
Picture.close();
}
}
void zooming_bilinear(){
double x,y;
double result_x,result_y,result;
double x_1,x1;
double y_1,y1;
for(int i=0;i<ROW*ZOOM_RATE;i++){
for(int j=0;j<COLUMN*ZOOM_RATE;j++){
y=(double)ZOOM_NUM*i;
x=(double)ZOOM_NUM*j;
x_1 = (int)x; y_1 = (int)y;
x1 = (int)(x+1); y1 = (int)(y+1);
result_x=(double)(x1-x)*int_arr_simple[(int)y_1][(int)x_1]/(double)(x1-x_1) + (double)(x-x_1)*int_arr_simple[(int)y_1][(int)x1]/(double)(x1-x_1);
result_y=(double)(x1-x)*int_arr_simple[(int)y1][(int)x_1] /(double)(x1-x_1) + (double)(x-x_1)*int_arr_simple[(int)y1][(int)x_1]/(double)(x1-x_1);
result=(double)(y1-y)*result_x/(double)(y1-y_1) + (double)(y-y_1)*result_y /(double)(y1-y_1 );
zoom_photo[i][j]=result;
}
}
}
void zooming_bicubic(){
double x,y;
double result_x,result_y,result;
double x_1,x1;
double y_1,y1;
//zoom 16 pixel arasında olduğu için verileri atmaya 2,2 den başlıyor ve 2 birim önce bitiyor...
for(int i=1;i<ROW*ZOOM_RATE-1;i++){
for(int j=1;j<COLUMN*ZOOM_RATE-1;j++){
zoom_photo_bicubic[i][j]=bicubic_function((float)ZOOM_NUM*j,(float)ZOOM_NUM*i);
}
}
}
int bicubic_function(float x_cor,float y_cor){//bicubic yöntemle renk döndürmek için kullanılan fonksiyon
coordinate nokta[4][4];
int result;//en sonunda rengi döndüren variable
nokta[0][0].x=(int)y_cor-1; nokta[0][0].y=(int)x_cor-1;
nokta[0][1].x=(int)y_cor-1; nokta[0][1].y=(int)x_cor;
nokta[0][2].x=(int)y_cor-1; nokta[0][2].y=(int)x_cor+1;
nokta[0][3].x=(int)y_cor-1; nokta[0][3].y=(int)x_cor+2;
nokta[1][0].x=(int)y_cor; nokta[1][0].y=(int)x_cor-1;
nokta[1][1].x=(int)y_cor; nokta[1][1].y=(int)x_cor;
nokta[1][2].x=(int)y_cor; nokta[1][2].y=(int)x_cor+1;
nokta[1][3].x=(int)y_cor; nokta[1][3].y=(int)x_cor+2;
nokta[2][0].x=(int)y_cor+1; nokta[2][0].y=(int)x_cor-1;
nokta[2][1].x=(int)y_cor+1; nokta[2][1].y=(int)x_cor;
nokta[2][2].x=(int)y_cor+1; nokta[2][2].y=(int)x_cor+1;
nokta[2][3].x=(int)y_cor+1; nokta[2][3].y=(int)x_cor+2;
nokta[3][0].x=(int)y_cor+2; nokta[3][0].y=(int)x_cor-1;
nokta[3][1].x=(int)y_cor+2; nokta[3][1].y=(int)x_cor;
nokta[3][2].x=(int)y_cor+2; nokta[3][2].y=(int)x_cor+1;
nokta[3][3].x=(int)y_cor+2; nokta[3][3].y=(int)x_cor+2;
float xline_1,xline_2,xline_3,xline_4;
int P00,P01,P02,P03;
P00=int_arr_simple[nokta[0][0].x][nokta[0][0].y-1];
P01=int_arr_simple[nokta[0][1].x][nokta[0][1].y-1];
P02=int_arr_simple[nokta[0][2].x][nokta[0][2].y-1];
P03=int_arr_simple[nokta[0][3].x][nokta[0][3].y-1];
int P10,P11,P12,P13;
P10=int_arr_simple[nokta[1][0].x][nokta[1][0].y-1];
P11=int_arr_simple[nokta[1][1].x][nokta[1][1].y-1];
P12=int_arr_simple[nokta[1][2].x][nokta[1][2].y-1];
P13=int_arr_simple[nokta[1][3].x][nokta[1][3].y-1];
int P20,P21,P22,P23;
P20=int_arr_simple[nokta[2][0].x][nokta[2][0].y-1];
P21=int_arr_simple[nokta[2][1].x][nokta[2][1].y-1];
P22=int_arr_simple[nokta[2][2].x][nokta[2][2].y-1];
P23=int_arr_simple[nokta[2][3].x][nokta[2][3].y-1];
int P30,P31,P32,P33;
P30=int_arr_simple[nokta[3][0].x][nokta[3][0].y-1];
P31=int_arr_simple[nokta[3][1].x][nokta[3][1].y-1];
P32=int_arr_simple[nokta[3][2].x][nokta[3][2].y-1];
P33=int_arr_simple[nokta[3][3].x][nokta[3][3].y-1];
xline_1=line_find(P00,P01,P02,P03, x_cor-(int)x_cor);
xline_2=line_find(P10,P11,P12,P13, x_cor-(int)x_cor);
xline_3=line_find(P20,P21,P22,P23, x_cor-(int)x_cor);
xline_4=line_find(P30,P31,P32,P33, x_cor-(int)x_cor);
result=line_find(xline_1,xline_2,xline_3,xline_4,y_cor-(int)y_cor);
return result;
}
int line_find(int P0,int P1,int P2,int P3, float x) { // bir denklemin "rengini" çevirmek için kullanılır....
float A,B,C,D,result;
A=(float)(-(float)1/2)*(float)P0 + ((float)3/2)*(float)P1 + (-(float)3/2)*(float)P2 + ((float)1/2)*(float)P3 ;
B=(float)P0 + (-(float)5/2)*(float)P1 + (2)*(float)P2 + (-(float)1/2)*(float)P3 ;
C=(-(float)1/2)*(float)P0 + ((float)1/2)*(float)P2 ;
D=(float)P1 ;
result=A*x*x*x + B*x*x + C*x + D ;
return result;
}
int main (){
readPpm("irfan.ppm");
save2Ppm("ppm",int_arr,255);
save2Pgm("pgm",int_arr_simple,255);
zooming_bilinear();
save2Pgm_zoom("zoom_bilinear",zoom_photo,255);
zooming_bicubic();
save2Pgm_zoom("zoom_bicubic",zoom_photo_bicubic,255);
return 0;
}
Upvotes: 2