请问彩色BMP图像如何转换成黑白的256图像?(求算法)现在想吧24位彩色图像转换成黑白的256图像,请问改如何转换?
能否保证从彩色到黑白是1对1的关系?情大家给电意见,回答者有分!

解决方案 »

  1.   

    DWORD              SrcBufSize,DstBufSize,DstLineBytes;
        LPBITMAPINFOHEADER lpImgData;
    LPSTR              lpPtr;
    HLOCAL             hTempImgData;
    LPBITMAPINFOHEADER lpTempImgData;
    LPSTR              lpTempPtr;
    HDC                hDc;
    HFILE              hf;
    LONG               x,y;
    BITMAPFILEHEADER   DstBf;
    BITMAPINFOHEADER   DstBi;
        LOGPALETTE         *pPal;
        HPALETTE           hPrevPalette; 
    HLOCAL             hPal;
    DWORD    NewNumColors;
    WORD    NewBitCount;
    float              Y;
    DWORD              i;
    unsigned char      Red,Green,Blue,Gray; NewNumColors=NumColors;
    NewBitCount=bi.biBitCount;
    if(NumColors==0) //true color
    {
    NewNumColors=256;
    NewBitCount=8;
    } DstLineBytes=(DWORD)WIDTHBYTES(bi.biWidth*NewBitCount);
    DstBufSize=(DWORD)(sizeof(BITMAPINFOHEADER)+NewNumColors*sizeof(RGBQUAD)+(DWORD)DstLineBytes*bi.biHeight);
    memcpy((char *)&DstBf,(char *)&bf,sizeof(BITMAPFILEHEADER));
    memcpy((char *)&DstBi,(char *)&bi,sizeof(BITMAPINFOHEADER));
    DstBf.bfSize=DstBufSize+sizeof(BITMAPFILEHEADER);
    DstBf.bfOffBits=(DWORD)(NewNumColors*sizeof(RGBQUAD)+sizeof(BITMAPFILEHEADER)
    +sizeof(BITMAPINFOHEADER));
    DstBi.biClrUsed=0;
    DstBi.biBitCount=NewBitCount; SrcBufSize=bf.bfSize-sizeof(BITMAPFILEHEADER); if((hTempImgData=LocalAlloc(LHND,DstBufSize))==NULL)
        {
         MessageBox("Error alloc memory!","Error Message",MB_OK|MB_ICONEXCLAMATION);
            return FALSE;
        }    lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData);    
    lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTempImgData); //copy image data
    memcpy(lpTempImgData,lpImgData,DstBufSize);
    //overwrite bitmapinfoheader with the new one
    memcpy(lpTempImgData,(char *)&DstBi,sizeof(BITMAPINFOHEADER)); lpPtr=(char *)lpImgData+sizeof(BITMAPINFOHEADER);
    lpTempPtr=(char *)lpTempImgData+sizeof(BITMAPINFOHEADER);    hPal=LocalAlloc(LHND,sizeof(LOGPALETTE) + NewNumColors* sizeof(PALETTEENTRY));
        pPal =(LOGPALETTE *)LocalLock(hPal);
        pPal->palNumEntries =(WORD) NewNumColors;
    pPal->palVersion    = 0x300; if(NumColors==0) //true color
    for (i = 0; i < 256; i++) {
          pPal->palPalEntry[i].peRed=(BYTE)i;
    pPal->palPalEntry[i].peGreen=(BYTE)i;
    pPal->palPalEntry[i].peBlue=(BYTE)i;
    pPal->palPalEntry[i].peFlags=(BYTE)0;
    *(lpTempPtr++)=(unsigned char)i;
    *(lpTempPtr++)=(unsigned char)i;
    *(lpTempPtr++)=(unsigned char)i;
    *(lpTempPtr++)=0;
    }
    else 
    for (i = 0; i < NewNumColors; i++) {
    Blue=(unsigned char )(*lpPtr++);
    Green=(unsigned char )(*lpPtr++);
    Red=(unsigned char )(*lpPtr++);
    Y=(float)(Red*0.299+Green*0.587+Blue*0.114);
    Gray=(BYTE)Y;
    lpPtr++;
          pPal->palPalEntry[i].peRed=Gray;
    pPal->palPalEntry[i].peGreen=Gray;
    pPal->palPalEntry[i].peBlue=Gray;
    pPal->palPalEntry[i].peFlags=0;
    *(lpTempPtr++)=(unsigned char)Gray;
    *(lpTempPtr++)=(unsigned char)Gray;
    *(lpTempPtr++)=(unsigned char)Gray;
    *(lpTempPtr++)=0;
    } if(hPalette!=NULL)                     
            DeleteObject(hPalette);

    hPalette=CreatePalette(pPal);
    LocalUnlock(hPal);
    LocalFree(hPal); hDc=::GetDC(m_hWnd);
    if(hPalette){
            hPrevPalette=SelectPalette(hDc,hPalette,FALSE);
    RealizePalette(hDc);
    }

    if(NumColors==0)
    for(y=0;y<bi.biHeight;y++){
    lpPtr=(char *)lpImgData+(SrcBufSize-LineBytes-y*LineBytes);
    lpTempPtr=(char *)lpTempImgData+(DstBufSize-DstLineBytes-y*DstLineBytes);
    for(x=0;x<bi.biWidth;x++){
    Blue=(unsigned char )(*lpPtr++);
    Green=(unsigned char )(*lpPtr++);
    Red=(unsigned char )(*lpPtr++);
    Y=(float)(Red*0.299+Green*0.587+Blue*0.114);
    Gray=(BYTE)Y;
    *(lpTempPtr++)=(unsigned char)Gray;
    }
    }    if(hBitmap!=NULL)
        DeleteObject(hBitmap);

    hBitmap=CreateDIBitmap(hDc, (LPBITMAPINFOHEADER)lpTempImgData, (LONG)CBM_INIT,
    (LPSTR)lpTempImgData+sizeof(BITMAPINFOHEADER) +NewNumColors*sizeof(RGBQUAD),
        (LPBITMAPINFO)lpTempImgData, DIB_RGB_COLORS); if(hPalette && hPrevPalette){
    SelectPalette(hDc,hPrevPalette,FALSE);
    RealizePalette(hDc);
    }    hf=_lcreat(BmpFileName,0);
    _lwrite(hf,(LPSTR)&DstBf,sizeof(BITMAPFILEHEADER)); 
    _lwrite(hf,(LPSTR)lpTempImgData,DstBufSize);
    _lclose(hf); ::ReleaseDC(m_hWnd,hDc);
    LocalUnlock(hTempImgData);
    LocalFree(hTempImgData);
    GlobalUnlock(hImgData);
    return TRUE;
      

  2.   

    HFILE              hf;
        LPBITMAPINFOHEADER lpImgData;
        LOGPALETTE         *pPal;
        LPRGBQUAD          lpRGB;
        HPALETTE           hPrevPalette; 
        HDC                hDc;
    HLOCAL             hPal;
    DWORD         ImgSize;
    DWORD              i;

        if((hf=_lopen(BmpFileName,OF_READ))==HFILE_ERROR){
            MessageBox("Can not Load file","Error",MB_OK|MB_ICONEXCLAMATION);
            return FALSE;
    }
    _lread(hf,(LPSTR)&bf,sizeof(BITMAPFILEHEADER)); 
    _lread(hf,(LPSTR)&bi,sizeof(BITMAPINFOHEADER));
    ImgWidth=bi.biWidth;
    ImgHeight=bi.biHeight;
    LineBytes=(DWORD)WIDTHBYTES(bi.biWidth*bi.biBitCount);
    ImgSize=(DWORD)LineBytes*bi.biHeight;
        if(bi.biClrUsed!=0)
    NumColors=(DWORD)bi.biClrUsed;
    else
            switch(bi.biBitCount){
    case 1:
    NumColors=2;
    break;
    case 4:
    NumColors=16;
    break;
    case 8:
    NumColors=256;
    break;
    case 24:
    NumColors=0;
    break;
    default:
    MessageBox("Invalid color numbers!","Error Message",MB_OK|MB_ICONEXCLAMATION);
    _lclose(hf);
    return FALSE; 
    NumColors = 0;
    break;
    }

    if(bf.bfOffBits!=(DWORD)(NumColors*sizeof(RGBQUAD)+sizeof(BITMAPFILEHEADER)
    +sizeof(BITMAPINFOHEADER)))
    {
    MessageBox("Invalid color numbers!","Error Message" ,MB_OK|
    MB_ICONEXCLAMATION);
    _lclose(hf);
    return FALSE; 
    }

    bf.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+NumColors*sizeof(RGBQUAD)+ImgSize;
    if((hImgData=GlobalAlloc(GHND,(DWORD)(sizeof(BITMAPINFOHEADER)+
    NumColors*sizeof(RGBQUAD)+ImgSize)))==NULL)
    {
    MessageBox("Error alloc memory!","ErrorMessage",MB_OK|
    MB_ICONEXCLAMATION);
    _lclose(hf);
    return FALSE;
    }

    lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData); 
        _llseek(hf,sizeof(BITMAPFILEHEADER),FILE_BEGIN);
    _hread(hf,(char *)lpImgData,(long)sizeof(BITMAPINFOHEADER)
    +(long)NumColors*sizeof(RGBQUAD)+ImgSize);
    _lclose(hf);
        if(NumColors!=0)
    {                    
    hPal=LocalAlloc(LHND,sizeof(LOGPALETTE) + NumColors* sizeof(PALETTEENTRY));
    pPal =(LOGPALETTE *)LocalLock(hPal);
    pPal->palNumEntries =(WORD) NumColors;
    pPal->palVersion    = 0x300;
    lpRGB = (LPRGBQUAD)((LPSTR)lpImgData + (DWORD)sizeof(BITMAPINFOHEADER));
    for (i = 0; i < NumColors; i++) {
    pPal->palPalEntry[i].peRed=lpRGB->rgbRed;
    pPal->palPalEntry[i].peGreen=lpRGB->rgbGreen;
    pPal->palPalEntry[i].peBlue=lpRGB->rgbBlue;
    pPal->palPalEntry[i].peFlags=(BYTE)0;
    lpRGB++;
    }
    hPalette=CreatePalette(pPal);
    LocalUnlock(hPal);
    LocalFree(hPal);
    }
    hDc=::GetDC(m_hWnd);
    if(hPalette){
            hPrevPalette=SelectPalette(hDc,hPalette,FALSE);
    RealizePalette(hDc);
    }
    hBitmap=CreateDIBitmap(hDc, (LPBITMAPINFOHEADER)lpImgData, (LONG)CBM_INIT,
    (LPSTR)lpImgData+sizeof(BITMAPINFOHEADER) +NumColors*sizeof(RGBQUAD),
    (LPBITMAPINFO)lpImgData, DIB_RGB_COLORS);
    if(hPalette && hPrevPalette){
    SelectPalette(hDc,hPrevPalette,FALSE);
    RealizePalette(hDc);
    }

    ::ReleaseDC(m_hWnd,hDc);
    GlobalUnlock(hImgData);
      

  3.   

    黑白?那不就成二值图了,用8位色太浪费空间了吧~~~或许你想说的是灰度?灰度化的实质就是把RGB三个通道的值都取亮度不过亮度的取值又和设备的色彩空间标准有关,一般用的比较多的是近似的NTSC亮度计算公式Y=0.3*Red+0.59*Green+0.11*Blue又可以近似的用下面的代码计算Gray=(77*Red+151*Green+28*Blue)>>8;第二个问题嘛,留给你自己思考,似乎很容易得到答案
      

  4.   

    //仅对8位,24位图像进行灰度处理,将灰度图存为 8 位,并赋值处理数组。
    void CDib::Gray()
    {
    long linebits = WIDTHBYTES(8*m_nWidth);
    //分配处理数组内存
    if(!m_pDataS)
    {
    m_pDataS = new double[linebits*m_nHeight];
    } unsigned char bitCount=GetBitCount();
        // 灰度映射表
    unsigned char bMap[256];
    if(bitCount==8)
    {

    for(int i=0;i<256;i++)
    {
    bMap[i]=(unsigned char)(0.299*m_pRGBQuad[i].rgbRed+
    0.587*m_pRGBQuad[i].rgbGreen+
    0.114*m_pRGBQuad[i].rgbBlue+0.5);
    m_pRGBQuad[i].rgbRed=i;
    m_pRGBQuad[i].rgbGreen=i;
    m_pRGBQuad[i].rgbBlue=i;
    m_pRGBQuad[i].rgbReserved=0;
    }
    // 更换每个象素的颜色索引(即按照灰度映射表换成灰度值)
    long lw=WIDTHBYTES(m_nWidth*8);
    for(long j=0l;j<m_nHeight;j++)
    {
    for(long i=0l;i<m_nWidth;i++)
    {
    long jj=j*lw+i;
    m_pDibData[jj]=bMap[m_pDibData[jj]];
    m_pDataS[j*m_nWidth+i]=(double)bMap[m_pDibData[jj]];
    }
    }
    }
    else if(bitCount==24)
    {
    //计算相应的 8 位图大小
    unsigned long dwFileSize = sizeof(BITMAPFILEHEADER) + m_pBitmapInfoHeader->biSize
    + 256 * sizeof(RGBQUAD) + WIDTHBYTES(m_nWidth*8) * m_nHeight;

    //写 BITMAPFILEHEADER
    BITMAPFILEHEADER bfh;
    memcpy(&bfh,m_pBitmapFileHeader,sizeof(BITMAPFILEHEADER));
    bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + m_pBitmapInfoHeader->biSize
    + 256 * sizeof(RGBQUAD);
    bfh.bfSize = dwFileSize;
    m_fileLeng = dwFileSize;
    //写 BITMAPINFOHEADER
    BITMAPINFOHEADER bih;
    memcpy(&bih,m_pBitmapInfoHeader,m_pBitmapInfoHeader->biSize);
    bih.biBitCount = 8;
    bih.biSizeImage = (unsigned long)WIDTHBYTES(m_nWidth*8) * (unsigned long)m_nHeight;
    bih.biClrUsed = 256;

    //写 RGBQUAD
    RGBQUAD rgbq[256];
    for(int i=0;i<256;i++)
    {
    rgbq[i].rgbRed=i;
    rgbq[i].rgbGreen=i;
    rgbq[i].rgbBlue=i;
    rgbq[i].rgbReserved=0;
    } //写位图数据
    unsigned char* pData = new unsigned char[bih.biSizeImage];
    long lw=WIDTHBYTES(m_nWidth*24);

    for(long j=0l;j<m_nHeight;j++)
    {
    for(long i=0l;i<m_nWidth;i++)
    {
    long jj=j*lw;
    long ii=3*i;
    unsigned char gray = (unsigned char)(0.299*(m_pDibData[jj+ii])+
    0.587*(m_pDibData[jj+ii+1])+0.114*(m_pDibData[jj+ii+2])+0.5);
    pData[j*linebits+i] = gray;
    m_pDataS[j*linebits+i] = gray;
    }
    }
    //重新申请内存文件
    m_pFileData = m_memFile.Detach();
    ASSERT(m_pFileData = (BYTE *) realloc((void * )m_pFileData,dwFileSize));
    m_memFile.Attach(m_pFileData,dwFileSize, GROWBYTES);
    m_memFile.Seek(0l,CFile::begin);
    m_memFile.Write(&bfh,sizeof(BITMAPFILEHEADER));
    m_memFile.Write(&bih,sizeof(BITMAPINFOHEADER));
    m_memFile.Write(rgbq,256 * sizeof(RGBQUAD));
    m_memFile.Write(pData,bih.biSizeImage); SetPara();
    delete[] pData;
    }
    }理论如楼上所说,,需要代码的话给我留言!
      

  5.   

    变成灰阶一般是0.3*r+0.59*g+0.11*b
    也可以直接(r+g+b)/3
      

  6.   

    这是我参考一个网上朋友的,运行没错,但是保存成文件时,文件位空,大家能否帮我看看那儿的错误啊?
    HDIB MakeGrayFile(HDIB pColorBmp,long nDisplayHeight,long nDisplayWidth)
    {

    //将RGB模式的位图转换为256色灰度位图

    long BmpLength =  WIDTHBYTES(8*nDisplayWidth)*nDisplayHeight + sizeof(RGBQUAD)*256;// + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
    HDIB hGrayDIB = (HDIB)::GlobalAlloc(GHND,BmpLength+sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)); 
    LPSTR pGrayDIB = (LPSTR)GlobalLock((HGLOBAL)hGrayDIB);
    LPSTR pColorDIB = (LPSTR)GlobalLock((HGLOBAL)pColorBmp); char *pgray = new char[BmpLength];
    LPSTR read = ::FindDIBBits(pColorDIB);//(char*)pColorBmp + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) ;
    char *write = pgray; //构造调色板信息
    for(int i=0;i<256;i++)
    {
    *(write+i*4) = i;
    *(write+i*4+1) = i;
    *(write+i*4+2) = i;
    *(write+i*4+3) = 0;
    }
    write += sizeof(RGBQUAD)*256; //指针条到象素数据区 int r,g,b;
    float Y;
    BYTE gray;
    for(int h=0;h<nDisplayHeight;h++)
    {
    for(int w=0;w<nDisplayWidth;w++)
    {
    g = (unsigned char)*read++;
    b = (unsigned char)*read++;
    r = (unsigned char)*read++;
    //提取灰度分量
    Y=(float)(r*0.299+g*0.587+b*0.114);
    gray = (BYTE)Y;
    *write = gray;
    write++;
    }
    } //拷贝新的灰度位图调色板信息和像素数据
    //设置位图文件头
    BITMAPFILEHEADER   bmfHdr; 
    bmfHdr.bfType = DIB_HEADER_MARKER;//0x4D41;//2;  // "BM"
    //BmpLength = bmfHdr.bfSize = nDisplayWidth*nDisplayHeight + sizeof(RGBQUAD)*256 + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
    bmfHdr.bfSize = (DWORD)WIDTHBYTES(8*nDisplayWidth)*nDisplayHeight + (DWORD)(sizeof(RGBQUAD)*256) + (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
    bmfHdr.bfReserved1 = 0;
    bmfHdr.bfReserved2 = 0;
    bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER)
    + (DWORD)sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256;
    //拷贝位图文件头
    memcpy(pGrayDIB, &bmfHdr, sizeof(BITMAPFILEHEADER)); //设置位图信息头
    BITMAPINFOHEADER bi;
    bi.biSize            = sizeof(BITMAPINFOHEADER);
    bi.biWidth           = nDisplayWidth;
    bi.biHeight          = nDisplayHeight;
    bi.biPlanes          = 1;
    bi.biBitCount        = 8;
    bi.biCompression     = BI_RGB;
    bi.biSizeImage       = WIDTHBYTES(8*nDisplayWidth)*nDisplayHeight;
    bi.biXPelsPerMeter   = 0;
    bi.biYPelsPerMeter   = 0;
    bi.biClrUsed         = 0;
    bi.biClrImportant    = 0;
    memcpy(pGrayDIB + sizeof(BITMAPFILEHEADER), &bi, sizeof(BITMAPINFOHEADER)); //拷贝新的灰度位图调色板信息和像素数据
    memcpy(pGrayDIB + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER), 
    pgray,  BmpLength);
    //释放分配的临时空间
    delete pgray;
    GlobalUnlock((HGLOBAL)hGrayDIB);
    return hGrayDIB;
    }
      

  7.   

    就这样简单
    CImage img;
    img.Load("c:\\test.bmp");
    for(int x=0;x<image.GetWidth();x++)
    {
    for(int y=0;y<img.GetHeight();y++)
    {
     c=img.GetPixel(x,y);
     r=GetRValue(c);
     g=GetRValue(c);
     b=GetRValue(c);
     newcolor=(r+g+b)/3>128?255:0;
     img.SetPixel(x,y,RGB(newcolor,newcolor,newcolor));
    }
    }
    img.Save("c:\\test1.jpg")
    图象已经成为黑白的了!
    注意包含头文件:"atlimage.h"
      

  8.   

    you can see freeimage.dll