⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 图像处理.txt

📁 用数字图像处理主要是为了修改图形,改善图像质量,或是从图像中提起有效信息,还有利用数字图像处理可以对图像进行体积.
💻 TXT
📖 第 1 页 / 共 4 页
字号:
第五讲 直方图修正和彩色变换

    这一讲,我们主要和调色板打交道。先从最简单的反色讲起。

1. 反色(invert)

    反色就是形成底片效果。如下图所示,图2为图1反色后的结果

                  

图1. 原图

                  

图2. 图1反色后的结果

反色有时是很有用的,比如说,图1中黑色区域占绝大多数,这样打印起来很费墨,我们可以先进行反色处理再打印。反色的实际含义是将R,G,B值反转。若颜色的量化级别是256,则新图的R,G,B值为255减去原图的R,G,B值。这里针对的是所有图,包括真彩图,带调色板的彩色图(又称为伪彩色图),和灰度图。针对不同种类有不同的处理。

先看看真彩图。我们知道真彩图不带调色板,每个像素用3个字节,表示R,G,B三个分量。所以处理很简单,把反转后的R,G,B值写入新图即可。再来看看带调色板的彩色图,我们知道位图中的数据只是对应调色板中的一个索引值,我们只需要将调色板中的颜色反转,形成新调色板,而位图数据不用动,就能够实现反转。灰度图是一种特殊的伪彩色图,只不过调色板中的R,G,B值 都是一样的而已。所以反转的处理和上面讲的一样。

这里,我想澄清一个概念。过去我们讲二值图时,一直都说成黑白图。二值位图一定是黑白的吗?答案是不一定。我们安装Windows95时看到的那幅setup.bmp是由蓝色和黑色组成的,但它实际上是二值图。原来,它的调色板中的两种颜色是黑与蓝,而不是黑与白。所以说二值图也可以是彩色的,只不过一般情况下是黑白图而已。

下面的程序实现了反色,注意其中真彩图和调色板位图处理时的差别。

BOOL Invert(HWND hWnd)

{

    DWORD                BufSize;

    LPBITMAPINFOHEADER lpImgData;

    LPSTR                 lpPtr;

    HLOCAL               hTempImgData;

    LPBITMAPINFOHEADER lpTempImgData;

    LPSTR                 lpTempPtr;

    HDC                   hDc;

    HFILE                 hf;

    LONG                 x,y;

    LOGPALETTE          *pPal;

    HPALETTE             hPrevPalette=NULL; 

    HLOCAL              hPal;

    DWORD               i;

    unsigned char           Red,Green,Blue;

 

    BufSize=bf.bfSize-sizeof(BITMAPFILEHEADER); //新开缓冲区的大小

    if((hTempImgData=LocalAlloc(LHND,BufSize))==NULL)

    {

        MessageBox(hWnd,"Error alloc memory!","Error 

Message",MB_OK|

MB_ICONEXCLAMATION);

return FALSE;

        }

    lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgDa

ta);    

    lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTe

mpImgData);

    //拷贝头信息

    memcpy(lpTempImgData,lpImgData,BufSize);

 

    hDc=GetDC(hWnd);

    if(NumColors!=0){ //NumColors不为0说明是带调色板的

    lpPtr=(char 

*)lpImgData+sizeof(BITMAPINFOHEADER); //指向原图数据

        lpTempPtr=(char 

*)lpTempImgData+sizeof(BITMAPINFOHEADER); //指向新图数据

    //为新调色板分配内存

    hPal=LocalAlloc(LHND,sizeof(LOGPALETTE) + 

NumColors* 

sizeof(PALETTEENTRY));

        pPal =(LOGPALETTE *)LocalLock(hPal);

        pPal->palNumEntries =(WORD) NumColors;

        pPal->palVersion    = 0x300;

        for (i = 0; i < NumColors; i++) {

            Blue=(unsigned char )(*lpPtr++);

            Green=(unsigned char )(*lpPtr++);

            Red=(unsigned char )(*lpPtr++);

            lpPtr++;

            //反转调色板中的颜色,存入新的调色板

            pPal->palPalEntry[i].peRed=(BYTE)(255-Red);

            pPal->palPalEntry[i].peGreen=(BYTE)(255-Green);

            pPal->palPalEntry[i].peBlue=(BYTE)(255-Blue);

            pPal->palPalEntry[i].peFlags=0;

            *(lpTempPtr++)=(unsigned char)(255-Blue);

            *(lpTempPtr++)=(unsigned char)(255-Green);

            *(lpTempPtr++)=(unsigned char)(255-Red);

            *(lpTempPtr++)=0;

        }

 

        if(hPalette!=NULL)                     

            DeleteObject(hPalette);

        hPalette=CreatePalette(pPal); //产生新的调色板

        LocalUnlock(hPal);

        LocalFree(hPal);

        if(hPalette){

            hPrevPalette=SelectPalette(hDc,hPalette,FALSE);

            RealizePalette(hDc);

        }

    }

    else{ //不带调色板,说明是真彩色图

        for(y=0;y<bi.biHeight;y++){

            lpPtr=(char *)lpImgData+(BufSize-LineBytes-

y*LineBytes);

            lpTempPtr=(char *)lpTempImgData+(BufSize-

LineBytes-y*LineBytes);

            for(x=0;x<bi.biWidth;x++){

                Blue=(unsigned char )(*lpPtr++);

                Green=(unsigned char )(*lpPtr++);

                Red=(unsigned char )(*lpPtr++);

            //反转位图数据中的颜色,存入新的位图数据中

                *(lpTempPtr++)=(unsigned char)(255-Blue);

                *(lpTempPtr++)=(unsigned char)(255-Green);

                *(lpTempPtr++)=(unsigned char)(255-Red);

            }

        }

    }

    if(hBitmap!=NULL)

        DeleteObject(hBitmap);

hBitmap=CreateDIBitmap(hDc,

    (LPBITMAPINFOHEADER)lpTempImgData, 

                          (LONG)CBM_INIT,

              

(LPSTR)lpTempImgData+sizeof(BITMAPINFOHEADE

R) +

  NumColors*sizeof(RGBQUAD),

                  

(LPBITMAPINFO)lpTempImgData, DIB_RGB_COLORS);

    if(hPalette && hPrevPalette){

        SelectPalette(hDc,hPrevPalette,FALSE);

        RealizePalette(hDc);

    }

    hf=_lcreat("c:\\invert.bmp",0);

    _lwrite(hf,(LPSTR)&bf,sizeof(BITMAPFILEHEADER)); 

    _lwrite(hf,(LPSTR)lpTempImgData,BufSize);

    _lclose(hf);

    //释放内存和资源

    ReleaseDC(hWnd,hDc);

    LocalUnlock(hTempImgData);

    LocalFree(hTempImgData);

    GlobalUnlock(hImgData);

    return TRUE;

}

 

2. 彩色图转灰度图(color to grayscale) 

我们在第二讲时提到了YUV的颜色表示方法,知道在这种表示方法中,Y分量的物理含义就是亮度,它含了灰度图的所有信息,只用Y分量就完全能够表示出一幅灰度图来。YUV和RGB之间有着如下的对应关系 
我们利用上式,根据R,G,B的值求出Y值后,将R,G,B值都赋值成Y,就能表示出灰度图来,这就是彩色图转灰度图的原理。

先看看真彩图。我们知道真彩图不带调色板,每个像素用3个字节,表示R,G,B三个分量。所以处理很简单,根据R,G,B的值求出Y值后,将R,G,B值都赋值成Y,写入新图即可。再来看看带调色板的彩色图,我们知道位图中的数据只是对应调色板中的一个索引值,我们只需要将调色板中的彩色变成灰度,形成新调色板,而位图数据不用动,就可以了。

下面的程序实现了彩色图到灰度图的转换,注意其中真彩图和调色板位图处理时的差别。

BOOL ColortoGrayScale(HWND hWnd)

{

    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; //NewNumColors为新图的颜色数

    NewBitCount=bi.biBitCount;  //NewBitCount为新图的颜色位数

    if(NumColors==0) //真彩图

    {

        NewNumColors=256;

        NewBitCount=8;

    }

//由于颜色位数有可能发生了改变,所以要重新计算每行占用的字节数以及新图

//的缓冲区大小

    DstLineBytes=(DWORD)WIDTHBYTES(bi.biWidth*NewBit

Count);

    DstBufSize=(DWORD)(sizeof(BITMAPINFOHEADER)+Ne

wNumColors*

sizeof(RGBQUAD)+(DWORD)DstLineBytes*bi.bi

Height);

    //DstBf和DstBi为新的BITMAPFILEHEADER和

BITMAPINFOHEADER

    //拷贝原来的头信息

    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(hWnd,"Error alloc memory!","Error 

Message",MB_OK|

MB_ICONEXCLAMATION);

        return FALSE;

    }

    lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgDa

ta);    

    lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTe

mpImgData);

//拷贝头信息和位图数据

    memcpy(lpTempImgData,lpImgData,DstBufSize);

    //用新的BITMAPINFOHEADER替换原来的头信息

    memcpy(lpTempImgData,(char 

*)&DstBi,sizeof(BITMAPINFOHEADER));

    //lpPtr指向原图的数据

    lpPtr=(char *)lpImgData+sizeof(BITMAPINFOHEADER);

    //lpTempPtr指向新图的数据

    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) //真彩色

        for (i = 0; i < 256; i++) { //灰度从(0,0,0)到(255,255,255)

            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++;

            //从原来的调色板中的颜色计算得到Y值,写入新的调色板

            pPal->palPalEntry[i].peRed=Gray;

            pPal->palPalEntry[i].peGreen=Gray;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -