简体   繁体   English

在C语言中将原始24位像素图缩放到大于50%的算法

[英]Algorithm to scale a raw 24 bit pixelmap to greater than 50% in C

Reducing a raw pixelmap to a value of 50% is easy. 将原始像素图减小到50%的值很容易。 I simply slide a 2x2 square across the map and average the RGB components of the 4 pixels as follows: 我只需在地图上滑动2x2的正方形,然后对4个像素的RGB分量进行平均,如下所示:

 img = XGetImage(d_remote,RootWindow(d_remote,0),0,0,attr.width,attr.height,XAllPlanes(),ZPixmap);

   int i;
   int j;
   for(i=0;i<attr.height;i=i+2){
        for(j=0;j<attr.width;j=j+2) {
                unsigned long p1 = XGetPixel(img, j, i);
                unsigned long p1R = p1 & 0x00ff0000;
                unsigned long p1G = p1 & 0x0000ff00;
                unsigned long p1B = p1 & 0x000000ff;

                unsigned long p2 = XGetPixel(img, j+1, i);
                unsigned long p2R = p2 & 0x00ff0000;
                unsigned long p2G = p2 & 0x0000ff00;
                unsigned long p2B = p2 & 0x000000ff;

                unsigned long p3 = XGetPixel(img, j, i+1);
                unsigned long p3R = p3 & 0x00ff0000;
                unsigned long p3G = p3 & 0x0000ff00;
                unsigned long p3B = p3 & 0x000000ff;

                unsigned long p4 = XGetPixel(img, j+1, i+1);
                unsigned long p4R = p4 & 0x00ff0000;
                unsigned long p4G = p4 & 0x0000ff00;
                unsigned long p4B = p4 & 0x000000ff;

                unsigned long averageR = (p1R+p2R+p3R+p4R)/4 & 0x00ff0000;
                unsigned long averageG = (p1G+p2G+p3G+p4G)/4 & 0x0000ff00;
                unsigned long averageB = (p1B+p2B+p3B+p4B)/4 & 0x000000ff;

                int average = averageR | averageG | averageB;

                XPutPixel(newImg, j/2, i/2, average);

        }
   }

This would make a pixelmap that is 500x500 turn into one that is 250x250. 这将使500x500的像素图变成250x250的像素图。 This is a 50% reduction. 这减少了50%。 What if I wanted to scale it by 20%. 如果我想将其缩放20%怎么办? For example I would like my 500x500 image to turn into 400x400? 例如,我想将500x500的图片变成400x400? The smallest square I can slide is a 2x2. 我可以滑动的最小正方形是2x2。 I don't see how I can get a reduction that is not a perfect power of 2. 我看不到如何获得不是2的完美幂的减少量。

Solution: 解:

How's this for effort?? 这是如何努力的? I modified a script I found that does bi-linear interpolation to work on XImages. 我修改了一个脚本,该脚本执行双线性插值以在XImages上工作。 It should work for any generic pixelmap. 它应该适用于任何通用像素图。 I do find the code ugly though since I see images as 2d arrays. 我确实发现代码很丑陋,因为我将图像视为2d数组。 I don't see why all the image code is mapped to a 1d array. 我不明白为什么所有的图像代码都映射到一个1d数组。 It's harder to visualize. 很难想象。 This works for any resize. 这适用于任何大小调整。

void resize(XImage* input, XImage* output, int sourceWidth, int sourceHeight, int targetWidth, int targetHeight)
{
    int a, b, c, d, x, y, index;
    float x_ratio = ((float)(sourceWidth - 1)) / targetWidth;
    float y_ratio = ((float)(sourceHeight - 1)) / targetHeight;
    float x_diff, y_diff, blue, red, green ;
    int offset = 0 ;

    int i=0;
    int j=0;

    int* inputData = (int*)input->data;
    int* outputData = (int*)output->data;
    for (i = 0; i < targetHeight; i++)
    {
        for (j = 0; j < targetWidth; j++)
        {
            x = (int)(x_ratio * j) ;
            y = (int)(y_ratio * i) ;
            x_diff = (x_ratio * j) - x ;
            y_diff = (y_ratio * i) - y ;
            index = (y * sourceWidth + x) ;
            a = inputData[index] ;
            b = inputData[index + 1] ;
            c = inputData[index + sourceWidth] ;
            d = inputData[index + sourceWidth + 1] ;

            // blue element
            blue = (a&0xff)*(1-x_diff)*(1-y_diff) + (b&0xff)*(x_diff)*(1-y_diff) +
                   (c&0xff)*(y_diff)*(1-x_diff)   + (d&0xff)*(x_diff*y_diff);

            // green element
            green = ((a>>8)&0xff)*(1-x_diff)*(1-y_diff) + ((b>>8)&0xff)*(x_diff)*(1-y_diff) +
                    ((c>>8)&0xff)*(y_diff)*(1-x_diff)   + ((d>>8)&0xff)*(x_diff*y_diff);

            // red element
            red = ((a>>16)&0xff)*(1-x_diff)*(1-y_diff) + ((b>>16)&0xff)*(x_diff)*(1-y_diff) +
                  ((c>>16)&0xff)*(y_diff)*(1-x_diff)   + ((d>>16)&0xff)*(x_diff*y_diff);


            outputData[offset++] = (int)red << 16 | (int)green << 8 | (int)blue;
        }
    }
}

Here is some pseudocode for downscaling. 这是一些缩小代码的伪代码。 WS,HS is the target image size WB,HB is the source size. WS,HS是目标图像尺寸WB,HB是源图像尺寸。 WS is less than WB and HS is less than HB. WS小于WB,HS小于HB。

double row[WB];
double Xratio= WB/WS;
double Yratio= HB/HS;

double curYratio= Yratio;
double remainY= Yratio - floor(Yratio);
double remainX= Xratio - floor(Xratio);
double curXratio;

double rfac, cfac;

int icol,irow, orow, ocol;

zero-out row

orow= 0;

for(irow=0..HB-1)
{
  // we find out how much of this row we will add to the current sum
  if (curYratio>=1.0) rfac= 1.0; else rfac= curYratio;

  // we add it
  for(icol=0..WB)     row[icol] += rfac * input[irow][icol];

  // we reduce the total weight 
  curYratio -= rfac;

  // if the total weight is now zero, we have a complete row,
  // otherwise we still need some of the next row
  if (curYratio!=0.0) continue;

  // we have a complete row, compute the weighted average
  for(icol=0..WB-1)   row[icol]/= Yratio; 

  // now we can scale the row in horizontal

  curXratio= Xratio;
  ocol= 0; 
  double pixel= 0.0;
  for(icol=0..WB-1)
  {
    if (curXratio>=1.0)  cfac= 1.0; else cfac= curXratio;
    pixel+= row[icol]*cfac;
    curXratio -= cfac;
    if (curXratio!=0) continue;

    // now we have a complete pixel
    out[orow][ocol]= pixel / Xratio;
    pixel= remainX * row[icol];
    curXratio= Xratio - remainX;   
    ocol++;
  }
  orow++;

  // let's put the remainder of the last input row into 'row'

  for(icol=0..WB-1)     row[i]= remainY*input[irow][icol];
  curYratio= Yratio - remainY;
}

This took longer than I thought it would, but there it is. 这花费的时间比我想象的要长,但确实如此。 Anyway, it's not very wise to run this directly on an input bitmap. 无论如何,直接在输入位图上运行它不是很明智。 You should convert each pixel value to it's sRGB value before doing any arithmetic. 在执行任何算术运算之前,应将每个像素值转换为sRGB值。 The pixel values in a common bitmap are just names for the real values which should be used in computations. 通用位图中的像素值只是应在计算中使用的实值的名称。 Look up sRGB on wikipedia, it has good information. 在Wikipedia上查找sRGB,它具有很好的信息。

If you do it without converting to sRGB and back, you will have a darker image when you scale down. 如果在不转换为sRGB的情况下执行此操作,则按比例缩小时将获得较暗的图像。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM