我现在已得到位图的头和位图数据bmpBuf,请问如何将其旋转180度,也就是在bmpBuf中交换
谢谢

解决方案 »

  1.   

    四、图像的基本操作处理  1、图像平移  图像平移只是改变图像在屏幕上的位置,图像本身并不发生变化。假设原图像区域左上角坐标为(x0, y0),右下角坐标为(x1, y1),将图像分别沿x和y轴平移dx和dy,则新图像的左上角坐标为(x0+dx, y0+dy),右下角坐标为(x1+dx, y1+dy)。坐标平移变换公式为:  x1 = x + dx  y1 = y + dy  在屏幕上实现图像的移动分为四个步骤:  ⑴ 读原图像到缓冲区;  ⑵ 擦除视图上原图像;  ⑶ 计算平移后的新坐标。  ⑷ 利用API函数::StretchDIBits()在新的左上角坐标位置处重新显示原图像。  其中,擦除原图像的方法与图形变换中擦除原图形的方法一致,在实现中仍采用XOR异或方式画图擦除原图像。对于新坐标值的计算还需要考虑边界情况,不要在图像平移后超出允许的屏幕范围。  2、图像颠倒  图像颠倒是指把定义好的图像区域上下翻转地显示在屏幕上。分析图像颠倒的过程,可发现每行的图像信息都保持不变,而只是改变了行的顺序,将第一行与最后的第n行相互交换,第二行与第n - 1行交换……,依此类推,从而实现了图像的颠倒。只需采用按行交换的方式,即可方便地修改缓冲区内容,实现图像的颠倒。基本步骤如下:  (1)将原图像读入缓冲区,并擦除原图像;  (2) 计算图像的高度,即行数height;计算图像宽度width;根据宽度、高度生成新缓冲区;  (3)把第一行与最末行交换,第2行与第n-1行交换……,依此类推,直至全部交换完毕。既原图中的(x、y)点,在新生成的图象中对应为x1=x,y1=height-1-y。把原图中的象素值读入新缓冲区的(x1,y1)点处。  (4)把交换后的图像缓冲区内容重新显示在屏幕上。  3、图像镜像变换  镜像变换是指将指定区域的图像左右翻转地显示在屏幕。分析镜像变换过程可以发现:每行图像信息的处理方式是相同的,而且行顺序不发生变化,只是每一行的像素信息按从左到右的顺序进行了左右颠倒,从而实现了镜像变换。因此,采用按行逐点变换的方式实现图像的镜像。  给出原图中的任意点(x, y)镜像变换后的新坐标(x1, y1)的坐标变换公式:  x1 = width-x-1  y1 = y  根据以上公式,对各个像素点计算新坐标后,把原图中的象素值读入新缓冲区的(x1,y1)点处。  4、图像任意角度的旋转  图像旋转是指把定义的图像绕某一点以逆时针或顺时针方向旋转一定的角度,通常是指绕图像的中心以逆时针方向旋转。  首先根据旋转的角度、图象对角线的长度计算旋转后的图像的最大宽度、高度,根据旋转后图象最大的宽度、高度生成新的缓冲区,假设图像的左上角为(left, top),右下角为(right, bottom),则图像上任意点(x, y)绕其中心(xcenter, ycenter)逆时针旋转angle角度后,新的坐标位置(x1, y1)的计算公式为:  xcenter = (width+1)/2+left;  ycenter = (height+1)/2+top;  x1 = (x-xcenter) cosθ- (y - ycenter) sinθ+xcenter;  y1 = (x-xcenter) sinθ+ (y- ycenter) cosθ+ ycenter;  与图像的镜像变换相类似,把原图中的象素值读入新缓冲区的(x1,y1)点处。注意在新缓冲区中与原图没有对应的象素点的值用白色代替。  五、小结  笔者开发的该图像处理程序在Windows98环境下编译通过,本文主要讲述了8bit灰度图像的处理,读者可以本文的基础上开发自己的针对二值、真彩色格式的图像处理系统。 
      

  2.   

    BYTE *lpBitData;//原始图像
    BITMAPINFOHEADER ih;
    BYTE *lpBitBuff//转换后的图像//
    //图像数据初始化
    //
    //int iBytesInRow=((ih.biBitCount) + 31) / 32 * 4//每行图像的字节数lpBitBuff=new BYTE(ih.biSizeImage)
    for(int i=0;i<ih.biHeight;i++)
    {
        for(int j=0;j<ih.biWidth;j++)
        memset(lpBitBuff[i*iBytesInRow+j],
               lpBitBuff[(ih.biHeight-i)*iBytesInRow+(ih.biWidth-j)],
               ih.biBitCount/8);}
    //此时,lpBitBuff包含的图像即为旋转180度的图像
      

  3.   

    http://www.codeguru.com/bitmap/rotate_bitmap.shtml
    旋转图像
    如果你的应用程序仅工作在Windows NT下,那么你可以通过API函数旋转你的位图。
     你或者使用world transformation和BitBlt()或者使用PlgBlt()旋转位图。一个
    使用第一种方法的函数显示在下面。
    如果你的目标是多平台的,那么你的任务变得非常困难。你只能通过旋转源位图中
    每个象素或者直接操作DIB字节得到旋转位图。第一种方法通过每个点的处理是非
    常慢的,第二种方法是很复杂的,但它有足够快的速度。注:下面的所有函数旋转
    后产生新的位图,如果你需要直接绘制位图,请自已修改函数。 其中函数1仅工作
    在NT环境下,它是最简单也是最快的,可惜它不支持Windows95。
    所有的函数所接受的角度单位是弧度,如果是角度单位是度请用下面的公式转换。
    radian = (2*pi *degree)/360
    旋转步骤:
    创建一对与设备兼容的显示设备。一个用于源位图,一个用于旋转后的目标位图。
    预计算正弦和余弦函数值,这样可以避免重复计算。
    用下面的公式计算旋转图像后的矩形
    newx = x.cos(angle) + y.sin(angle)
    newy = y.cos(angle) - x.sin(angle)
    旋转后的位图将不能占用整个新位图,我们将用背景色填充它。
    点阵转换公式
    newx = x * eM11 + y * eM21 + eDx
    newy = x * eM12 + y * eM22 + eDy
    其中eM11和eM22是角度的余弦值,eM21是角度的正弦,eM12是eM21的负值。 eDx & eDy
    目的是旋转后的位图在新的位图不被剪切。
    函数一:适用于NT
    // GetRotatedBitmapNT
     Create a new bitmap with rotated image
    // Returns
    - Returns new bitmap with rotated image
    // hBitmap
    - Bitmap to rotate
    // radians
    - Angle of rotation in radians
    // clrBack
    - Color of pixels in the resulting bitmap that do
    //
     not get covered by source pixels
    HBITMAP GetRotatedBitmapNT( HBITMAP hBitmap, float radians, COLORREF clrBack )
    / Create a memory DC compatible with the display
    DC sourceDC, destDC;
    ourceDC.CreateCompatibleDC( NULL );
    estDC.CreateCompatibleDC( NULL );
    / Get logical coordinates
    ITMAP bm;
    :GetObject( hBitmap, sizeof( bm ), &bm );
    loat cosine = (float)cos(radians);
    loat sine = (float)sin(radians);
    / Compute dimensions of the resulting bitmap
    / First get the coordinates of the 3 corners other than origin
    nt x1 = (int)(bm.bmHeight * sine);
    nt y1 = (int)(bm.bmHeight * cosine);
    nt x2 = (int)(bm.bmWidth * cosine + bm.bmHeight * sine);
    nt y2 = (int)(bm.bmHeight * cosine - bm.bmWidth * sine);
    nt x3 = (int)(bm.bmWidth * cosine);
    nt y3 = (int)(-bm.bmWidth * sine);
    nt minx = min(0,min(x1, min(x2,x3)));
    nt miny = min(0,min(y1, min(y2,y3)));
    nt maxx = max(0,max(x1, max(x2,x3)));
    nt maxy = max(0,max(y1, max(y2,y3)));
    nt w = maxx - minx;
    nt h = maxy - miny;
    / Create a bitmap to hold the result
    BITMAP hbmResult = ::CreateCompatibleBitmap(CClientDC(NULL), w, h);
    BITMAP hbmOldSource = (HBITMAP)::SelectObject( sourceDC.m_hDC, hBitmap );
    BITMAP hbmOldDest = (HBITMAP)::SelectObject( destDC.m_hDC, hbmResult );
    / Draw the background color before we change mapping mode
    BRUSH hbrBack = CreateSolidBrush( clrBack );
    BRUSH hbrOld = (HBRUSH)::SelectObject( destDC.m_hDC, hbrBack );
    estDC.PatBlt( 0, 0, w, h, PATCOPY );
    :DeleteObject( ::SelectObject( destDC.m_hDC, hbrOld ) );
    / We will use world transform to rotate the bitmap
    etGraphicsMode(destDC.m_hDC, GM_ADVANCED);
    FORM xform;
    form.eM11 = cosine;
    form.eM12 = -sine;
    form.eM21 = sine;
    form.eM22 = cosine;
    form.eDx = (float)-minx;
    form.eDy = (float)-miny;
    etWorldTransform( destDC.m_hDC, &xform );
    / Now do the actual rotating - a pixel at a time
    estDC.BitBlt(0,0,bm.bmWidth, bm.bmHeight, &sourceDC, 0, 0, SRCCOPY );
    / Restore DCs
    :SelectObject( sourceDC.m_hDC, hbmOldSource );
    :SelectObject( destDC.m_hDC, hbmOldDest );
    eturn hbmResult;
    函数二: GetRotatedBitmap()使用 GetPixel & SetPixel
    // GetRotatedBitmap
     Create a new bitmap with rotated image
    // Returns
    - Returns new bitmap with rotated image
    // hBitmap
    - Bitmap to rotate
    // radians
    - Angle of rotation in radians
    // clrBack
    - Color of pixels in the resulting bitmap that do
    //
     not get covered by source pixels
    // Note
     If the bitmap uses colors not in the system palette
    //
     then the result is unexpected. You can fix this by
    //
     adding an argument for the logical palette.
    HBITMAP GetRotatedBitmap( HBITMAP hBitmap, float radians, COLORREF clrBack )
    / Create a memory DC compatible with the display
    DC sourceDC, destDC;
    ourceDC.CreateCompatibleDC( NULL );
    estDC.CreateCompatibleDC( NULL );
    / Get logical coordinates
    ITMAP bm;
    :GetObject( hBitmap, sizeof( bm ), &bm );
    loat cosine = (float)cos(radians);
    loat sine = (float)sin(radians);
    / Compute dimensions of the resulting bitmap
    / First get the coordinates of the 3 corners other than origin
    nt x1 = (int)(-bm.bmHeight * sine);
    nt y1 = (int)(bm.bmHeight * cosine);
    nt x2 = (int)(bm.bmWidth * cosine - bm.bmHeight * sine);
    nt y2 = (int)(bm.bmHeight * cosine + bm.bmWidth * sine);
    nt x3 = (int)(bm.bmWidth * cosine);
    nt y3 = (int)(bm.bmWidth * sine);
    nt minx = min(0,min(x1, min(x2,x3)));
    nt miny = min(0,min(y1, min(y2,y3)));
    nt maxx = max(x1, max(x2,x3));
    nt maxy = max(y1, max(y2,y3));
    nt w = maxx - minx;
    nt h = maxy - miny;
    / Create a bitmap to hold the result
    BITMAP hbmResult = ::CreateCompatibleBitmap(CClientDC(NULL), w, h);
    BITMAP hbmOldSource = (HBITMAP)::SelectObject( sourceDC.m_hDC, hBitmap );
    BITMAP hbmOldDest = (HBITMAP)::SelectObject( destDC.m_hDC, hbmResult );
    / Draw the background color before we change mapping mode
    BRUSH hbrBack = CreateSolidBrush( clrBack );
    BRUSH hbrOld = (HBRUSH)::SelectObject( destDC.m_hDC, hbrBack );
    estDC.PatBlt( 0, 0, w, h, PATCOPY );
    :DeleteObject( ::SelectObject( destDC.m_hDC, hbrOld ) );
    / Set mapping mode so that +ve y axis is upwords
    ourceDC.SetMapMode(MM_ISOTROPIC);
    ourceDC.SetWindowExt(1,1);
    ourceDC.SetViewportExt(1,-1);
    ourceDC.SetViewportOrg(0, bm.bmHeight-1);
    estDC.SetMapMode(MM_ISOTROPIC);
    estDC.SetWindowExt(1,1);
    estDC.SetViewportExt(1,-1);
    estDC.SetWindowOrg(minx, maxy);
    / Now do the actual rotating - a pixel at a time
    / Computing the destination point for each source point
    / will leave a few pixels that do not get covered
    / So we use a reverse transform - e.i. compute the source point
    / for each destination point
    or( int y = miny; y < maxy; y++ )
    for( int x = minx; x < maxx; x++ )
    nt sourcex = (int)(x*cosine + y*sine);
    nt sourcey = (int)(y*cosine - x*sine);
    f( sourcex >= 0 && sourcex < bm.bmWidth && sourcey >= 0
    & sourcey < bm.bmHeight )
    destDC.SetPixel(x,y,sourceDC.GetPixel(sourcex,sourcey));
    / Restore DCs
    :SelectObject( sourceDC.m_hDC, hbmOldSource );
    :SelectObject( destDC.m_hDC, hbmOldDest );
    eturn hbmResult;
    函数三: GetRotatedBitmap()使用DIB
         // GetRotatedBitmap - Create a new bitmap with rotated image
         // Returns - Returns new bitmap with rotated image
         // hDIB - Device-independent bitmap to rotate
         // radians - Angle of rotation in radians
         // clrBack - Color of pixels in the resulting bitmap that do
         //  not get covered by source pixels
         HANDLE GetRotatedBitmap( HANDLE hDIB, float radians, COLORREF clrBack)
         {
         // Get source bitmap info
         BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB ;
         int bpp = bmInfo.bmiHeader.biBitCount; // Bits per pixel
         int nColors = bmInfo.bmiHeader.biClrUsed ? bmInfo.bmiHeader.biClrUsed
         :
         1 << bpp;
         int nWidth = bmInfo.bmiHeader.biWidth;
         int nHeight = bmInfo.bmiHeader.biHeight;
         int nRowBytes = ((((nWidth * bpp) + 31) & ~31) / 8);
      

  4.   

    // Make sure height is positive and biCompression is BI_RGB or
         BI_BITFIELDS
         DWORD &compression = bmInfo.bmiHeader.biCompression;
         if( nHeight < 0 || (compression!=BI_RGB &&
         compression!=BI_BITFIELDS))
         return NULL;
         LPVOID lpDIBBits;
         if( bmInfo.bmiHeader.biBitCount > 8 )
         lpDIBBits = (LPVOID)((LPDWORD)(bmInfo.bmiColors +
         bmInfo.bmiHeader.biClrUsed) +
         ((compression == BI_BITFIELDS) ? 3 : 0));
         else
         lpDIBBits = (LPVOID)(bmInfo.bmiColors + nColors);
         // Compute the cosine and sine only once
         float cosine = (float)cos(radians);
         float sine = (float)sin(radians);
         // Compute dimensions of the resulting bitmap
         // First get the coordinates of the 3 corners other than origin
         int x1 = (int)(-nHeight * sine);
         int y1 = (int)(nHeight * cosine);
         int x2 = (int)(nWidth * cosine - nHeight * sine);
         int y2 = (int)(nHeight * cosine + nWidth * sine);
         int x3 = (int)(nWidth * cosine);
         int y3 = (int)(nWidth * sine);
         int minx = min(0,min(x1, min(x2,x3)));
         int miny = min(0,min(y1, min(y2,y3)));
         int maxx = max(x1, max(x2,x3));
         int maxy = max(y1, max(y2,y3));
         int w = maxx - minx;
         int h = maxy - miny;
         // Create a DIB to hold the result
         int nResultRowBytes = ((((w * bpp) + 31) & ~31) / 8);
         long len = nResultRowBytes * h;
         int nHeaderSize = ((LPBYTE)lpDIBBits-(LPBYTE)hDIB) ;
         HANDLE hDIBResult = GlobalAlloc(GMEM_FIXED,len+nHeaderSize);
         // Initialize the header information
         memcpy( (void*)hDIBResult, (void*)hDIB, nHeaderSize);
         BITMAPINFO &bmInfoResult = *(LPBITMAPINFO)hDIBResult ;
         bmInfoResult.bmiHeader.biWidth = w;
         bmInfoResult.bmiHeader.biHeight = h;
         bmInfoResult.bmiHeader.biSizeImage = len;
         LPVOID lpDIBBitsResult = (LPVOID)((LPBYTE)hDIBResult + nHeaderSize);
         // Get the back color value (index)
         ZeroMemory( lpDIBBitsResult, len );
         DWORD dwBackColor;
         switch(bpp)
         {
         case 1: //Monochrome
         if( clrBack == RGB(255,255,255) )
         memset( lpDIBBitsResult, 0xff, len );
         break;
         case 4:
         case 8: //Search the color table
         int i;
         for(i = 0; i < nColors; i++ )
         {
         if( bmInfo.bmiColors[i].rgbBlue == GetBValue(clrBack)
         && bmInfo.bmiColors[i].rgbGreen == GetGValue(clrBack)
         && bmInfo.bmiColors[i].rgbRed == GetRValue(clrBack) )
         {
         if(bpp==4) i = i | i<<4;
         memset( lpDIBBitsResult, i, len );
         break;
         }
         }
         // If not match found the color remains black
         break;
         case 16:
         // Windows95 supports 5 bits each for all colors or 5 bits for red
         & blue
         // and 6 bits for green - Check the color mask for RGB555 or RGB565
         if( *((DWORD*)bmInfo.bmiColors) == 0x7c00 )
         {
         // Bitmap is RGB555
         dwBackColor = ((GetRValue(clrBack)>>3) << 10) +
         ((GetRValue(clrBack)>>3) << 5) +
         (GetBValue(clrBack)>>3) ;
         }
         else
         {
         // Bitmap is RGB565
         dwBackColor = ((GetRValue(clrBack)>>3) << 11) +
         ((GetRValue(clrBack)>>2) << 5) +
         (GetBValue(clrBack)>>3) ;
         }
         break;
         case 24:
         case 32:
         dwBackColor = (((DWORD)GetRValue(clrBack)) << 16) |
         (((DWORD)GetGValue(clrBack)) << 8) |
         (((DWORD)GetBValue(clrBack)));
         break;
         }
         // Now do the actual rotating - a pixel at a time
         // Computing the destination point for each source point
         // will leave a few pixels that do not get covered
         // So we use a reverse transform - e.i. compute the source point
         // for each destination point
         for( int y = 0; y < h; y++ )
         {
         for( int x = 0; x < w; x++ )
         {
         int sourcex = (int)((x+minx)*cosine + (y+miny)*sine);
         int sourcey = (int)((y+miny)*cosine - (x+minx)*sine);
         if( sourcex >= 0 && sourcex < nWidth && sourcey
         >= 0
         && sourcey < nHeight )
         {
         // Set the destination pixel
         switch(bpp)
         {
         BYTE mask;
         case 1: //Monochrome
         mask = *((LPBYTE)lpDIBBits + nRowBytes*sourcey +
         sourcex/8) & (0x80 >> sourcex%8);
         //Adjust mask for destination bitmap
         mask = mask ? (0x80 >> x%8) : 0;
         *((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) +
         (x/8)) &= ~(0x80 >> x%8);
         *((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) +
         (x/8)) |= mask;
         break;
         case 4:
         mask = *((LPBYTE)lpDIBBits + nRowBytes*sourcey +
         sourcex/2) & ((sourcex&1) ? 0x0f : 0xf0);
         //Adjust mask for destination bitmap
         if( (sourcex&1) != (x&1) )
         mask = (mask&0xf0) ? (mask>>4) : (mask<<4);
         *((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) +
         (x/2)) &= ~((x&1) ? 0x0f : 0xf0);
         *((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) +
         (x/2)) |= mask;
         break;
         case 8:
         BYTE pixel ;
         pixel = *((LPBYTE)lpDIBBits + nRowBytes*sourcey +
         sourcex);
         *((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) +
         (x)) = pixel;
         break;
         case 16:
         DWORD dwPixel;
         dwPixel = *((LPWORD)((LPBYTE)lpDIBBits +
         nRowBytes*sourcey + sourcex*2));
         *((LPWORD)((LPBYTE)lpDIBBitsResult +
         nResultRowBytes*y + x*2)) = (WORD)dwPixel;
         break;
         case 24:
         dwPixel = *((LPDWORD)((LPBYTE)lpDIBBits +
         nRowBytes*sourcey + sourcex*3)) & 0xffffff;
         *((LPDWORD)((LPBYTE)lpDIBBitsResult +
         nResultRowBytes*y + x*3)) |= dwPixel;
         break;
         case 32:
         dwPixel = *((LPDWORD)((LPBYTE)lpDIBBits +
         nRowBytes*sourcey + sourcex*4));
         *((LPDWORD)((LPBYTE)lpDIBBitsResult +
         nResultRowBytes*y + x*4)) = dwPixel;
         }
         }
         else
         {
         // Draw the background "color."
         tppabs="http://www.codeguru.com/bitmap/color." The
         background color
         // has already been drawn for 8 bits per pixel and less
         switch(bpp)
         {
         case 16:
         *((LPWORD)((LPBYTE)lpDIBBitsResult +
         nResultRowBytes*y + x*2)) =
         (WORD)dwBackColor;
         break;
         case 24:
         *((LPDWORD)((LPBYTE)lpDIBBitsResult +
         nResultRowBytes*y + x*3)) |= dwBackColor;
         break;
         case 32:
         *((LPDWORD)((LPBYTE)lpDIBBitsResult +
         nResultRowBytes*y + x*4)) = dwBackColor;
         break;
         }
         }
         }
         }
         return hDIBResult;
         }
    http://www.ittide.com/document/article/graphic/13.html