5
\$\begingroup\$

The following code is to enlarge pictures using bilinear interpolation. What can be modified in the function of slow_rescale to make it more efficient? I expect to modify it from the view of Principles of Computer Organization.

unsigned char *slow_rescale(unsigned char *src, int src_x, int src_y, int dest_x, int dest_y)
{
 double step_x,step_y;          // Step increase as per instructions above
 unsigned char R1,R2,R3,R4;     // Colours at the four neighbours
 unsigned char G1,G2,G3,G4;
 unsigned char B1,B2,B3,B4;
 double RT1, GT1, BT1;          // Interpolated colours at T1 and T2
 double RT2, GT2, BT2;
 unsigned char R,G,B;           // Final colour at a destination pixel
 unsigned char *dst;            // Destination image - must be allocated here! 
 int x,y;               // Coordinates on destination image
 double fx,fy;              // Corresponding coordinates on source image
 double dx,dy;              // Fractional component of source image    coordinates

 dst=(unsigned char *)calloc(dest_x*dest_y*3,sizeof(unsigned char));   // Allocate and clear   destination image
 if (!dst) return(NULL);                           // Unable to allocate image

 step_x=(double)(src_x-1)/(double)(dest_x-1);
 step_y=(double)(src_y-1)/(double)(dest_y-1);

 for (x=0;x<dest_x;x++)         // Loop over destination image
 for (y=0;y<dest_y;y++)
  {
fx=x*step_x;
fy=y*step_y;
dx=fx-(int)fx;
dy=fy-(int)fy;   
getPixel(src,floor(fx),floor(fy),src_x,&R1,&G1,&B1);    // get N1 colours
getPixel(src,ceil(fx),floor(fy),src_x,&R2,&G2,&B2); // get N2 colours
getPixel(src,floor(fx),ceil(fy),src_x,&R3,&G3,&B3); // get N3 colours
getPixel(src,ceil(fx),ceil(fy),src_x,&R4,&G4,&B4);  // get N4 colours
   // Interpolate to get T1 and T2 colours
   RT1=(dx*R2)+(1-dx)*R1;
   GT1=(dx*G2)+(1-dx)*G1;
   BT1=(dx*B2)+(1-dx)*B1;
   RT2=(dx*R4)+(1-dx)*R3;
   GT2=(dx*G4)+(1-dx)*G3;
   BT2=(dx*B4)+(1-dx)*B3;
   // Obtain final colour by interpolating between T1 and T2
   R=(unsigned char)((dy*RT2)+((1-dy)*RT1));
   G=(unsigned char)((dy*GT2)+((1-dy)*GT1));
   B=(unsigned char)((dy*BT2)+((1-dy)*BT1));
  // Store the final colour
  setPixel(dst,x,y,dest_x,R,G,B);
 } 
  return(dst);
}
void getPixel(unsigned char *image, int x, int y, int sx, unsigned char *R, unsigned char *G, unsigned char *B)
{
 // Get the colour at pixel x,y in the image and return it using the provided RGB pointers
 // Requires the image size along the x direction!
 *(R)=*(image+((x+(y*sx))*3)+0);
 *(G)=*(image+((x+(y*sx))*3)+1);
 *(B)=*(image+((x+(y*sx))*3)+2);
}

void setPixel(unsigned char *image, int x, int y, int sx, unsigned char R, unsigned char G, unsigned char B)
{
 // Set the colour of the pixel at x,y in the image to the specified R,G,B
 // Requires the image size along the x direction!
 *(image+((x+(y*sx))*3)+0)=R;
 *(image+((x+(y*sx))*3)+1)=G;
 *(image+((x+(y*sx))*3)+2)=B;
}
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

Please make everyone (including yourself) a favor :

  • Declare your variable in the smallest possible scope. Also define them as your declare them if you can (and you usually can).
  • Indent your code properly.

Then you'd get something like :

unsigned char *slow_rescale(unsigned char *src, int src_x, int src_y, int dest_x, int dest_y)
{
    unsigned char* dst=(unsigned char *)calloc(dest_x*dest_y*3,sizeof(unsigned char));   // Allocate and clear destination image
    if (!dst) return(NULL); // Unable to allocate image

    double step_x=(double)(src_x-1)/(double)(dest_x-1);
    double step_y=(double)(src_y-1)/(double)(dest_y-1);

    for (int x=0;x<dest_x;x++) // Loop over destination image
    {
        for (int y=0;y<dest_y;y++)
        {
            double fx=x*step_x;
            double fy=y*step_y;
            double dx=fx-(int)fx;
            double dy=fy-(int)fy;

            unsigned char R1,R2,R3,R4; // Colours at the four neighbours
            unsigned char G1,G2,G3,G4;
            unsigned char B1,B2,B3,B4;

            getPixel(src,floor(fx),floor(fy),src_x,&R1,&G1,&B1); // get N1 colours
            getPixel(src,ceil(fx),floor(fy),src_x,&R2,&G2,&B2); // get N2 colours
            getPixel(src,floor(fx),ceil(fy),src_x,&R3,&G3,&B3); // get N3 colours
            getPixel(src,ceil(fx),ceil(fy),src_x,&R4,&G4,&B4);  // get N4 colours
            // Interpolate to get T1 and T2 colours
            double RT1=(dx*R2)+(1-dx)*R1;
            double GT1=(dx*G2)+(1-dx)*G1;
            double BT1=(dx*B2)+(1-dx)*B1;
            double RT2=(dx*R4)+(1-dx)*R3;
            double GT2=(dx*G4)+(1-dx)*G3;
            double BT2=(dx*B4)+(1-dx)*B3;
            // Obtain final colour by interpolating between T1 and T2
            unsigned char R=(unsigned char)((dy*RT2)+((1-dy)*RT1));
            unsigned char G=(unsigned char)((dy*GT2)+((1-dy)*GT1));
            unsigned char B=(unsigned char)((dy*BT2)+((1-dy)*BT1));
            // Store the final colour
            setPixel(dst,x,y,dest_x,R,G,B);
        }
    }
    return(dst);
}
void getPixel(unsigned char *image, int x, int y, int sx, unsigned char *R, unsigned char *G, unsigned char *B)
{
    // Get the colour at pixel x,y in the image and return it using the provided RGB pointers
    // Requires the image size along the x direction!
    *(R)=*(image+((x+(y*sx))*3)+0);
    *(G)=*(image+((x+(y*sx))*3)+1);
    *(B)=*(image+((x+(y*sx))*3)+2);
}

void setPixel(unsigned char *image, int x, int y, int sx, unsigned char R, unsigned char G, unsigned char B)
{
    // Set the colour of the pixel at x,y in the image to the specified R,G,B
    // Requires the image size along the x direction!
    *(image+((x+(y*sx))*3)+0)=R;
    *(image+((x+(y*sx))*3)+1)=G;
    *(image+((x+(y*sx))*3)+2)=B;
}

Then, try to compute things once and only once when possible and you'll get something like :

unsigned char *slow_rescale(unsigned char *src, int src_x, int src_y, int dest_x, int dest_y)
{
    unsigned char* dst=(unsigned char *)calloc(dest_x*dest_y*3,sizeof(unsigned char));   // Allocate and clear destination image
    if (!dst) return(NULL); // Unable to allocate image

    double step_x=(double)(src_x-1)/(double)(dest_x-1);
    double step_y=(double)(src_y-1)/(double)(dest_y-1);

    for (int x=0;x<dest_x;x++) // Loop over destination image
    {
        double fx=x*step_x;
        double dx=fx-(int)fx;
        int ffx = floor(fx);
        int cfx = ceil(fx);
        for (int y=0;y<dest_y;y++)
        {
            double fy=y*step_y;
            double dy=fy-(int)fy;
            int ffy = floor(fy);
            int cfy = ceil(fy);

            unsigned char R1,R2,R3,R4,G1,G2,G3,G4,B1,B2,B3,B4;

            getPixel(src, (ffx + ffy*src_x)*3, &R1,&G1,&B1); // get N1 colours
            getPixel(src, (cfx + ffy*src_x)*3, &R2,&G2,&B2); // get N2 colours
            getPixel(src, (ffx + cfy*src_x)*3, &R3,&G3,&B3); // get N3 colours
            getPixel(src, (cfx + cfy*src_x)*3, &R4,&G4,&B4); // get N4 colours
            // Interpolate to get T1 and T2 colours
            double RT1 = dx*R2 + (1-dx)*R1;
            double GT1 = dx*G2 + (1-dx)*G1;
            double BT1 = dx*B2 + (1-dx)*B1;
            double RT2 = dx*R4 + (1-dx)*R3;
            double GT2 = dx*G4 + (1-dx)*G3;
            double BT2 = dx*B4 + (1-dx)*B3;
            // Obtain final colour by interpolating between T1 and T2
            unsigned char R = dy*RT2 + (1-dy)*RT1;
            unsigned char G = dy*GT2 + (1-dy)*GT1;
            unsigned char B = dy*BT2 + (1-dy)*BT1;
            // Store the final colour
            setPixel(dst, (x + y*dest_x)*3,R,G,B);
        }
    }
    return(dst);
}

inline void getPixel(unsigned char *image, int offset, unsigned char *R, unsigned char *G, unsigned char *B)
{
    *R=image[offset+0];
    *G=image[offset+1];
    *B=image[offset+2];
}

inline void setPixel(unsigned char *image, int offset, unsigned char R, unsigned char G, unsigned char B)
{
    image[offset+0]=R;
    image[offset+1]=G;
    image[offset+2]=B;
}

I'd expect this to be much much faster than your original code and to do roughtly the same thing (I have have introduced errors though).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.