存档

文章标签 ‘Bicubic’

CxImage库Resample函数插值优化

2011年9月14日 没有评论

最近用了下图像操作库cximage。这库不错,免费开源。修改下bcb,vc都能用。

唯一的主要毛病可能就算是优化不给力了。

使用中,对其resample函数的插值算法尤其头痛,随便一个pdg图像,200%缩放,花费10-20s是常事。因此不得不硬着头皮对其进行优化。

优化中能想起来的使用过 定点替换浮点,循环展开,区域缓存,查表等等。

优化后效果还不错。
bicubic 24bit图像能实现2178×2976 2倍放大耗时 1.8s左右
bicubic 1bit 图像能实现2178×2976 2倍放大耗时 2.6s左右

bilinear 24bit图像能实现2178×2976 2倍放大耗时 0.78s左右
bilinear 1bit 图像能实现2178×2976 2倍放大耗时 1.31s左右

以上测试数据基于T6400 CPU,优化基于cximage 7.02.

当然肯定还有优化空间,例如源码进一步优化以及mmx,sse优化等等,不过暂时本人是没啥辙了,能力有限,只能到这个地步。

这里贴出改过之后的ximatran.cpp
PS:KernelBSpline函数也改成了定点版本,所以这个函数需要自己去改下,不在ximatran.cpp里
修改后的ximatran.cpp

分类: Computer 标签: , ,

CxImage bicubic插值算法优化

2011年9月6日 没有评论

CxImage是个好东西,开源,支持图片种类多,操作花样多,如果非要说缺点的话,那估计只有1个,效率低下,尤其某些图形处理算法效率更低,无任何优化。

这里说到的是CxImage的bicubic插值算法的优化。

Bicubic插值,对与目标图形的某个点,需要其源图像对应点周围的16个点参与计算,因此计算量很大,并且还是浮点运算。

就优化而言,有多种途径,浮点转定点,浮点数转整数,sse等。这里说到的优化方法是浮点转定点,浮点数转整数。

基本思想是,用整数近视替代浮点数,精度是1/256,即将任一浮点数向精度1/256的整数倍靠近,之后计算bicubic函数的权重数据,存到表格里。bicubic插值时查表即可。
CxImage的原bicubic插值函数片段是

//		float f_x, f_y, a, b, rr, gg, bb, r1, r2;
//		int32_t   i_x, i_y, xx, yy;
//		RGBQUAD rgb;
//		uint8_t* iDst;
//		for(int32_t y=0; y<newy; y++){
//			info.nProgress = (int32_t)(100*y/newy);
//			if (info.nEscape) break;
//			f_y = (float) y * yScale - 0.5f;
//			i_y = (int32_t) floor(f_y);
//			a   = f_y - (float)floor(f_y);
//			for(int32_t x=0; x<newx; x++){
//				f_x = (float) x * xScale - 0.5f;
//				i_x = (int32_t) floor(f_x);
//				b   = f_x - (float)floor(f_x);
//
//				rr = gg = bb = 0.0f;
//				for(int32_t m=-1; m<3; m++) {
//					r1 = KernelBSpline((float) m - a);
//					yy = i_y+m;
//					if (yy<0) yy=0;
//					if (yy>=head.biHeight) yy = head.biHeight-1;
//					for(int32_t n=-1; n<3; n++) {
//						r2 = r1 * KernelBSpline(b - (float)n);
//						xx = i_x+n;
//						if (xx<0) xx=0;
//						if (xx>=head.biWidth) xx=head.biWidth-1;
//
//						if (head.biClrUsed){
//							rgb = GetPixelColor(xx,yy);
//						} else {
//							iDst  = info.pImage + yy*info.dwEffWidth + xx*3;
//							rgb.rgbBlue = *iDst++;
//							rgb.rgbGreen= *iDst++;
//							rgb.rgbRed  = *iDst;
//						}
//
//						rr += rgb.rgbRed * r2;
//						gg += rgb.rgbGreen * r2;
//						bb += rgb.rgbBlue * r2;
//					}
//				}
//
//				if (head.biClrUsed)
//					newImage.SetPixelColor(x,y,RGB(rr,gg,bb));
//				else {
//					iDst = newImage.info.pImage + y*newImage.info.dwEffWidth + x*3;
//					*iDst++ = (uint8_t)bb;
//					*iDst++ = (uint8_t)gg;
//					*iDst   = (uint8_t)rr;
//				}
//
//			}
//		}
//		break;

以下是经过初步优化的代码,其中s_BicubicTblX,s_BicubicTblY是两个预先计算好的权重表

		//float f_x, f_y, a, b, rr, gg, bb, r1, r2;
		int32_t   i_x, i_y, xx, yy, a, b, r_x, r_y;
		int32_t r1,r2;
		int32_t rr,gg,bb;
		uint8_t r_r,g_g,b_b;
		RGBQUAD rgb;
		uint8_t* iDst;
		uint8_t* iSrc;
 
		r_x = (int32_t)((float)(head.biWidth << 8)/((float)newx)+0.5);
		r_y = (int32_t)((float)(head.biHeight << 8)/((float)newy)+0.5);
 
 
		for(int32_t y=0; y<newy; y++){
			info.nProgress = (int32_t)(100*y/newy);
			if (info.nEscape) break;
 
 
			i_y = (y*r_y) >> 8;
			a   = (uint8_t)(y*r_y);
			for(int32_t x=0; x<newx; x++){
				i_x = (x*r_x) >> 8;
				b   = (uint8_t)(x*r_x);
 
				rr = gg = bb = 0;
				for(int32_t m=0; m<4; m++) {
 
					r1 = s_BicubicTblY[m][a];
					yy = i_y+m;
					if (yy<0) yy=0;
					if (yy>=head.biHeight) yy = head.biHeight-1;
 
					for(int32_t n=0; n<4; n++) {
						r2 = s_BicubicTblX[n][b];
						xx = i_x+n;
						if (xx<0) xx=0;
						if (xx>=head.biWidth) xx=head.biWidth-1;
 
						if (head.biClrUsed){
							rgb = GetPixelColor(xx,yy);
						} else {
							iSrc  = info.pImage + yy*info.dwEffWidth + xx*3;
							//memcpy(&rgb,iSrc,3);
							rgb.rgbBlue = *iSrc++;
							rgb.rgbGreen= *iSrc++;
							rgb.rgbRed  = *iSrc;
						}
 
						rr += rgb.rgbRed * r1 * r2;
						gg += rgb.rgbGreen * r1 * r2;
						bb += rgb.rgbBlue * r1 * r2;
					}
				}
				bb = ((bb<=0)-1) & bb;
				gg = ((gg<=0)-1) & gg;
				rr = ((rr<=0)-1) & rr;
 
 
				if (head.biClrUsed)
					newImage.SetPixelColor(x,y,RGB(rr,gg,bb));
				else {
					iDst = newImage.info.pImage + y*newImage.info.dwEffWidth + x*3;
					b_b = ((bb & 0xFFFF0000) >= 0xFF0000) ? (0xFF) : ((uint8_t)(bb>>16));
					g_g = ((gg & 0xFFFF0000) >= 0xFF0000) ? (0xFF) : ((uint8_t)(gg>>16));
					r_r = ((rr & 0xFFFF0000) >= 0xFF0000) ? (0xFF) : ((uint8_t)(rr>>16));
					*iDst++ = (uint8_t)b_b;
					*iDst++ = (uint8_t)g_g;
					*iDst   = (uint8_t)r_r;
				}
 
			}
		}
		break;

优化后,速度提升大约1倍左右,对SSE不熟,不知是否还有利用SSE优化的空间

分类: Computer 标签: ,