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

拉胡尔·艾耶(Rahul Iyer)

我正在尝试将图像从大尺寸(大至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,因此这是最重要的范围。

编辑:如果您认为其他插值算法会更适合(而不是双线性),那么我可以接受。面临的挑战是编写一种有效的算法来对各个像素进行平均/内插。

如何对原始图像的各个像素进行插值?

马尔科姆·麦克莱恩(Malcolm McLean)

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

由于双线性插值与最近的采样并没有太大的区别,因此它不太适合于大幅下采样。您只能插值四个相邻像素,因此容易受到锯齿效果的影响,尤其是在计算机生成的图像上。

此功能使用平均方法。

 /*
  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

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

使用缓冲区提供图像文件-损坏的图像

来自分类Dev

如何获取转换后图像的缓冲区值

来自分类Dev

实现Z缓冲区算法

来自分类Dev

何时使用数组,缓冲区或直接缓冲区

来自分类Dev

使用libpng 1.2将RGB图像缓冲区写入内存中的PNG缓冲区导致分段错误

来自分类Dev

从url下载图像并放入缓冲区

来自分类Dev

使用完整缓冲区的生产者-消费者算法

来自分类Dev

无法使TClientSocket接收缓冲区值

来自分类Dev

python PIL图像如何将图像保存到缓冲区,以便以后使用?

来自分类Dev

缓冲区较小时的简单混响算法

来自分类Dev

从 IntPtr 缓冲区创建图像后,图像需要翻转

来自分类Dev

使用WriteableBitmap的缓冲区大小不足?

来自分类Dev

在Android AudioTrack中使用缓冲区

来自分类Dev

使用OpenCL获取OpenGL缓冲区

来自分类Dev

使用删除[]导致缓冲区溢出

来自分类Dev

使用strcpy的基本缓冲区溢出

来自分类Dev

在Android AudioTrack中使用缓冲区

来自分类Dev

/记忆/使用中间缓冲区吗?

来自分类Dev

缓冲区使用哪种硬件

来自分类Dev

在磁盘上使用循环缓冲区

来自分类Dev

使用 memcpy 处理缓冲区

来自分类Dev

使用 Cocoa 渲染像素缓冲区

来自分类Dev

使用 Vader 测试缓冲区列表

来自分类Dev

如何使用LEADTOOLS 19将图像效果应用于内存缓冲区中的JPEG

来自分类Dev

图像未使用android中的缓冲区读取器存储在服务器上

来自分类Dev

Java 映射字节缓冲区 - 缓冲区中的垃圾值

来自分类Dev

Android如何将int值写入缓冲区并使用计时器从缓冲区中获取值?

来自分类Dev

使用深度缓冲区时将值重新绘制到屏幕

来自分类Dev

C ++在带有右值缓冲区的ostream中使用snprintf,这格式正确吗?

Related 相关文章

热门标签

归档