我写的图像缩放程序(双立方插值算法)

#include <cmath>

typedef struct
{
  unsigned char x;
  unsigned char y;
  unsigned char z;
  unsigned char w;
} uchar4;

#define INT_SCALE  256
#define INT_SCALE_SHF  8

// w0, w1, w2, and w3 are the four cubic B-spline basis functions
__inline long w0_int(long a)
{
  return ((a*(a*(-a + 3*INT_SCALE) - 3*INT_SCALE*INT_SCALE) + INT_SCALE*INT_SCALE*INT_SCALE)/6)>>(INT_SCALE_SHF*2);   // optimized
}

__inline long w1_int(long a)
{
   return ((a*a*(3*a - 6*INT_SCALE) + 4*INT_SCALE*INT_SCALE*INT_SCALE)/6)>>(INT_SCALE_SHF*2);
}

__inline long w2_int(long a)
{
  return ((a*(a*(-3*a + 3*INT_SCALE) + 3*INT_SCALE*INT_SCALE) + INT_SCALE*INT_SCALE*INT_SCALE)/6)>>(INT_SCALE_SHF*2);
}

__inline long w3_int(long a)
{
  return ((a*a*a)/6)>>(INT_SCALE_SHF*2);
}

__inline unsigned long texPick(unsigned long *image, int x, int y, unsigned long p, unsigned long h)
{
  if(x < 0)
    x = 0;
  else if(x >= p)
    x = p - 1;
  if(y < 0)
    y = 0;
  else if (y >= h)
    y = h - 1;

  return image[y * p + x];
}

__inline unsigned long cubicFilter_int(long x, unsigned long c0, unsigned long c1, unsigned long c2, unsigned long c3)
{

  uchar4 *p[4];
  p[0] = (uchar4 *)&c0;
  p[1] = (uchar4 *)&c1;
  p[2] = (uchar4 *)&c2;
  p[3] = (uchar4 *)&c3;

  uchar4 r;

  long w0x = w0_int(x);
  long w1x = w1_int(x);
  long w2x = w2_int(x);
  long w3x = w3_int(x);

  r.x = (p[0]->x * w0x + p[1]->x * w1x + p[2]->x * w2x + p[3]->x * w3x + INT_SCALE / 2) >> INT_SCALE_SHF;

  r.y = (p[0]->y * w0x + p[1]->y * w1x + p[2]->y * w2x + p[3]->y * w3x + INT_SCALE / 2) >> INT_SCALE_SHF;

  r.z = (p[0]->z * w0x + p[1]->z * w1x + p[2]->z * w2x + p[3]->z * w3x + INT_SCALE / 2) >> INT_SCALE_SHF;

  r.w = 0xff;

  return *((unsigned long *)&r);
}

// using 16 texture lookups
__inline unsigned long tex2DBicubic(unsigned long *image, float x, float y, unsigned long pitch4, unsigned long height)
{
  x -= 0.5f;
  y -= 0.5f;
  int px = (int)x;
  int py = (int)y;
  long fx = (x - px) * INT_SCALE + 0.500001f;
  long fy = (y - py) * INT_SCALE + 0.500001f;

  return cubicFilter_int(fy,
               cubicFilter_int(fx, texPick(image, px-1, py-1, pitch4, height), texPick(image, px, py-1, pitch4, height), texPick(image, px+1, py-1, pitch4, height), texPick(image, px+2,py-1, pitch4, height)),
               cubicFilter_int(fx, texPick(image, px-1, py, pitch4, height),   texPick(image, px, py, pitch4, height),   texPick(image, px+1, py, pitch4, height),   texPick(image, px+2, py, pitch4, height)),
               cubicFilter_int(fx, texPick(image, px-1, py+1, pitch4, height), texPick(image, px, py+1, pitch4, height), texPick(image, px+1, py+1, pitch4, height), texPick(image, px+2, py+1, pitch4, height)),
               cubicFilter_int(fx, texPick(image, px-1, py+2, pitch4, height), texPick(image, px, py+2, pitch4, height), texPick(image, px+1, py+2, pitch4, height), texPick(image, px+2, py+2, pitch4, height))
               );
}

UINT AFX_CDECL CPUBicubicThread(LPVOID param)
{
  unsigned long *p = (unsigned long *)param;

  unsigned long *image = (unsigned long *)p[0];
  unsigned long pitch = p[1];
  unsigned long pitch4 = p[1] / 4;
  unsigned long width = p[2];
  unsigned long height = p[3];
  unsigned long y_amount = p[4];
  unsigned long y_start = p[5];
  unsigned long *image_out = (unsigned long *)p[6];
  float scale = *((float *)&p[7]);
  unsigned long pitch_org = p[8];
  unsigned long pitch4_org = p[8] / 4;
  unsigned long height_org = p[9];

  long x, y;

  image_out += pitch4 * y_start;

  for(y = y_start; y < y_start + y_amount; y ++)
  {
    if(y >= height)
      break;

    for(x = 0; x < width; x ++)
    {
      float u = x / scale;
      float v = y / scale;
      image_out[x] = tex2DBicubic(image, u, v, pitch4_org, height_org);
    }
    image_out += pitch4;
  }

  return 0;
}



双立方插值,没什么可解释的,看看photoshop的缩放就知道了。用的是比较常规的方法,目标图像的每个点由原图像相应坐标附近16个点插值得到。主函数我写成线程函数了,就是为了调动几个核一起跑。关键函数是tex2DBicubic。

在E7200双核CPU上能跑出每秒处理1128万像素的速度。

计算过程我全部改成整型计算了。如果用float的话会慢约50%。
+300  科创币    虎哥   2010-01-10   
+200  科创币    我说要有光   2010-01-10    开放源代码的分享
来自 软件综合
 
2010-1-11 13:31:30
1楼
[s:92] 还有速度两倍多倍的GPU版本
折叠评论
加载评论中,请稍候...
折叠评论
2楼
额,提供i7 920OC 4GHZ供测试
折叠评论
加载评论中,请稍候...
折叠评论
小俊(作者)
3楼
我用Geforce GTX285跑这个程序的OpenCL版本(利用纹理单元优化),速度达到每秒23亿像素,是双核E7200的200多倍,是4核QX6600的100多倍。用4GHz的i7估计也要输六七十倍。
折叠评论
加载评论中,请稍候...
折叠评论
2010-1-24 00:17:18
2010-1-24 00:17:18
4楼
白痴问一下,为什么显卡比CPU快那么多?
折叠评论
加载评论中,请稍候...
折叠评论
2010-1-25 21:00:39
2010-1-25 21:00:39
小俊(作者)
5楼
引用第4楼10班陈大葱22号于2010-01-24 00:17发表的  :
白痴问一下,为什么显卡比CPU快那么多?


1、本地存储器带宽超高
2、运算单元超多,能并行调度
折叠评论
加载评论中,请稍候...
折叠评论
2010-1-27 23:48:41
2010-1-27 23:48:41
6楼
双立方插值不是很普遍的算法么...
[s:257]
折叠评论
加载评论中,请稍候...
折叠评论
2010-2-25 14:11:24
2010-2-25 14:11:24
7楼
那现在电脑上的图像咋不用GPU来处理 锕。。
系不系相应的匹配问题啊
折叠评论
加载评论中,请稍候...
折叠评论
8楼
CUDA是最近几年才发展起来的,再加上AMD-ATI的某些问题……
折叠评论
加载评论中,请稍候...
折叠评论
小俊(作者)
9楼
撇开软件环境不讲,旧GPU架构不适合这些较复杂的算法,而新的统一架构是近几年才出现的。
折叠评论
加载评论中,请稍候...
折叠评论
10楼
G80支持CUDA2.0吗?
折叠评论
加载评论中,请稍候...
折叠评论
11楼
G80是计算能力1.0的,不能完全支持CUDA2.x所有特性,但是没有用到这些特性的话也可以跑程序
CUDA2.x特性需要计算能力1.2/1.3的硬件才能完全支持,双精度浮点需要计算能力1.3才能支持
折叠评论
加载评论中,请稍候...
折叠评论
小俊(作者)
12楼
对,跟编译选项有关。只要选择对应的计算能力,无论是哪个CUDA版本对哪个GPU都是可以支持的。
折叠评论
加载评论中,请稍候...
折叠评论
2010-3-2 13:47:34
2010-3-2 13:47:34
13楼
出个beta把
折叠评论
加载评论中,请稍候...
折叠评论
2010-10-18 20:47:10
2010-10-18 20:47:10
14楼
你好,看了您帖出来的代码,我将代码加进vc6下,怎么跑不起来呢?谢谢你的回答
折叠评论
加载评论中,请稍候...
折叠评论
2010-10-19 15:47:46
15楼
回 14楼(soundofwind) 的帖子
这不是C程序,是CUDA程序
折叠评论
加载评论中,请稍候...
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

ID:{{user.uid}}
{{user.username}}
{{user.info.certsName}}
{{user.description}}
{{format("YYYY/MM/DD", user.toc)}}注册,{{fromNow(user.tlv)}}活动
{{submitted?"":"投诉"}}
请选择违规类型:
{{reason.description}}
支持的图片格式:jpg, jpeg, png