使用缓冲区缩小/插入图像的算法?

时间:2016-10-06 06:23:24

标签: c++

我试图将图像从大尺寸(大到960x960)缩小到可能小到32x32。我使用以下代码来获取原始像素:

    Image* img = new Image();
    img->initWithImageFile(fileNameWithPath);
    int x=3;
    if(img->hasAlpha()){
        x=4;
    }

    unsigned char *data = new unsigned char[img->getDataLen()*x];
    data = img->getData();
    // [0][0] => Left-Top Pixel !
    // But cocos2d Location Y-axis is Bottom(0) to Top(max)

    //This is for changing pixels in the original image
    //Skip this loop if there are no changes to be made (converting to grayscale etc).
    for(int i=0;i<img->getWidth();i++)
    {
        for(int j=0;j<img->getHeight();j++)
        {
            unsigned char *pixel = data + (i + j * img->getWidth()) * x;

            // You can see/change pixels' RGBA value(0-255) here !
            unsigned char r = *pixel;
            unsigned char g = *(pixel + 1);
            unsigned char b = *(pixel + 2) ;
            unsigned char a = *(pixel + 3);

            //pixel[2] = 255; //Example: Setting the blue component to 255
        }
    }

我可以通过执行以下操作来创建输出图像:

        int width = scale*img->getWidth();
        int height = scale*img->getHeight();
        Image* scaledImage = new Image();
        auto dataLen = width * height * x * sizeof(unsigned char);
        auto data2 = static_cast<unsigned char*>(malloc(dataLen));
        scaledImage->initWithRawData(data2, dataLen, width, height, 8);

我可以通过执行以下操作来设置输出图像的各个像素:

            unsigned char *pixel2 = data2 + (i + j * width) * x;

问题是如何有效地平均/插入原始图像中的像素(使用最小的cpu和内存,如果需要,优先使用更多的cpu和更少的内存)。

挑战:

  1. 缩小的图像和原始图像可能不完美 倍数。
  2. 缩小的图像可以小到0.1 原始图片大小。
  3. 大多数图像将缩小为原始图像的0.4到0.1,因此这些是最重要的范围。
  4. 编辑:如果你认为其他一些插值算法更适合(而不是双线性),那么我愿意接受它。挑战在于编写一种有效的算法来平均/插入各个像素。

    如何插入原始图像的各个像素?

1 个答案:

答案 0 :(得分:2)

内存不是问题,你需要一个带有原始图像的输入缓冲区和一个带有重新缩放图像的输出缓冲区,你不需要了。

双线性插值不太适合用于较大因子的下采样,因为它与最近采样没有实际差别。您只插入四个相邻像素,因此容易受到锯齿效果的影响,特别是在计算机生成的图像上。

此功能使用平均方法。

 /*
  resize an image using the averaging method.
  Note that dwidth and dheight must be smaller than or equal to swidth, sheight.

 */
void sprshrink(unsigned char *dest, int dwidth, int dheight, unsigned char *src, int swidth, int sheight)
{
  int x, y;
  int i, ii;
  float red, green, blue, alpha;
  float xfrag, yfrag, xfrag2, yfrag2;
  float xt, yt, dx, dy;
  int xi, yi;


  dx = ((float)swidth)/dwidth;
  dy = ((float)sheight)/dheight;

  for(yt= 0, y=0;y<dheight;y++, yt += dy)
  {
    yfrag = ceil(yt) - yt;
    if(yfrag == 0)
      yfrag = 1;
    yfrag2 = yt+dy - (float) floor(yt + dy);
    if(yfrag2 == 0 && dy != 1.0f)
      yfrag2 = 1;

    for(xt = 0, x=0;x<dwidth;x++, xt+= dx)
    {
      xi = (int) xt;
      yi = (int) yt;
      xfrag = (float) ceil(xt) - xt;
     if(xfrag == 0)
       xfrag = 1;
      xfrag2 = xt+dx - (float) floor(xt+dx);
     if(xfrag2 == 0 && dx != 1.0f)
        xfrag2 = 1;
      red = xfrag * yfrag * src[(yi*swidth+xi)*4];
      green =  xfrag * yfrag * src[(yi*swidth+xi)*4+1];
      blue =   xfrag * yfrag * src[(yi*swidth+xi)*4+2];
      alpha =  xfrag * yfrag * src[(yi*swidth+xi)*4+3];

      for(i=0; xi + i + 1 < xt+dx-1; i++)
      {
        red += yfrag * src[(yi*swidth+xi+i+1)*4];
        green += yfrag * src[(yi*swidth+xi+i+1)*4+1];
        blue += yfrag * src[(yi*swidth+xi+i+1)*4+2];
        alpha += yfrag * src[(yi*swidth+xi+i+1)*4+3];
      } 

      red += xfrag2 * yfrag * src[(yi*swidth+xi+i+1)*4];
      green += xfrag2 * yfrag * src[(yi*swidth+xi+i+1)*4+1];
      blue += xfrag2 * yfrag * src[(yi*swidth+xi+i+1)*4+2];
      alpha += xfrag2 * yfrag * src[(yi*swidth+xi+i+1)*4+3];


      for(i=0; yi+i+1 < yt +dy-1 && yi + i+1 < sheight;i++)
      {
        red += xfrag * src[((yi+i+1)*swidth+xi)*4];
        green += xfrag * src[((yi+i+1)*swidth+xi)*4+1];
        blue += xfrag * src[((yi+i+1)*swidth+xi)*4+2];
        alpha += xfrag * src[((yi+i+1)*swidth+xi)*4+3];

        for (ii = 0; xi + ii + 1 < xt + dx - 1 && xi + ii + 1 < swidth; ii++)
        {
          red += src[((yi+i+1)*swidth+xi+ii+1)*4];
          green += src[((yi+i+1)*swidth+xi+ii+1)*4+1];
          blue += src[((yi+i+1)*swidth+xi+ii+1)*4+2];
          alpha += src[((yi+i+1)*swidth+xi+ii+1)*4+3];
        }

          if (yi + i + 1 < sheight && xi + ii + 1 < swidth)
          {
              red += xfrag2 * src[((yi+i+1)*swidth+xi+ii+1)*4];
              green += xfrag2 * src[((yi+i+1)*swidth+xi+ii+1)*4+1];
              blue += xfrag2 * src[((yi+i+1)*swidth+xi+ii+1)*4+2];
              alpha += xfrag2 * src[((yi+i+1)*swidth+xi+ii+1)*4+3];
          }
      }

      if (yi + i + 1 < sheight)
      {
          red += xfrag * yfrag2 * src[((yi + i + 1)*swidth + xi) * 4];
          green += xfrag * yfrag2 * src[((yi + i + 1)*swidth + xi) * 4 + 1];
          blue += xfrag * yfrag2 * src[((yi + i + 1)*swidth + xi) * 4 + 2];
          alpha += xfrag * yfrag2 * src[((yi + i + 1)*swidth + xi) * 4 + 3];

          for (ii = 0; xi + ii + 1 < xt + dx - 1 && xi + ii + 1 < swidth; ii++)
          {
              red += yfrag2 * src[((yi + i + 1)*swidth + xi + ii + 1) * 4];
              green += yfrag2 * src[((yi + i + 1)*swidth + xi + ii + 1) * 4 + 1];
              blue += yfrag2 * src[((yi + i + 1)*swidth + xi + ii + 1) * 4 + 2];
              alpha += yfrag2 * src[((yi + i + 1)*swidth + xi + ii + 1) * 4 + 3];
          }
      }

      if (yi + i + 1 < sheight && xi + ii + 1 < swidth)
      {
          red += xfrag2 * yfrag2 * src[((yi + i + 1)*swidth + xi + ii + 1) * 4];
          green += xfrag2 * yfrag2 * src[((yi + i + 1)*swidth + xi + ii + 1) * 4 + 1];
          blue += xfrag2 * yfrag2 * src[((yi + i + 1)*swidth + xi + ii + 1) * 4 + 2];
          alpha += xfrag2 * yfrag2 * src[((yi + i + 1)*swidth + xi + ii + 1) * 4 + 3];
      }


     red /= dx * dy;
     green /= dx * dy;
     blue /= dx * dy;
     alpha /= dx * dy;

     red = clamp(red, 0, 255);
     green = clamp(green, 0, 255);
     blue = clamp(blue, 0, 255);
     alpha = clamp(alpha, 0, 255);

     dest[(y*dwidth+x)*4] = (unsigned char) red;
     dest[(y*dwidth+x)*4+1] = (unsigned char) green;
     dest[(y*dwidth+x)*4+2] = (unsigned char) blue;
     dest[(y*dwidth+x)*4+3] = (unsigned char) alpha;
    }
  }


}

它在github上的Baby X资源编译器中维护。

https://github.com/MalcolmMcLean/babyxrc