日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【学习图像处理】之实验二——灰度图像直方图规定化

發(fā)布時間:2023/12/20 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【学习图像处理】之实验二——灰度图像直方图规定化 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

灰度圖像直方圖規(guī)定化

    • 圖像增強(qiáng)
      • 一、實驗內(nèi)容
      • 二、灰度直方圖
        • 1、什么是灰度直方圖?
        • 2、直方圖均衡化
        • 3、直方圖規(guī)定化
      • 三、代碼實現(xiàn)與分析
        • 0、輔助功能實現(xiàn)
        • 1、繪制原圖像直方圖SH
        • 2、繪制均衡直方圖SQH ,給出均衡圖象QI
        • 3、繪出目標(biāo)均衡直方圖EQH
        • 4、繪制規(guī)定化變換函數(shù)T,給出最終增強(qiáng)圖象DI及其直方圖DH
    • 結(jié)語

圖像增強(qiáng)

上一回我們通過進(jìn)行圖像反白、調(diào)整調(diào)色板取值和彩圖變灰圖的實驗對bmp圖像的數(shù)據(jù)格式有了比較熟練的了解。其實一張圖片上往往只有很少一部分信息是我們真正需要的,而這些信息卻埋沒于茫茫的像素之中,利用起來很不方便,因此我們就需要對圖像進(jìn)行增強(qiáng)。
增強(qiáng)什么?當(dāng)然是依據(jù)需求定向的加強(qiáng)指定內(nèi)容。今天的主題就是對灰度圖像進(jìn)行直方圖均衡化(Histogram Equalization)與直方圖規(guī)定化(Histogram Specifications)處理。

一、實驗內(nèi)容

  • 繪出原圖象直方圖SH
  • 繪出直方圖SH的均衡直方圖SQH ,給出均衡圖象QI
  • 繪出目標(biāo)直方圖EH的均衡直方圖EQH
  • 繪出完成規(guī)定化任務(wù)的變換函數(shù)T,給出最終增強(qiáng)圖象DI及其直方圖DH
  • 二、灰度直方圖

    1、什么是灰度直方圖?

    對于灰度圖而言,畫面是由很多個不同灰度值的像素組成的,圖像中灰度的分布情況就成為了一個很重要的特征信息,因為它直接決定了整張圖片什么信息最為突出,而另一些則不太明顯。
    灰度直方圖,即是對圖像中每個灰度級的像素數(shù)做了統(tǒng)計,繪制成的以灰度級為橫坐標(biāo),像素個數(shù)(頻率)為縱坐標(biāo)的圖像,它能夠直觀的體現(xiàn)灰度圖像中某種灰度出現(xiàn)的概率,表達(dá)式為: Pr(rk)=nknPr(rk)=\frac{nk}{n}Pr(rk)=nnk? ,其中rkrkrk為灰階,nknknk表示灰度級為rkrkrk的像元數(shù)目。
    當(dāng)然直方圖也有一個很明顯的缺點,就是它丟失了像素所在位置的信息。

    2、直方圖均衡化

    一般一張自然的灰度圖都會集中在相對較窄的一段灰階內(nèi),這樣就會導(dǎo)致細(xì)節(jié)丟失。如果我們通過某種手段,把灰度區(qū)間拉大或者讓灰度盡可能均勻分布,這樣做就可以增大圖像對比度,從而把細(xì)節(jié)信息顯示出來。
    直方圖均衡化就是一種達(dá)成上述目的的手段。均衡化處理后,灰度范圍變大,對比度變大,清晰度變大,能夠有效增強(qiáng)圖像。其具體的推導(dǎo)過程涉及概率論中知識,感興趣可以看這位作者撰寫的直方圖均衡化的數(shù)學(xué)原理,而它的作用解釋可以見直方圖均衡化作用。
    對于我們寫代碼而言,只需要知道最終的變換公式即可:
    y=f(x)=(L?1)∑0xih(xi)w?hy=f(x)=(L-1)\sum_{0}^{x_i} \frac{h(x_i)}{w*h}y=f(x)=(L?1)0xi??w?hh(xi?)?

    3、直方圖規(guī)定化

    上面講到了直方圖均衡化,現(xiàn)在有一個問題:如果兩張圖片s和u,他們都可以均衡化到t,那是否意味著s可以通過某種方法轉(zhuǎn)換成u呢?答案是肯定的,我們用幾個公式來表示s、u、t間的關(guān)系:
    t=T(sk)=∑i=0kps(si)t=T(s_k)=\sum_{i=0}^{k} p_s(s_i)t=T(sk?)=i=0k?ps?(si?) (1) k=0,1,...,M?1k=0,1,...,M-1k=0,1,...,M?1
    t=Tu(uj)=∑j=0lpu(uj)t=T_u(u_j)=\sum_{j=0}^{l} p_u(u_j)t=Tu?(uj?)=j=0l?pu?(uj?) (2) l=0,1,...,N?1l=0,1,...,N-1l=0,1,...,N?1

    由此可見,我們想要通過均衡化的結(jié)果逆求出u是可行的。我們只需要找到s到u的映射關(guān)系T,而這個關(guān)系應(yīng)該是:
    ∣∑i=0kps(si)?∑i=0lpu(uj)∣|\sum_{i=0}^{k} p_s(s_i)-\sum_{i=0}^{l} p_u(u_j)|i=0k?ps?(si?)?i=0l?pu?(uj?)

    三、代碼實現(xiàn)與分析

    這次實驗中我們用下面這張圖作為原圖像:

    0、輔助功能實現(xiàn)

    如果你仔細(xì)分析一下實驗的每一步,會發(fā)現(xiàn)我們需要多次的存儲用以繪制直方圖的數(shù)據(jù),而且這個數(shù)據(jù)往往是保存在一個數(shù)組之中,因此我們可以專門寫一個函數(shù)將數(shù)組保存到txt文件中去。

    template<typename T> bool array2txt(T &H,const char* cFilename) //將一個數(shù)組輸出到以cFilename命名的txt文件中 { ofstream outfile;outfile.open(cFilename, ios::out);if (!outfile.is_open()){cout << "Open file failure" << endl;return false;}for (int i = 0; i < (sizeof(H)/sizeof(H[0])); i++) //遍歷數(shù)組寫入txt{outfile << H[i] << "\t" ;}return true; }

    可以看到,這里我為了能夠反復(fù)利用使用了模版函數(shù)和c++中的文件流輸出語句,以此來避免文件輸出時該用%d還是%f的問題。不過實際上我們大部分?jǐn)?shù)據(jù)都是float類型的數(shù)組,所以模版函數(shù)是可選的。

    1、繪制原圖像直方圖SH

    正式開始實驗,在本次實驗中的直方圖我都以“灰階-概率”的形式輸出,如果你想輸出“灰階-頻率”的直方圖,那么不要除以總數(shù)即可。

    float* outHistogramData(BMPFILE &src,const char*cFilename)//將繪制“灰階-概率”直方圖的數(shù)據(jù)保存到txt文件中 {float H[256] = { 0 }; //8bit的灰度圖,256灰階int i, j;float *result = (float*)malloc(256 * sizeof(float));int total = src.imageh * src.imagew;for (i = 0; i < src.imageh; i++)for (j = 0; j < src.imagew; j++){H[src.pDataAt(i)[j]] += 1.0; //對每個灰階進(jìn)行計數(shù)}for (i = 0; i < 256; i++){H[i] /= (float)total; //計算圖像概率p(Sk)result[i] = H[i];}if (!array2txt(H,cFilename)){printf("outHistogramData error!\n");exit(0);}return result; }

    這里一定要注意,如果你想要返回函數(shù)中新建的一個數(shù)組,那么一定要用malloc對它進(jìn)行內(nèi)存分配,否則返回后的指針將是野指針。同時,由于我array2txt函數(shù)的定義問題,它不可以接受一個指針表示的數(shù)組,這個可以由你自行修改。我的解決辦法是單獨創(chuàng)建一個定長數(shù)組H[256],讓它傳入array2txt函數(shù),另分配一個指針result返回結(jié)果。

    我們得到的txt文本中數(shù)據(jù)大致長這個樣子(后面的過程我就不貼數(shù)據(jù)的圖了)


    把這些數(shù)據(jù)導(dǎo)入到Excel表格中即可做出我們要的直方圖SH:

    2、繪制均衡直方圖SQH ,給出均衡圖象QI

    根據(jù)我們之前的分析,均衡直方圖的求解需要對“灰階-概率”數(shù)據(jù)進(jìn)行累加處理,然后再擴(kuò)展到8bit對應(yīng)的0-255范圍上。這里“灰階-概率”我們可以利用上一步中得到的數(shù)據(jù)(當(dāng)然你也可以再算一遍,少傳一個參數(shù))

    float* HistEqualize(BMPFILE &src,BMPFILE &des,float* hist_data, const char*cFilename) //已知灰階-概率矩陣,做直方圖均衡化 {float count_origin[256] = { 0 }, T[256] = { 0 }, count_new[256] = { 0 };//count_origin用來記錄原圖像各灰階個數(shù),count_new是均衡化之后的結(jié)果float *result = (float*)malloc(256 * sizeof(float)); //返回均衡化后的灰階-概率矩陣int i, j;int total = src.imageh * src.imagew;for (i = 0; i < 256; i++){count_origin[i] = hist_data[i] * total; //求原圖中的灰階計數(shù)}for (i = 0; i < 256; i++)for (j = 0; j <= i; j++){T[i] += hist_data[j]; //求得均衡化之后的tkresult[i] = T[i]; //如果需要作圖的那么result=count_new,如果需要均衡化result=T}if(!array2txt(T, "tk_data.txt")){printf("outHistogramData error!\n");exit(0);}for (i = 0; i < 256; i++){T[i] = int((256 - 1)*T[i] + 0.5); //用式tk=int((L-1)*tk+0.5)將tk擴(kuò)展至[0,L-1]范圍,得到灰度級}for (i = 0; i < src.imageh; i++)for (j = 0; j < src.imagew; j++){des.pDataAt(i)[j] = T[src.pDataAt(i)[j]]; //將新的值賦予給輸出圖像}for (i = 0; i < 256; i++){count_new[int(T[i])] += count_origin[i]; //根據(jù)新的灰度級求新的計數(shù)}for (i = 0; i < 256; i++){count_new[i] /= (float)total; //計算新圖像概率p(tk)//result[i] = count_new[i]; //如果需要作圖的那么result=count_new,如果需要均衡化result=T}if(!array2txt(count_new, cFilename)){printf("outHistogramData error!\n");exit(0);}des.SaveBMPFILE("QI.bmp");return result; }

    對于最后輸出圖像的賦值以及灰階的重新計數(shù)如果有不明白的,可以看看下面這張圖:


    我舉一個例子,如果原圖中灰度級為3,那么它在輸出圖像中的灰度級就應(yīng)該是T[3]=6。這就是為什么

    des.pDataAt(i)[j] = T[src.pDataAt(i)[j]]; count_new[int(T[i])] += count_origin[i]; //count_new初值為0

    得到的均衡直方圖SQH如圖:

    均衡圖像QI則是:

    3、繪出目標(biāo)均衡直方圖EQH

    可能是直接給出直方圖數(shù)據(jù)缺乏挑戰(zhàn)性,老師給了我們一個函數(shù),要求將函數(shù)轉(zhuǎn)換為目標(biāo)直方圖。函數(shù)表達(dá)式為:
    y=a(14(x?12)2)y=a(\frac{1}{4}(x-\frac{1}{2})^{2})y=a(41?(x?21?)2)x∈[0,1]x\in[0,1]x[0,1]
    注意到函數(shù)中含有未知量a,所以我們需要找到方程解出a的值。既然它代表直方圖,那么它就應(yīng)該符合直方圖的性質(zhì)——頻率之和為1。有了這個入手點,我們就可以列方程了:
    1=∫01f(x)dx1=\int_{0}^{1} f(x)dx1=01?f(x)dx
    接下來通過微分的基本思想,求解未知數(shù):

    float calculateA() //計算 y=a(1/4-(x-1/2)^2)中的a { //一種比較直觀且簡單的算法是分割成多份然后求面積和,最后用1/sum即可求得a(因為概率和應(yīng)為1)int i;float x[1000]; //定義域[0,1]分割成0.001為步長的1000份float y[1000]; //值域float sum = 0;for (i = 0; i < 1000; i++) //由于c語言只能用整數(shù)下標(biāo),因此只能將x取值存為數(shù)組{x[i] = i * 0.001;}for (i = 0; i < 1000; i++) //計算x對應(yīng)的y值{y[i] = (0.25 - pow((x[i] - 0.5), 2)); //y=(1/4-(x-1/2)^2)}for (int i = 0; i < 1000; i++) //計算面積和{sum += y[i] * 0.001;}return (1 / sum); }

    求得a的值無限逼近于6,因此函數(shù)即為y=6(14(x?12)2)y=6(\frac{1}{4}(x-\frac{1}{2})^{2})y=6(41?(x?21?)2)。接下來我們需要把圖像放縮到0-255的區(qū)間上,可以仿照上面的微分思路,將0-1均分為256份,然后分別求概率值即可(注意結(jié)果也要相應(yīng)放縮)。
    這樣我們就得到了目標(biāo)直方圖EH的“灰階-概率”數(shù)據(jù),將其傳入2中函數(shù)(這里理論上是無法得出圖像的,但是因為u也是s經(jīng)過某種處理后得到的圖像,因此我們可以將s作為原圖傳入函數(shù)中),即可求得EQH:

    4、繪制規(guī)定化變換函數(shù)T,給出最終增強(qiáng)圖象DI及其直方圖DH

    在完成步驟2、3的過程中我們已經(jīng)求得了SQH_tk和EQH_tk兩個數(shù)組,即直方圖規(guī)定化所需要的所有數(shù)據(jù)已經(jīng)齊了,接下來我們按照公式去求規(guī)定化需要的映射函數(shù)T。規(guī)定化的主要步驟就是把SQH_tk中的每一個灰度映射到一個EQH_tk中與之差值最小的灰度值上,由于tk是單調(diào)遞增的,因此我們只需要判斷到第一個大于SQH_tk[i]的值即可。得到映射函數(shù)T之后,我們將原圖像中的像素按照映射關(guān)系重新賦值即可得到DI。代碼如下:

    int* HistSpecificate(HXLBMPFILE &src, HXLBMPFILE &des, float* hist_data, const char*cFilename) //直方圖規(guī)定化 {int i, j, index=0;float *SQH_tk = HistEqualize(src, des, "SQH.txt"); //獲取原圖像的均衡化tk數(shù)組float *EQH_tk = HistEqualize(src, des, hist_data,"EQH.txt"); //獲取目標(biāo)圖像的均衡化tk數(shù)組int T[256]; //灰階對應(yīng)關(guān)系矩陣int *result = (int*)malloc(256 * sizeof(int));float min, temp;for (i = 0; i < 256; i++){min = fabs(SQH_tk[i] - EQH_tk[0]); //假設(shè)最小值for (j = index; j < 256; j++){temp = fabs(SQH_tk[i] - EQH_tk[j]); //依次做差找到最小值if (temp < min){min = temp;index=j;}if (SQH_tk[i] < EQH_tk[j])break;}T[i] = index; //保存映射結(jié)果result[i] = index;}if(!array2txt(T,"HistSpecificate.txt")){printf("outHistogramData error!\n");exit(0);}for (i = 0; i < src.imageh; i++)for (j = 0; j < src.imagew; j++){des.pDataAt(i)[j] = T[src.pDataAt(i)[j]]; //將新的值賦予給輸出圖像}des.SaveBMPFILE("DI.bmp");outHistogramData(des, cFilename);return result; }

    最終得到的變換函數(shù)T如圖:


    增強(qiáng)圖像DI與其直方圖DH分別是:

    結(jié)語

    第二次圖像處理的實驗,說實話直方圖均衡化的代碼寫起來很簡單,但是真正的重點在于如何理解直方圖均衡化以及規(guī)定化的意義,因為實際應(yīng)用中我們可以直接從opencv這樣的庫中調(diào)用函數(shù)。況且如果是為了寫代碼而寫,那么完全可以去一些OJ網(wǎng)站刷題,因此對于算法的理解才是學(xué)習(xí)過程中應(yīng)該注意的地方。
    本次實驗完整的項目文件與代碼可見我的gitee。

    總結(jié)

    以上是生活随笔為你收集整理的【学习图像处理】之实验二——灰度图像直方图规定化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。