打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
图像缩放旋转
一、缩放操作
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库差不多

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
MFC 位图旋转
Bitmap、CBitmap、HBITMAP以及BITMAP的相互转换
Gdi+
MFC实现图像灰度、采样和量化功能详解
C#中Bitmap类实现对图像操作的一些方法
Android ImageView 总结
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服