基于YUV422的图像缩放 (双线性插值)

      通常的摄像头读取的数据都是YUV422格式的,如果想要支持数码变焦,我们需要对他进行缩放操作,当然具体点应该是放大操作,因为我们都是把采集到的图像的局部放大,称为数码变焦.

      在测试过程中尝试了很多不同的方法,包括了Gdiplus, Opencv, Ippi 以及自己编写的基于YUV422的插值操作.

      这里简单介绍下基于Gdiplus, Opencv和Ippi的缩放操作. Gdiplus和Opencv都只能在YUV444上操作,为此,我们需要将YUV422转换为YUV444,有了YUV422,YUV444很容易得到,速度也很快. 通过Gdiplus, Opencv对YUV444进行缩放,将缩放后的YUV444再转换为YUV422即可完成整个缩放过程. 而Ippi提供了YUV422上的缩放函数,可以直接进行缩放操作.

 

      具体的缩放如下:

Gdiplus:

int ZoomIn(BYTE* pOridata, int width, int height, CRect rect)//YUV444 { BITMAPINFOHEADER bmih; memset(&bmih, 0, sizeof(BITMAPINFOHEADER)); bmih.biSize = sizeof(BITMAPINFOHEADER); bmih.biWidth = width; bmih.biHeight = height; bmih.biPlanes = 1; bmih.biBitCount = 24; bmih.biSizeImage = width*height*bmih.biBitCount/8; Bitmap* pBitmap = Bitmap::FromBITMAPINFO((BITMAPINFO*)&bmih, pOridata); Bitmap* ptemp = pBitmap->Clone(rect.left, height-rect.bottom, rect.Width(), rect.Height(), pBitmap->GetPixelFormat()); Graphics gph(pBitmap); gph.DrawImage(ptemp, 0, 0, width, height); delete ptemp; delete pBitmap; return 0; }

 

Opencv:

YUV4222YUV444(pYUV422, pYUV444, iwidth, iheight); if (!pZoomsrcIplImg) { pZoomsrcIplImg = cvCreateImage(cvSize(iwidth, iheight), IPL_DEPTH_8U, 3); } if (pZoomsrcIplImg) { memcpy(pZoomsrcIplImg->imageData, pYUV444, g_iwidth*g_iheight*3); cvSetImageROI(pZoomsrcIplImg, cvRect(drawrect.left, drawrect.top, drawrect.Width(), drawrect.Height())); } if (!pZoomdstIplImg) { pZoomdstIplImg = cvCreateImage(cvSize(iwidth, iheight), IPL_DEPTH_8U, 3); } cvResize(pZoomsrcIplImg, pZoomdstIplImg, CV_INTER_LINEAR); memcpy(pYUV444, pZoomdstIplImg->imageData, iwidth*iheight*3); YUV4442YUV422(pYUV444, pYUV422, iwidth, iheight); cvResetImageROI(pZoomsrcIplImg);

 

Ippi:

IppiSize srcsize; srcsize.width = iwidth; srcsize.height = iheight; IppiRect srcROI; srcROI.x = (drawrect.left>>2)<<1; srcROI.y = drawrect.top; srcROI.width = (drawrect.Width()>>1)<<1; srcROI.height = (drawrect.Height()>>1)<<1; IppiSize dstsize; dstsize.width = iwidth; dstsize.height = iheight; double xFactor = double(dstsize.width)/srcROI.width; double yFactor = double(dstsize.height)/srcROI.height; ippiResizeYUV422_8u_C2R(pYUV422src, srcsize, g_iwidth*2, srcROI, pYUV422dst, iwidth*2, dstsize, xFactor, yFactor, IPPI_INTER_LINEAR); memcpy(g_pYUV422src, g_pYUV422dst, g_iwidth*g_iheight*2);

 

上述方法中drawrect为所需缩放区域, iwidth, iheight为缩放后的宽高(假设与原图像的整体宽高一致,即将图像部分区域缩放至全部)

 

利用双线性插值,本人写了一个基于YUV422的缩放代码,考虑到计算量的问题,效率无法和上述几种比较.(需要进行优化)

上述算法, Gdiplus与Opencv速度相似, Ippi速度要明显快于Gdiplus和Opencv. Ippi和Opencv均为intel所提供软件包.

 

本人所写基于YUV422的缩放:

int YUVZoomIn(void* pYUV, int width, int height, CRect rect) { if (rect.Width()%2!=0) { rect.left++; } if (rect.left%2!=0) { rect.left++; rect.right++; } BYTE* pZoomInData = new BYTE[width*height*2]; memset(pZoomInData, 0, width*height*2); double scale = ((double)(rect.right-rect.left))/width; BYTE* pOriYUV = (BYTE*)pYUV; BYTE* pZoonInYUV = (BYTE*)pZoomInData; double indexI, indexJ, u, v; int roundI, roundJ; int left, right, rectwidth, preU, preV; left=(rect.left>>1)<<1; right=(rect.right>>1)<<1; rectwidth=right-left; for (int i=0; i>1; *(pZoonInYUV+i*width*2+j*2+1) = (*(pZoonInYUV+i*width*2+j*2+1)+preV)>>1; } else { *(pZoonInYUV+i*width*2+j*2)=(BYTE)((*(pOriYUV+(rect.top+roundI)*width*2+(left+roundJ-1)*2+2)*(1-u)*(1-v)) +(*(pOriYUV+(rect.top+roundI)*width*2+(left+roundJ+1)*2)*(1-u)*v) +(*(pOriYUV+(rect.top+roundI+1)*width*2+(left+roundJ-1)*2+2)*(1-v)*u) +(*(pOriYUV+(rect.top+roundI+1)*width*2+(left+roundJ+1)*2)*u*v)); *(pZoonInYUV+i*width*2+j*2-1)=(BYTE)((*(pOriYUV+(rect.top+roundI)*width*2+(left+roundJ-1)*2+1)*(1-u)*(1-v)) +(*(pOriYUV+(rect.top+roundI)*width*2+(left+roundJ+1)*2+1)*(1-u)*v) +(*(pOriYUV+(rect.top+roundI+1)*width*2+(left+roundJ-1)*2+1)*(1-v)*u) +(*(pOriYUV+(rect.top+roundI+1)*width*2+(left+roundJ+1)*2+1)*u*v)); *(pZoonInYUV+i*width*2+j*2+1)=(BYTE)((*(pOriYUV+(rect.top+roundI)*width*2+(left+roundJ-1)*2+3)*(1-u)*(1-v)) +(*(pOriYUV+(rect.top+roundI)*width*2+(left+roundJ+1)*2+3)*(1-u)*v) +(*(pOriYUV+(rect.top+roundI+1)*width*2+(left+roundJ-1)*2+3)*(1-v)*u) +(*(pOriYUV+(rect.top+roundI+1)*width*2+(left+roundJ+1)*2+3)*u*v)); *(pZoonInYUV+i*width*2+j*2-1) = (*(pZoonInYUV+i*width*2+j*2-1)+preU)>>1; *(pZoonInYUV+i*width*2+j*2+1) = (*(pZoonInYUV+i*width*2+j*2+1)+preV)>>1; } } } } memcpy(pYUV, pZoonInYUV, width*height*2); delete [] pZoonInYUV; return 0; }

测试可以使用,速度存在些问题,有改进想法的可以直接与我联系,哈哈

mosesyuan at gmail dot com

你可能感兴趣的:(基于YUV422的图像缩放 (双线性插值))