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

📄 图像处理.txt

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

DstLineBytes-y*DstLineBytes);

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

            //R,G,B各取4位

            Blue=(int)(*(lpPtr++) & 0xf0);

            Green=(int)(*(lpPtr++) & 0xf0);

            Red=(int)(*(lpPtr++) & 0xf0);

            //拼成一个12位整数

            ClrIndex=(Blue<<4) + Green +(Red >>4);

            for (i = 0; i < PalCounts;i++)

                if (ClrIndex == ColorIndex[i]){

//根据12索引值取得对应的调色板中的索引值

                    *(lpTempPtr++)=(unsigned char)ColorHits[i];

                    break;

                }

        }

    }

    if(hBitmap!=NULL)

        DeleteObject(hBitmap);

    //产生新的位图  

    hBitmap=CreateDIBitmap(hDc, (LPBITMAPINFOHEADER)lpTempImgData, 

 (LONG)CBM_INIT,    (LPSTR)lpTempImgData+sizeof(BITMAPINFOHEADER) +

256*sizeof(RGBQUAD),    (LPBITMAPINFO)lpTempImgData, DIB_RGB_COLORS);

    if(hPalette && hPrevPalette){

        SelectPalette(hDc,hPrevPalette,FALSE);

        RealizePalette(hDc);

    }

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

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

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

    _lclose(hf);

    //释放内存和资源

    ReleaseDC(hWnd,hDc);

    LocalUnlock(hTempImgData);

    LocalFree(hTempImgData);

    GlobalUnlock(hImgData);

    return TRUE;

}

 

    以下我们将要介绍灰度变换,针对的都是256级灰度图。

4.对比度扩展(contrast stretching)

    假设有一幅图,由于成象时光照不足,使得整幅图偏暗,(例如,灰度范围从0到63);或者成象时光照过强,使得整幅图偏亮,(例如,灰度范围从200到255),我们称这些情况为低对比度,即灰度都挤在一起,没有拉开。灰度扩展的意思就是把你所感兴趣的灰度范围拉开,使得该范围内的像素,亮的越亮,暗的越暗,从而达到了增强对比度的目的。我们可以用如下的图来说明对比度扩展的原理。

                       

图5. 对比度扩展的原理

    图中的横坐标gold表示原图的灰度值,纵坐标gnew表示gold经过对比度扩展后得到了新的灰度值。a,b,c为三段直线的斜率,因为是对比度扩展,所以斜率b>1。g1old和g2old表示原图中要进行对比度扩展的范围,g1new和g2new表示对应的新值。用公式表示为  

        a*gold                      当0<=gold<g1old时

gnew=  b*(gold-g1old)+g1new     当g1old<=gold<g2old时

        c*(gold-g2old)+g2new        当g2old<gold<=255时

显然要得到对比度扩展后的灰度,我们需要知道a,b,c,g1old,g2old五个参数。由于有新图的灰度级别也是255这个约束,所以满足a*g1old+b*(g2old-g1old)+c(255-g2old)=255这个方程。这样,我们只需给出四个参数,而另一个可以可以代入方程求得。我们假设a=c,这样,我们只要给出b,g1old和g2old,就可以求出  

a=(255-b*(g2old-g1old))/(255-(g2old-g1old)) 

要注意的是,给出的三个参数必须满足1. b*(g2old-g1old)<=255;2. (g2old-g1old)<=255

这两点是显然的。

    下图为图1取g1old=100;g2old=150 ;b=3.0进行对比度扩展的结果。可以看出亮的区域(雕塑)变得更亮,暗的区域(手)变得更暗。

                              

图6. 图1对比度扩展后的结果

下面的这段程序实现了对比度扩展。首先出现对话框,输入b,g1old,g2old的三个参数(在程序中分别是StretchRatio,SecondPoint,FirstPoint),然后对调色板做响应的处理,而实际的位图数据不用动。

BOOL ContrastStretch(HWND hWnd)

{

    DLGPROC                dlgInputBox = NULL;

    DWORD              BufSize;

    LPBITMAPINFOHEADER lpImgData;

    LPSTR                  lpPtr;

    HLOCAL                 hTempImgData;

    LPBITMAPINFOHEADER lpTempImgData;

    LPSTR                 lpTempPtr;

    HDC                   hDc;

    HFILE                  hf;

    LOGPALETTE          *pPal;

    HPALETTE             hPrevPalette=NULL; 

    HLOCAL               hPal;

    DWORD                i;

    unsigned char         Gray;

    float                   a,g1,g2,g;

 

    if( NumColors!=256){ //必须是256级灰度图

        MessageBox(hWnd,"Must be a 256 grayscale bitmap!","Error Message",MB_OK|

MB_ICONEXCLAMATION);

        return FALSE;

}

//出现对话框,输入三个参数

    dlgInputBox = (DLGPROC) MakeProcInstance ( (FARPROC)InputBox, ghInst );

    DialogBox (ghInst, "INPUTBOX", hWnd, dlgInputBox);

    FreeProcInstance ( (FARPROC) dlgInputBox );

    if( StretchRatio*(SecondPoint-FirstPoint) > 255.0){ //参数不合法

MessageBox(hWnd,"StretchRatio*(SecondPoint-FirstPoint) can not be larger than 255!","Error Message",MB_OK|MB_ICONEXCLAMATION);

        return FALSE;

    }

if( (SecondPoint-FirstPoint) >=255){ //参数不合法

            MessageBox(hWnd,"The area you selected can not be the whole scale!",

"Error Message",MB_OK|MB_ICONEXCLAMATION);

        return FALSE;

}

//计算出第一和第三段的斜率a

    a=(float)((255.0-StretchRatio*(SecondPoint-FirstPoint))

/(255.0-(SecondPoint-FirstPoint))); 

    //对比度扩展范围的边界点所对应的新的灰度

    g1=a*FirstPoint;

    g2=StretchRatio*(SecondPoint-FirstPoint)+g1;

    //新开的缓冲区的大小

    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(hImgData);    

    lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTempImgData);

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

    memcpy(lpTempImgData,lpImgData,BufSize);

    hDc=GetDC(hWnd);

    //lpPtr指向原图数据缓冲区,lpTempPtr指向新图数据缓冲区

    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 < 256; i++) {

        Gray=(unsigned char )*lpPtr;

        lpPtr+=4;

        //进行对比度扩展

        if(Gray<FirstPoint) g=(float)(a*Gray);

        else if (Gray<SecondPoint) g=g1+StretchRatio*(Gray-FirstPoint);

        else g=g2+a*(Gray-SecondPoint);

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

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

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

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

        *(lpTempPtr++)=(unsigned char)g;

        *(lpTempPtr++)=(unsigned char)g;

        *(lpTempPtr++)=(unsigned char)g;

        *(lpTempPtr++)=0;

    }

    if(hPalette!=NULL)                     

        DeleteObject(hPalette);

    //产生新的逻辑调色板

    hPalette=CreatePalette(pPal);

    LocalUnlock(hPal);

    LocalFree(hPal);

    if(hPalette){

        hPrevPalette=SelectPalette(hDc,hPalette,FALSE);

        RealizePalette(hDc);

    }

    if(hBitmap!=NULL)

        DeleteObject(hBitmap);

    //产生新的位图  

    hBitmap=CreateDIBitmap(hDc, (LPBITMAPINFOHEADER)lpTempImgData, 

(LONG)CBM_INIT, (LPSTR)lpTempImgData+sizeof(BITMAPINFOHEADER) +

NumColors*sizeof(RGBQUAD),(LPBITMAPINFO)lpTempImgData, DIB_RGB_COLORS);

    if(hPalette && hPrevPalette){

        SelectPalette(hDc,hPrevPalette,FALSE);

        RealizePalette(hDc);

    }

    hf=_lcreat("c:\\stretch.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;

}

 

5.削波(cliping)

削波可以看作是对比度扩展的一个特例,我们用如下的图说明削波的原理。

                                   

图7. 削波的原理

不难看出,只要令对比度扩展中的a=c=0就实现了削波。我们只要给出范围的两个端点,斜率b就可以用方程b*(g2old-g1old)=255求出。

    下图为图1取g1old=150;g2old=200 进行削波的结果。把亮的区域(雕塑)提取了出来。

                          

图8. 图1削波处理后的结果

削波的程序和对比度扩展的程序很类似,就不再给出了。

 

6.阈值化(thresholding)

阈值化可以看作是削波的一个特例,我们用如下的图说明阈值化的原理。

                                     

图9. 阈值化的原理

不难看出,只要令削波中的g1old=g2old就实现了阈值化。阈值就象个门槛,比它大就是白,比它小就是黑。经过阈值化处理后的图象变成了黑白二值图,所以说阈值化是灰度图转二值图的一种常用方法(我们以前介绍过图案化和抖动的方法)。阈值化只需给出阈值点,即g1old即可。

下图为图1阈值取128,阈值化处理后的结果,得到了一幅黑白图。

                      

图10. 图1阈值化处理后的结果

阈值化的程序和对比度扩展的程序很类似,就不再给出了。

 

7.灰度窗口变换(slicing) 

灰度窗口变换是将某一区间的灰度级和其它部分(背景)分开。我们用如下的图说明灰度窗口变换的原理。其中[g1old,g2old]称为灰度窗口。

                                          

图11. 清除背景的灰度窗口变换的原理

                                          

图12. 保留背景的灰度窗口变换的原理

灰度窗口变换有两种,一种是清除背景的,一种是保留背景的。前者把不在灰度窗口范围内的像素都赋值为0,在灰度窗口范围内的像素都赋值为255,这也能实现灰度图的二值化;后者是把不在灰度窗口范围内的像素保留原灰度值,在灰度窗口范围内的像素都赋值为255。

灰度窗口变换可以检测出在某一灰度窗口范围内的所有像素,是图象灰度分析中的一个有力工具。下面有三幅图,图13为原图,图14是经过清除背景的灰度窗口变换处理后的图(灰度窗口取[200-255]),将夜景中大厦里的灯光提取了出来。图15是经过保留背景的灰度窗口变换处理后的图(灰度窗口取[200-255]),将夜景中大厦里的灯光提取了出来,同时保留了大厦的背景,可以看出它们的差别还是很明显的。

    
图13. 原图        图14. 图13经过清除背景      图15. 图13经过保留背景的

的灰度窗口变换处理后的图     灰度窗口变换处理后的图

灰度窗口变换的程序和对比度扩展的程序很类似,就不再给出了。

我突然想起了不久前在一本科学杂志上看到的一篇文章,非常有趣,是介绍电影〈阿甘正传〉特技制作的。其中有一项就用到了类似灰度窗口变换的思想。相信看过这部电影的读者都会对那个断腿的丹尼上校有深刻的印象。他的断腿是怎么拍出来的呢?其实方法很简单,先拍一幅没有演员出现的背景画面,然后拍一幅有演员出现,其它不变的画面。要注意的是,此时演员的腿用蓝布包裹。把前后两幅图输入计算机进行处理。第二幅图中凡是遇到蓝色的像素,就用第一幅图中对应位置的背景像素代替。这样,一位断腿的上校就逼真的出现在屏幕上了。这就是电影特技中经常用到的“蓝幕”技术。

说点题外话,其实现代电影,特别是好莱坞的电影,越来越离不开计算机及图象处理技术。最近引起轰动的大片<Titanic>中的很多特技镜头就是利用了庞大的SGI图形工作站机群没日没夜的计算产生的。图象处理技术和我们所喜爱的电影艺术紧密的结合了起来,这更增加了我们学习它的兴趣。

 

8.灰度直方图统计(histogram)

    有时我们需要知道一幅图中的灰度分布情况,这时就可以采用灰度直方图来表示,图中的横坐标表示灰度值,纵坐标表示该灰度值出现的次数(频率)。图16为图13的灰度直方图,可见,低灰度的像素占了绝大部分。

             

图16. 图13的灰度直方图

 

下面的程序显示一幅图的灰度直方图。有两段程序,第一段统计出每个灰度的像素个数,存放在数组GrayTable[]中,然后产生一个新的窗口,把统计结果显示出来。第二段程序就是该窗口的消息处理函数。要注意的是,由于各灰度出现的频率可能相差很大,所以如何将结果显示在有限的窗口范围内,是一个必须考虑的问题。我们这里的做法是,在所有出现的灰度中,统计出一个最大值max和一个最小值min,假设能显示的窗口最大坐标为270,最小坐标为5,按成比例显示,这样,灰度出现的次数和显示坐标之间呈线形关系,设 a*grayhits+b=coordinate,其中grayhits为灰度出现的次数,coordinate为显示坐标,a和b为两个常数。我们将max和min代入,应该满足a*max+b=270 ;  a*min+b=5

可以解得a=265/(max-min);    b=270.0-a* max 。

    还有一点,不要忘了在WinMain函数中注册那个新产生窗口的窗口类。

int GrayTable[256];

int MaxGrayNum;

int MinGrayNum;

BOOL Histogram(HWND hWnd)

{

    DWORD               OffBits,BufSize;

    LPBITMAPINFOHEADER lpImgData;

    LPSTR                 lpPtr;

    int                    x,y;

    int                     grayindex;

    HWND                   hPopupWnd;

    int                     temp;

    //计数器清零

    for(grayindex=0;grayindex<256;grayindex++)

        GrayTable[grayindex]=0;

    //OffBits为到实际位图数据的偏移值

    OffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER);

//BufSize为缓冲区的大小

    BufSize=bf.bfSize-sizeof(BITMAPFILEHEADER);

    lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData);

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

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

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

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

            GrayTable[grayindex]++; //对应的颜色计数值加1

⌨️ 快捷键说明

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