一、缩放操作
1、前几天碰上需要对bmp位图进行缩放的功能,调用API函数,虽然能实现位图缩放,但是对有放大的效果好,缩小会造成失真,图像上有花点,让人难以接受,因为本人以前学易语言,易语言有一段代码,对bmp图像缩放效果非常 好,昨天抽空,把它翻译成c++代码了,经验证,非常 好用,帖上代码:这一段是对宽度进行缩放:void __stdcall bmpsetH(unsigned char *bitmap,int h,unsigned char *bitmap2){int i,j,k,bitmapH1,bitmapH2,bitmapV1,bitmapV2,bitmapSize1,bitmapSize2,bitmapLen1,bitmapLen2;int startH1,startH2,R,G,B,R1,G1,B1; // 位图宽1 = 取字节集数据 (位图数据, #整数型, 19)bitmapH1=*((int*)(bitmap+18)); bitmapV1=*((int*)(bitmap+22)); int redress1=bitmapH1%4; int bitmapNH1=bitmapH1*3+redress1; bitmapLen1=bitmapNH1*bitmapV1; bitmapSize1=bitmapLen1+54; int redress2=h%4; int bitmapNH2=h*3+redress2; bitmapLen2=bitmapNH2*bitmapV1; bitmapSize2=bitmapLen2+54; memcpy(bitmap2,bitmap,54); memcpy(bitmap2+2,&bitmapSize2,4); memcpy(bitmap2+18,&h,4); double Hval=(double)bitmapH1/h; double Hvala=0; int Hvalb=0,Hvalc=0; for (i=1;i<=bitmapV1;i++) { startH2=bitmapSize2-i*bitmapNH2; startH1=bitmapSize1-i*bitmapNH1; B1=bitmap[startH1]; G1=bitmap[startH1+1]; R1=bitmap[startH1+2]; for(j=1;j<=h;j++) { startH2=startH2+3; Hvala=Hvala+Hval; if (Hvala<1) { Hvalb=3; } else { Hvalc=Hvala; Hvalb=Hvalc*3; } startH1=bitmapSize1-i*bitmapNH1+Hvalb; B=(bitmap[startH1-3]+B1)/2; G=(bitmap[startH1-2]+G1)/2; R=(bitmap[startH1-1]+R1)/2; bitmap2[startH2-3]=B; bitmap2[startH2-2]=G; bitmap2[startH2-1]=R; B1=bitmap[startH1-3]; G1=bitmap[startH1-2]; R1=bitmap[startH1-1]; } Hvala=0; }}这一段是对高度进行缩放:void BmpSetV(unsigned char *bitmap,int v,unsigned char *bitmap2){ double Vval,Vvala=0; int i,j,Vvalb=0,bitH1,bitNH1,bitV1,redress,bitLen1,bitsize1,bitLen2,bitsize2;int start3=0,start2=0,start1=0,G1,B1,R1,R,G,B; bitH1=*((int*)(bitmap+18));bitV1=*((int*)(bitmap+22));redress=bitH1%4;bitNH1=bitH1*3+redress;bitLen1=bitNH1*bitV1;bitsize1=bitLen1+54;bitLen2=bitNH1*v;bitsize2=bitLen2+54;memcpy(bitmap2,bitmap,54);memcpy(bitmap2+2,&bitsize2,4);memcpy(bitmap2+22,&v,4);Vval=bitV1/(double)v;for (i=1;i<=bitH1;i++){ start3=bitsize1-bitNH1+i*3; B1=bitmap[start3-3]; G1=bitmap[start3-2]; R1=bitmap[start3-1]; for (j=1;j<=v;j++) { Vvala=Vvala+Vval; if (Vvala<1)Vvalb=1; else Vvalb=Vvala; start2=bitsize2-j*bitNH1+i*3; start1=bitsize1-Vvalb*bitNH1+i*3; if (Vvalb<bitV1) { start3=bitsize1-Vvalb*bitNH1-bitNH1+i*3; if(i==1) { bitmap2[start2-3]=bitmap[start1-3]; bitmap2[start2-2]=bitmap[start1-2];bitmap2[start2-1]=bitmap[start1-1]; } else { B=(B1+bitmap[start1-3])/2; G=(G1+bitmap[start1-2])/2; R=(R1+bitmap[start1-1])/2; bitmap2[start2-3]=B; bitmap2[start2-2]=G; bitmap2[start2-1]=R; B1=bitmap[start3-3]; G1=bitmap[start3-2]; R1=bitmap[start3-1]; } } else { bitmap2[start2-3]=bitmap[start1-3]; bitmap2[start2-2]=bitmap[start1-2];bitmap2[start2-1]=bitmap[start1-1]; } } Vvala=0;}}示例:int main(int argc, char* argv[]){ unsigned char *bmp,*bmp2;bmp=(unsigned char*)malloc(1244214);bmp2=(unsigned char*)malloc(1244214);FILE *fp=fopen("D:\\开机画面.bmp","rb");fread(bmp,1,304182,fp);fclose(fp); //bmpsetH(bmp,720,bmp2); // memcpy(bmp,bmp2,1244214);BmpSetV(bmp,290,bmp2); fp=fopen("D:\\开机.bmp","wb");fwrite(bmp2,1,1244214,fp);fclose(fp); free(bmp);free(bmp2);return 0;}2、缩小的时候,如果是按比例采样,失真会大一些;如果对周围区域的点取平均,效果会相对好一些
3、平均就是平滑了,可能会引起雾感
4、也许是我描述不清楚,是这样的,我开始用api函数进行放大和缩小,放大看不出来什么问题,缩小的话,在图片上会有很我的小白点出来,而用上面这个算法,看起来只是把图片缩小或拉大了,而看不到其它类似的小白点,所以我觉得可以,而api缩小,比如,会在人脸上出现一些白点,像是一幅画,被小孩子洒了白色墨水一样,我使用的是api画图函数:StretchBlt,放大效果很好哟,和上面这个算法的结果是一样的,看起来正常
5、缩放用:StretchBlt
图片任意角度翻转:
HBITMAP CBarDemoView::GetRotatedBitmapNT( HBITMAP hBitmap, float radians, COLORREF clrBack )
{
// Create a memory DC compatible with the display
CDC sourceDC, destDC;
sourceDC.CreateCompatibleDC( NULL );
destDC.CreateCompatibleDC( NULL );
// Get logical coordinates
BITMAP bm;
::GetObject( hBitmap, sizeof( bm ), &bm );
float cosine = (float)cos(radians/180 * PI);
float sine = (float)sin(radians/180 * PI);
int x1 = (int)(bm.bmHeight * sine);
int y1 = (int)(bm.bmHeight * cosine);
int x2 = (int)(bm.bmWidth * cosine + bm.bmHeight * sine);
int y2 = (int)(bm.bmHeight * cosine - bm.bmWidth * sine);
int x3 = (int)(bm.bmWidth * cosine);
int y3 = (int)(-bm.bmWidth * sine);
int minx = min(0,min(x1, min(x2,x3)));
int miny = min(0,min(y1, min(y2,y3)));
int maxx = max(0,max(x1, max(x2,x3)));
int maxy = max(0,max(y1, max(y2,y3)));
int w = maxx - minx;
int h = maxy - miny;
// Create a bitmap to hold the result
HBITMAP hbmResult = ::CreateCompatibleBitmap(CClientDC(NULL), w, h);
HBITMAP hbmOldSource = (HBITMAP)::SelectObject( sourceDC.m_hDC, hBitmap );
HBITMAP hbmOldDest = (HBITMAP)::SelectObject( destDC.m_hDC, hbmResult );
// Draw the background color before we change mapping mode
HBRUSH hbrBack = CreateSolidBrush( clrBack );
HBRUSH hbrOld = (HBRUSH)::SelectObject( destDC.m_hDC, hbrBack );
destDC.PatBlt( 0, 0, w, h, PATCOPY );
::DeleteObject( ::SelectObject( destDC.m_hDC, hbrOld ) );
// We will use world transform to rotate the bitmap
SetGraphicsMode(destDC.m_hDC, GM_ADVANCED);
XFORM xform;
xform.eM11 = cosine;
xform.eM12 = -sine;
xform.eM21 = sine;
xform.eM22 = cosine;
xform.eDx = (float)-minx;
xform.eDy = (float)-miny;
SetWorldTransform( destDC.m_hDC, &xform );
// Now do the actual rotating - a pixel at a time
destDC.BitBlt(0,0,bm.bmWidth, bm.bmHeight, &sourceDC, 0, 0, SRCCOPY );
nWidth[m_count] = bm.bmWidth;
nHeight[m_count] = bm.bmHeight;
// Restore DCs
::SelectObject( sourceDC.m_hDC, hbmOldSource );
::SelectObject( destDC.m_hDC, hbmOldDest );
return hbmResult;
}
6、缩放用:StretchBlt
CPaintDC dc(this);
CRect rect;
CBitmap Bmp;
BITMAP bitmap;
CDC memDC;
GetClientRect(&rect);
Bmp.LoadBitmap(IDB_BITMAP);
memDC.CreateCompatibleDC(&dc);
memDC.SelectObject(&Bmp);
Bmp.GetBitmap(&bitmap);
dc.StretchBlt(X,Y,rect.Width(),rect.Height(),&memDC,0,0,bitmap.bmWidth,bitmap.bmHeight,SRCCOPY);
Bmp.DeleteObject();
步骤大概就是这样,具体意思自己查MSDN
7、StretchBlt实现不了,它只能实现绽放,要用GetPixel()和SetPixel()函数来做,基本法是,你创建一个图片的内存DC,按照你想要旋转的方式来重新写入各个像素的颜色,例如,你把图片的右下角的点的颜色写入到内存图片DC的左上角,再把最石下角左边的那个点写到左上角第二个位置,如此通过循环后,再把图片内存DC 显示出来,就能实现旋转。
不推荐你用GDI来做复杂的图片操作,用GDI+做起来要简单得多!
8、图像处理库
ImageMagick:功能强大丰富,非常流行
GraphicsMagick:效率高,图像处理领域的瑞士军刀
GD:老牌了,不多说
感觉应该跟opencv库差不多