我用的方法是:
创建一个MEMORY DC HDC hdc=CreateCompatibleDC(NULL);
HBITMAP hBitmap=CreateBitmap(width,height,1,8,NULL); //256色
SelectObject(hdc,hBitmap);然后把24位的那个BMP 画到 hdc,再将hBitmap保存成文件,完成转换.这样做各位觉得如何? 有何缺点?
用同样的方法转成二值时,一些东东在新图中看不到了,变成空白.欢迎提出你的看法.

解决方案 »

  1.   

    这样转的效果会好么?windows里所自带的画图就是强行把24bit画入8bit..惨不忍睹
      

  2.   

    自己根据BMP图片的格式,自行将图片进行抽样处理
      

  3.   

    用二叉树算出各部分的分布
    每个R[0-FF]下有G[0-FF](每八个一组)
    每个G[0-FF]下有B[0-FF](每八个一组)
    先算出单节点超过1%的就提出来,然后父节点减去对应分布
    再在剩下的找合并
      

  4.   

    Windows 图象编程中有8叉树的算法,有没有更简单的方法?我用100分来讨论这个问题,怎么没人气?
      

  5.   

    抖动,是指当在低分辨率下看较高分辨率的图像、低色模式下显示更多色模式(如在VGA16色图形模式下显示256色及全彩色图像)时出现的颜色和图像变形的问题。
    解决这个问题的算法就是抖动算法。下面是一篇这方面的文字,应该会对你有所帮助。 在16色模式下显示256色及全彩色
    该文描述了在VGA16色图形模式下显示256色及全彩色图像的抖动算法,并给出了 显示BitMap图像的C语言程序。 
        关键词 抖动算法 亮度矩阵 显示 
        在编写有关图像显示的软件时,有时为了软件的兼容性和通用性,不得不采用VGA标准的图形模式,这就涉及到如何在16色图形模式下显示256色及全彩色图像的问题。解决这一问题有两种方法。一种是采用色彩近似的方法,即根据需要显示的全部颜色,经过寻优来选择16种最具代表性的颜色,每一种颜色都用这16种颜色中最接近的一种来代替。《计算机世界月刊》1994年第1期的《用集群方法进行颜色选择》一文详细描述了该方法。但事实上,该方法仅对于某些理想的情况适用,而对于更普遍的情况,该方法无论从运算速度还是从处理效果来讲,都不可能令人感到满意,因而不宜在实际中运用。另一种方法是被众多商品化软件所广泛采用的抖动技术,其原理是利用多种可见颜色的组合来模拟一种不可见的颜色。目前,关于彩色图像抖动算法的资料不多。笔者通过对灰度图像处理算法及Windows环境下一些图像处理软件的剖析,得出了抖动算法的一般原理和实现方法.
        一、抖动算法原理 
        我们知道,在256色及全彩色图像中,每一种颜色均由R、G、B三个颜色分量组成,而每一个分量又一般由一个字节表示。这样,每一个颜色分量可有256级亮度变化。    本算法的关键在于引入亮度矩阵的概念,即采用一个16×16的矩阵来表示每一个颜色分量的亮度值,不同亮度值对应着矩阵的不同排列。矩阵全为0时对应亮度0,全为255时对应亮度255。 
        当亮度值为L时,亮度矩阵中将有[L255×256]个255及[(1-L255)×256]个0,此时,矩阵的平均亮度值为 
        L'={[L/255×256]×255+[(1-L/255)×256]×0}/256=L 
        这就是说,矩阵的平均亮度正好为颜色分量的实际亮度。 
        假设某一颜色C的R、G、B三个颜色分量的亮度矩阵分别为: @@01A04600.GIF;公式一@@ 
        其中rmn、gmn、bmn(0≤m, n≤15)取值为0或15。 
        将上述三个矩阵作叠加运算,得@@01A04601.GIF;公式二@@ 
        其中的Cmn为表1中由rmn、gmn、bmn所确定的颜色值。表1为VGA16色图形模式下的标准调色板(并非设置模式后的缺省调色板)。显然,Cmn只可能为0及9~15之中的一个。由此方法得到的矩阵Mc即可视为颜色C的模拟矩阵。由于颜色C的R、G、B三个颜色分量与亮度矩阵MR、MG、MB有着相等的亮度值,所以矩阵MC从视觉效果上来讲能很好地模拟颜色C。但在显示时,不可能用整个这样的矩阵来替代一个像素点,那将导致整幅图像长宽均变成原图的16倍。实际的做法是:若该像素点距离图像原点的座标为(X,Y),则令: 
        m=Y mod 16 
        n=X mod 16       (1) 
        此时,可用MC中的颜色Cmn来显示该像素。 @@01A04602.GIF;表1 16色图形模式标准调色板@@ 
        二、算法实现 
        1.亮度矩阵的表示 
        算法中要用到257个16×16的亮度矩阵,如果对每一个都分别表示的话,将占用很大的内存空间(大于64K)。由于亮度矩阵的排列及增长均有一定的规律性,我们只需要采用一个16×16的矩阵即可。该矩阵中256个元素的取值分别为0~255,按一定规律排列。令其为: 
    @@01A04603.GIF;公式三@@ 
        亮度为L时的矩阵可由H变化而来,其中@@01A04604.GIF;公式四@@ 
        2.颜色查找表算法中只用到了颜色0及9~15,我们可以忽略其他项并将有用部分表示为一个三维数组形式的颜色查找表,如表2所示。此时,r, g, b值作为数组下标,取值为0或1。与之相应,我们将(2)式变为@@01A04605.GIF;公式三@@ 
        3.每一像素的显示步骤 
        ①对256色图像,由颜色索引值查颜色映射表获取R、G、B值;对全彩色图像,直接读取R、G、B值; 
        ②根据像素座标(X,Y),由(1)式求得m, n; 
        ③根据R、G、B值,由(3)式求得rmn、gmn、bmn; 
        ④由rmn、gmn、bmn查表2得颜色值C; 
        ⑤将像素以颜色C显示于(X,Y)处。 
        本文所附程序用于在16色图形模式下显示256色及全彩色BitMap图像。 
        关于BitMap图像的格式及读取方法,许多资料均有介绍,这里不再赘述。 
        该程序由Turbo C 2.0及Borland C 3.1编译,在386兼容机上运行通过。运行方法为:   show文件名.BMP 
    @@01A04606.GIF;公式三表2 颜色查找表@@ 
        事实证明,采用本文所描述的算法,可以得到与许多商品化软件相似的处理速度和处理效果。 
        源程序:
      

  6.   

    #include<stdio.h> 
        #include<dos.h> 
        #include<stdio.h> 
        #include<conio.h> 
        #define NoError 0 
        #define ErrorFileOpen1 
        #define ErrorFileType 2 
        #define ErrorImageColor 3 
        typedef struct tagBITMAPFILEHEADER { 
            unsigned int   bfType; 
            unsigned longbfSize; 
            unsigned intbfReserved1;  unsigned intbfReserved2; 
            unsigned longbfoffBits; 
        } BITMAPFILEHEADER; 
        typedef struct tagBITMAPINFOHEADER { 
            unsigned longbiSize; 
            unsigned long  biWidth; 
            unsigned longbiHeight; 
            unsigned intbiPlanes; 
            unsigned intbiBitCount; 
            unsigned long biCompression; 
            unsigned long biSizeImage; 
            unsigned long biXPelsPerMeter; 
            unsigned long biYPelsPerMeter; 
            unsigned long biClrUsed; 
            unsigned long biClrImportant; 
        } BITMAPINFOHEADER; 
        typedef struct tagRGBQUAD { 
            unsigned char rgbBlue; 
            unsigned char rgbGreen; 
            unsigned charrgbRed; 
            unsigned char rgbReserved; 
        } RGBQUAD; 
        void main(int argc,char *argv[]); 
        int ShowBmp(char *FileName); 
        int GetColor(unsigned char R,unsigned char G, unsigned char B,int X,int Y) 

        void SetVideoMode(unsigned char Mode); 
        void SetPalReg(unsigned char *palReg); 
        void SetDacReg(unsigned char *DacReg, int Color, int Count); 
        void PutPixel(int X, int Y,unsigned char Color); 
        unsigned char PalReg[17]= {  0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0}; 
        unsigned char StandardPal[48]= { 
        0, 0, 0, 32, 0, 0, 0,32, 0, 32,32, 0,   0, 0,32, 32, 0,32, 0,32,32, 32,32, 
    32,  48,48,48, 63, 0, 0, 0,63, 0, 63,63, 0,   0, 0,63, 63, 0,63, 0,63,63, 63,6 
    3,63,}; 
        unsigned char LightnessMatrix [16][16]= { 
        { 0,235,59,219,15,231,55,215,2,232,56,217,12,229,52,213}, 
        {128,64,187,123,143,79,183,119,130,66,184,120,140,76,180,116}, 
        {33,192,16,251,47,207,31,247,34,194,18,248,44,204,28,244}, 
        {161,97,144,80,175,111,159,95,162,98,146,82,172,108,156,92}, 
        {8,225,48,208,5,239,63,223,10,226,50,210,6,236,60,220}, 
        {136,72,176,112,133,69,191,127,138,74,178,114,134,70,188,124}, 
        {41,200,24,240,36,197,20,255,42,202,26,242,38,198,22,252}, 
        {169,105,152,88,164,100,148,84,170,106,154,90,166,102,150,86}, 
        {3,233,57,216,13,228,53,212,1,234,58,218,14,230,54,214}, 
        {131,67,185,121,141,77,181,117,129,65,186,122,142,78,182,118}, 
        {35,195,19,249,45,205,29,245,32,193,17,250,46,206,30,246}, 
        {163,99,147,83,173,109,157,93,160,96,145,81,174,110,158,94}, 
        {11,227,51,211,7,237,61,221,9,224,49,209,4,238,62,222}, 
        {139,75,179,115,135,71,189,125,137,73,177,113,132,68,190,126}, 
        {43,203,27,243,39,199,23,253,40,201,25,241,37,196,21,254}, 
        {171,107,155,91,167,103,151,87,168,104,153,89,165,101,149,85}, 
        }; 
        unsigned char ColorTable[2][2][2]= { 
        {{0,12},{10,14}},{{9,13},{11,15}}}; 
        unsigned char ColorMap[256][3]; 
        void main (int argc, char *argv[]) 
        { 
            if(argc!=2) { 
                    printf("Usage:\n\tSHOW Filename.BMP\n"); 
                    exit(1); 
            } 
            ShowBmp(argv[1]); 
        } 
        int ShowBmp(char *FileName) 
        { 
            FILE *Fp; 
            BITMAPFILEHEADER FileHead; 
            BITMAPINFOHEADER InfoHead; 
            RGBQUAD RGB; 
            int N, W,Y,X,C,Color; 
            unsigned char Buffer[4096]; 
            if (!(Fp=fopen(FileName,"rb"))) 
                    return(ErrorFileOpen); 
            fread(&FileHead,siazeof(BITMAPFILEHEADER),1,Fp); 
            if(FileHead.bfType!='BM') 
                    return(ErrorFileType); 
            fread(&InfoHead,sizeof(BITMAPFILEHEADER),1,Fp); 
            if(InfoHead.biBitcount!=8 && InfoHead.biBitCount!=24) { 
                    fclose(Fp); 
                    return(ErrorImageColor); 
            } 
            SetVideoMode(0x12); 
            SetPalReg(PalReg); 
            SetDacReg(StandardPa1,0,16); 
            if(InfoHead.biBitcount==8) { 
                    for (N=0;N<256;N++) { 
                            fread(&RGB, sizeof(RGBQUAD),1,Fp); 
                            ColorMap[N][0]=RGB.rgbRed; 
                            ColorMap[N][1]=RGB.rgbGreen; 
                            ColorMap[N][2]=RGB.rgbBlue; 
                    } 
                    W=(InfoHead.biwidth+3)/4*4; 
                    for(Y=InfoHead.biHeight-1;Y>=480;Y--) 
                            fread(Buffer,sizeof(unsigned char),W,Fp); 
                    for(;Y>0;Y--) { 
                            fread(Buffer, sizeof(unsigned char),w,FP); 
                            for (X=0;X<InfoHead.biWidth && X<640;X++) { 
                                    C=Buffer[X]; 
                                    Color=GetColor(ColorMap[C][0],ColorMap[C][1],C 
    olorMap[C][2],X,Y); 
                                    PutPixel (X,Y,color); 
                            } 
                    } 
            } 
            else { 
                    W=(infoHead.biWidth*3+3)/4*4; 
                    for(Y=InfoHead.biHeight-1;Y>639;Y--) 
                            fread(Buffer,sizeof(unsigned char),W,Fp); 
                    for(;Y>=0;Y--) { 
                            fread(Buffer,sizeof(unsigned char),W,Fp); 
                            for (X=0;X<InfoHead.biWidth && X<640;X++) { 
                                    C=X*3; 
                                    Color=GetColor(Buffer[C+2],Buffer[C+1],Buffer[ 
    C],X,Y); 
                                    PutPixel(X,Y,color); 
                            } 
                    } 
            } 
            getch(); 
            fclose(Fp); 
            SetVideoMode(0x03); 
            return(NoError); 
            } 
            int GetColor(unsigned char R, unsigned char G,unsigned char B, int X, 
    int Y){ 
            unsigned int L=LightnessMatrix[Y & 0x0F][X & 0x0F]; 
            return(colorTable[( 
                            unsigned int)R*256/255>L][( 
                            unsigned int)G*256/255>L][( 
                            unsigned int)B*256/255>L]);} 
            void SetVideoMode(unsigned char Mode){ 
                    -H=0x00; 
                    -AL=Mode; 
                    geninterrupt(0x10); 
            } 
            voidSetPalReg(unsigned char *PalReg){ 
                    -ES=FP-SEG((unsigned char far*)PalReg); 
                    -DX=FP-OFF((unsigned char far*)PalReg; 
                    -AX=0x1002; 
                    geninterrupt(0x10); 
            } 
            void SetDacReg(unsigned char *DacReg,int Color,int Count){ 
                    -ES=FP-SEG((unsigned char far*)DacReg); 
                    -DX=FP-OFF((unsigned char far*)DacReg); 
                    -AX=0x1012; 
                    -BX=Color; 
                    -CX=Count; 
                    geninterrupt(0x10); 
            } 
            void PutPixel(int X, int Y, unsigned charColor){ 
                    -AH=0x0C; 
                    -AL=Color; 
                    -CX=X; 
                    -DX=Y; 
                    geninterrupt(0x10); 
            } 
        }
      

  7.   

    用API GetDiBits 和 SetDiBits 就可以了//参数、返回值说明
    //HDC 一个合法的DC
    //HBITMAP 原始位图
    //UINT 需要的颜色数
    //返回值:新生成的位图(用完注意 DeleteObject)HBITMAP ColorBitmap(HDC hdc,HBITMAP hBmpSrc,UINT nColor){
    HBITMAP hCreate = NULL;
    char * lpHeader = NULL;
    char * lpBits = NULL; __try{
    __try{
    BITMAP bmp;
    if(GetObject(hBmpSrc,sizeof(BITMAP),&bmp) == 0){
    __leave;
    } BITMAPINFOHEADER bmpInfo;
    memset(&bmpInfo,0,sizeof(BITMAPINFOHEADER));

    bmpInfo.biSize = sizeof(BITMAPINFOHEADER);
    bmpInfo.biWidth = bmp.bmWidth;
    bmpInfo.biHeight = bmp.bmHeight;
    bmpInfo.biPlanes = 1; //设置新的位图的颜色数
    //可以设置的数值有
    //1 - 2色
    //4 - 16色
    //8 - 256色
    //16 - 16位色
    //24 - 24位色
    bmpInfo.biBitCount = nColor;

    //256色(包含256)以下的位图需要调色版,
    //下面是计算所需调色版空间大小
    int nHeadSize = nColor > 8 ? 0 : 1 << 8;
    nHeadSize *= sizeof(RGBQUAD);

    //加上位图信息头的空间大小
    nHeadSize += sizeof(BITMAPINFOHEADER);

    //为信息头和调色版分配空间
    lpHeader = new char[nHeadSize];
    BITMAPINFOHEADER * lpBmpInfo = 
    (BITMAPINFOHEADER *)lpHeader;

    * lpBmpInfo = bmpInfo;

    //GetBIBits 取得存储位图数据所需空间
    if(::GetDIBits(hdc,
                   hBmpSrc,
                   0,  //数据开始的扫描线,从0开始
                   bmp.bmHeight,//数据结束的扫描线,位图高
          NULL, //数据存储缓冲区,= NULL则会返需求量
          (LPBITMAPINFO)lpBmpInfo,
          DIB_RGB_COLORS) == 0)
    {
    __leave;
    }

    //为位图数据分配空间
    lpBits = new char[lpBmpInfo->biSizeImage]; 

    //GetBIBits 取得存储位图数据
    if(::GetDIBits(hdc,
          hBmpSrc,
          0,
          bmp.bmHeight,
          lpBits,
          (LPBITMAPINFO)lpBmpInfo,
          DIB_RGB_COLORS) == 0)
    {
    __leave;
    }

    //生成新位图
    hCreate = ::CreateCompatibleBitmap(hdc
                                                                  bmp.bmWidth,
                                                                  bmp.bmHeight);
    if(hCreate == NULL){
    __leave;
    }

    //将位图数据写入新位图中
    ::SetDIBits(hdc,
       hCreate,
       0,
       bmp.bmHeight,
       lpBits,
       (LPBITMAPINFO)lpBmpInfo,
       DIB_RGB_COLORS);  
    }__except(EXCEPTION_EXECUTE_HANDLER){
    __leave;
    }
    }__finally{
    if(lpHeader != NULL){
    delete [] lpHeader;
    } if(lpBits != NULL){
    delete [] lpBits;
    }
    } return hCreate;
    }
      

  8.   

    sorry 有点笔误
    int nHeadSize = nColor > 8 ? 0 : 1 << 8;
    改为
    int nHeadSize = nColor > 8 ? 0 : 1 << nColor;
      

  9.   

    to xlt123:你的方法和我的有何不同?
      

  10.   

    也没什么不同,
    不过将所有工作放在内存中完成,
    将转化工作交给API做而已
      

  11.   

    8叉树是效果很好的算法的其中之一,还有更好的?
    用8叉树量化好的palatte再作误差扩散,效果应该不错的了..
      

  12.   

    你是不是想高逼真的将彩色图片24bit转换成8bit的.彩色图片变成黑白图片使用的是抖动算法,抖动算法对图像的分辨率有影响.(你要有心理准备)上面那位兄弟把抖动算法介绍的很详细.我就不多说了,
    我主要说一下24bit->8bit.
    目前你有两种选择,1.彩色统计算法(流行色法)
    首先对彩色图象中的所有彩色做统计分析.由此可以得出一个彩色直方图.取统计结果的前256种颜色作为原图像的颜色.图像其余所有的颜色用最小距离映射到调色板.
    因为R\G\B是一种高度相关的颜色模型,所以计算其欧氏空间的距离时用下面公式:
    d(x,x') = sqrt(w1 * (r - r')^2 + w2 * (g - g')^2 + w3 * (b - b')^2)
    w1 = 3 w2 = 6 w3 = 1或者w1 = 4 w2 = 8 w3 = 1都可以;2.中位切分法
    将图像的色彩空间用RGB模型来表示,彩色立方体的每一个轴相对应于R\G\B三基色之一.每一根轴都量化为从0到255,0对应黑,255对应于亮度最大.这样,图像中任一色彩都可以用RGB彩色立方体切分成256个小立方体,没一个小立方提中都包含相同的相素,
      

  13.   

    楼主:我最近正在做一个论文,当中正好用到24Bit->8bit转换.有很多好算法,不过也不方便写给你,上面给出的是最简单也是比较容易想到的.如果你觉得以上两个算法你还不能满足,我这还有终级算法,不过你要有心理准备,算法的时间杂度是非常高的,用的知识也是非常的古懊.