轉自: https://blog.csdn.net/ebowtang/article/details/38236441#
關於圖像增強必須清楚的基本概念
1.圖像增強的目的:
1)改善圖像的視覺效果,
2)轉換爲更適合於人或機器分析處理的形式
3)突出對人或機器分析有意義的信息
4)抑制無用信息,提高圖像的使用價值
5)增強後的圖像並不一定保真
2,圖像增強的方法分類:
1)從處理對象分類:灰度圖像,(僞)彩色圖像
2)從處理策略分類:全局處理,局部處理(ROI ROI,Region of Interest Interest)
3)從處理方法分類:空間域(點域運算,即灰度變換;鄰域方法,即空域濾波),頻域方法
4)從處理目的分類:圖像銳化,平滑去噪,灰度調整(對比度增強)
3,圖像增強的方法之對比度增強
1)灰度變換法
線性變換(已實現)
對數變換(已實現)
指數變換(已實現)
2)直方圖調整法
直方圖均衡化(已實現)
直方圖匹配(未實現)
一,直方圖均衡化
直方圖均衡化的英文名稱是Histogram Equalization.
圖像對比度增強的方法可以分成兩類:一類是直接對比度增強方法;另一類是間接對比度增強方法。直方圖拉伸和直方圖均衡化是兩種最常見的間接對比度增強方法。直方圖拉伸是通過對比度拉伸對直方圖進行調整,從而“擴大”前景和背景灰度的差別,以達到增強對比度的目的,這種方法可以利用線性或非線性的方法來實現;直方圖均衡化則通過使用累積函數對灰度值進行“調整”以實現對比度的增強。直方圖均衡化處理的“中心思想”是把原始圖像的灰度直方圖從比較集中的某個灰度區間變成在全部灰度範圍內的均勻分佈。直方圖均衡化就是對圖像進行非線性拉伸,重新分配圖像像素值,使一定灰度範圍內的像素數量大致相同。直方圖均衡化就是把給定圖像的直方圖分佈改變成“均勻”分佈直方圖分佈。
缺點:
1)變換後圖像的灰度級減少,某些細節消失;
2)某些圖像,如直方圖有高峯,經處理後對比度不自然的過分增強。
直方圖均衡化是圖像處理領域中利用圖像直方圖對對比度進行調整的方法。
這種方法通常用來增加許多圖像的局部對比度,尤其是當圖像的有用數據的對比度相當接近的時候。通過這種方法,亮度可以更好地在直方圖上分佈。這樣就可以用於增強局部的對比度而不影響整體的對比度,直方圖均衡化通過有效地擴展常用的亮度來實現這種功能。
這種方法對於背景和前景都太亮或者太暗的圖像非常有用,這種方法尤其是可以帶來X光圖像中更好的骨骼結構顯示以及曝光過度或者曝光不足照片中更好的細節。這種方法的一個主要優勢是它是一個相當直觀的技術並且是可逆操作,如果已知均衡化函數,那麼就可以恢復原始的直方圖,並且計算量也不大。這種方法的一個缺點是它對處理的數據不加選擇,它可能會增加背景雜訊的對比度並且降低有用信號的對比度。
關於編程實現,同樣是不調用matlab庫函數,自己編程實現。這樣可以更深刻地理解直方圖均衡化技術,提高編程能力。
實現代碼(matlab):
- clc;
- close all;
- clear all;
- src_img = imread('flyman_gray.bmp');
- figure (1)
- subplot(321),imshow(src_img),title('原圖像');%顯示原始圖像
- subplot(322),imhist(src_img),title('原圖像直方圖');%顯示原始圖像直方圖
- matlab_eq=histeq(src_img); %利用matlab的函數直方圖均衡化
- subplot(323),imshow(matlab_eq),title('matlab直方圖均衡化原圖像');%顯示原始圖像
- subplot(324),imhist(matlab_eq),title('matlab均衡化後的直方圖');%顯示原始圖像直方圖
- dst_img=myHE(src_img); %利用自己寫的函數直方圖均衡化
- subplot(325),imshow(dst_img),title('手寫均衡化效果');%顯示原始圖像
- subplot(326),imhist(dst_img),title('手寫均衡化直方圖');%顯示原始圖像直方圖
直方圖均衡化函數的實現:
- function dst_img=myHE(src_img)
- [height,width] = size(src_img);
- dst_img=uint8(zeros(height,width));
- %進行像素灰度統計;
- NumPixel = zeros(1,256);%統計各灰度數目,共256個灰度級
- for i = 1:height
- for j = 1: width
- NumPixel(src_img(i,j) + 1) = NumPixel(src_img(i,j) + 1) + 1;%對應灰度值像素點數量增加一
- end
- end
- %計算灰度分佈密度
- ProbPixel = zeros(1,256);
- for i = 1:256
- ProbPixel(i) = NumPixel(i) / (height * width * 1.0);
- end
- %計算累計直方圖分佈
- CumuPixel = zeros(1,256);
- for i = 1:256
- if i == 1
- CumuPixel(i) = ProbPixel(i);
- else
- CumuPixel(i) = CumuPixel(i - 1) + ProbPixel(i);
- end
- end
- % 指定範圍進行均衡化
- % pixel_max=max(max(I));
- % pixel_min=min(min(I));
- pixel_max=255;
- pixel_min=0;
- %對灰度值進行映射(均衡化)
- for i = 1:height
- for j = 1: width
- dst_img(i,j) = CumuPixel(src_img(i,j)+1)*(pixel_max-pixel_min)+pixel_min;
- end
- end
- return;
爲什們和matlab的直方圖不一樣呢???
二,指數變換
- clc;
- close all;
- clear all;
- % -------------Gamma Transformations-----------------
- %f = imread('Fig0316(4)(bottom_left).tif');
- f = imread('seed.tif');
- Gamma = 0.4;
- g2 = myExpEnhance(f,Gamma);
- figure();
- subplot(221); imshow(f); xlabel('a).Original Image');
- subplot(222),imhist(f),title('原圖像直方圖');%顯示原始圖像直方圖
- subplot(223); imshow(g2); xlabel('b).Gamma Transformations \gamma = 0.4');
- subplot(224),imhist(g2),title('增強圖像直方圖');%顯示原始圖像直方圖
- function dst_img=myExpEnhance(src_img,Gamma)
- src_img = mat2gray(src_img,[0 255]);%將圖像矩陣A中介於amin和amax的數據歸一化處理, 其餘小於amin的元素都變爲0, 大於amax的元素都變爲1。
- C = 1;
- g2 = C*(src_img.^Gamma);
- %反歸一化
- max=255;
- min=0;
- dst_img=uint8(g2*(max-min)+min);
三,對數變換
- clc;
- close all;
- clear all;
- %-------------Log Transformations-----------------
- f = imread('seed.tif');
- g_1 = myLogEnhance(f,10);
- g_2 = myLogEnhance(f,100);
- g_3 = myLogEnhance(f,200);
- figure();
- subplot(2,2,1);
- imshow(f);xlabel('a).Original Image');
- subplot(2,2,2);
- imshow(g_1);xlabel('b).Log Transformations v=10');
- subplot(2,2,3);
- imshow(g_2);xlabel('c).Log Transformations v=100');
- subplot(2,2,4);
- imshow(g_3);
- xlabel('d).Log Transformations v=200');
對數變換核心函數
- function dst_img=myLogEnhance(src_img,v)
- c=1.0;
- src_img = mat2gray(src_img,[0 255]);
- g =c*log2(1 + v*src_img)/log2(v+1);
- %反歸一化
- max=255;
- min=0;
- dst_img=uint8(g*(max-min)+min);
五,線性拉伸
- clc;
- close all;
- clear all;
- I=imread('seed.tif');
- [m,n,k]=size(I);
- figure (1)
- imshow('seed.tif');title(' 原圖像');
- mid=mean(mean(I));
- %橫軸
- fa=20; fb=80;
- %縱軸
- ga=50; gb=230;
- J=myLinearEnhance(I,fa,fb,ga,gb);
- figure (2)
- imshow(J);title(' 線性拉伸圖像');
- pixel_f=1:256;
- pixel_g=zeros(1,256);
- %三段斜率,小於1表示該段將會被收縮
- k1=double(ga/fa);
- k2=(gb- ga)/(fb- fa);
- k3=(256- gb)/(256- fb);
- for i=1:256
- if i <= fa
- pixel_g(i)= k1*i;
- elseif fa < i && i <= fb
- pixel_g(i)= k2*( i- fa)+ ga;
- else
- pixel_g(i)= k3*( i - fb)+ gb;
- end
- end
- figure (3)
- plot(pixel_f,pixel_g);
- function dst_img=myLinearEnhance(src_img,fa,fb,ga,gb)
- [height,width] = size(src_img);
- dst_img=uint8(zeros(height,width));
- src_img=double(src_img);
- %三段斜率
- k1=ga/fa;
- k2=(gb- ga)/(fb- fa);
- k3=(255- gb)/(255- fb);
- for i=1:height
- for j=1:width
- if src_img(i,j) <= fa
- dst_img(i,j)= k1*src_img(i,j);
- elseif fa < src_img(i,j) && src_img(i,j) <= fb
- dst_img(i,j)= k2*( src_img(i,j)- fa)+ ga;
- else
- dst_img(i,j)= k3*( src_img(i,j)- fb)+ gb;
- end
- end
- end
- dst_img=uint8(dst_img);
附錄:
附錄網上的另一份講解:
直方圖均衡化算法分爲三個步驟,第一步是統計直方圖每個灰度級出現的次數,第二步是累計歸一化的直方圖,第三步是計算新的像素值。
第一步:
for(i=0;i<height;i++)
for(j=0;j<width;j++)
n[s[i][j]]++;
for(i=0;i<L;i++)
p[i]=n[i]/(width*height);
這裏,n[i]表示的是灰度級爲i的像素的個數,L表示的是最大灰度級,width和height分別表示的是原始圖像的寬度和高度,所以,p[i]表示的就是灰度級爲i的像素在整幅圖像中出現的概率(其實就是p[]這個數組存儲的就是這幅圖像的歸一化之後的直方圖)。
第二步:
for(i=0;i<=L;i++)
for(j=0;j<=i;j++)
c[i]+=p[j];
c[]這個數組存儲的就是累計的歸一化直方圖。
第三步:
max=min=s[0][0];
for(i=0;i<height;i++)
for(j=0;j<width;j++)
if(max<s[i][j]){
max=s[i][j];
}else if(min>s[i][j]){
min=s[i][j];
}
找出像素的最大值和最小值。
for(i=0;i<height;i++)
for(j=0;j<width;j++)
t[i][j]=c[s[i][j]]*(max-min)+min;
t[][]就是最終直方圖均衡化之後的結果。
收錄優秀代碼:
這份代碼寫得不錯,學習了,原博客地址見參考資源【3】!
- using namespace cv;
- using namespace std;
- class hisEqt
- {
- public:
- hisEqt::hisEqt();
- hisEqt::~hisEqt();
- public:
- int w;
- int h;
- int nlen;
- int *pHis;
- float *pdf;
- //=====求像素分佈概率密度====
- void getPdf();
- //======統計像素個數=======
- void getHis(unsigned char*imgdata);
- //==========畫統計分佈直方圖===============
- void drawHistogram(const float*pdf,Mat &hist1);
- //===========直方圖均衡化==========
- void hisBal();
- //====直方圖均衡化後的圖像===
- void imgBal(unsigned char* img);
- };
- hisEqt::hisEqt() :nlen(0){
- pHis = new int[256 * sizeof(int)];
- memset(pHis, 0, 256 * sizeof(int));
- pdf = new float[255 * sizeof(float)];
- memset(pdf, 0, 255 * sizeof(float));
- }
- hisEqt::~hisEqt(){
- delete[]pHis;
- delete[]pdf;
- }
- //======統計像素個數=======
- void hisEqt::getHis(unsigned char*imgdata){
- for (int i = 0; i<nlen; i++)
- {
- pHis[imgdata[i]]++;
- }
- }
- //=====求像素分佈概率密度====
- void hisEqt::getPdf(){
- for (int k = 0; k<256; k++)
- {
- pdf[k] = pHis[k] / float(nlen);
- }
- }
- //===========直方圖均衡化==========
- void hisEqt::hisBal(){
- for (int k = 1; k<256; k++)
- {
- pdf[k] += pdf[k - 1];
- }
- for (int k = 0; k<256; k++)
- {
- pHis[k] = 255 * pdf[k];
- }
- }
- //====直方圖均衡化
- void hisEqt::imgBal(unsigned char* img){
- for (int i = 0; i<nlen; i++)
- {
- img[i] = pHis[img[i]];
- }
- }
- void hisEqt::drawHistogram(const float *pdf, Mat& hist1){
- for (int k = 0; k<256; k++)
- {
- if (k % 2 == 0)
- {
- Point a(k, 255), b(k, 255 - pdf[k] * 2550);
- line(hist1,
- a,
- b,
- Scalar(0, 0, 255),
- 1);
- }
- else
- {
- Point a(k, 255), b(k, 255 - pdf[k] * 2550);
- line(hist1,
- a,
- b,
- Scalar(0, 255, 0),
- 1);
- }
- }
- }
- int main()
- {
- Mat image = imread("Fig0651(a)(flower_no_compression).tif");
- if (!image.data)
- return -1;
- Mat hist2(256, 256, CV_8UC3, Scalar(0, 0, 0));
- Mat hist1(256, 256, CV_8UC3, Scalar(0, 0, 0));
- Mat imgOut = Mat(image.rows, image.cols, CV_8UC3, Scalar(0, 0, 0));
- vector<Mat> planes;
- int chn = image.channels();
- if (chn == 3)
- {
- split(image, planes);
- }
- while (chn)
- {
- chn--;
- unsigned char* imageData = new unsigned char[sizeof(unsigned char)*(image.cols*image.rows)];
- memcpy(imageData, planes[chn].data, planes[chn].cols*planes[chn].rows);
- hisEqt his;//自定義的類
- his.nlen = image.rows*image.cols;
- his.getHis(imageData);
- his.getPdf();
- // //======畫原圖直方圖並保存============
- his.drawHistogram(his.pdf, hist1);
- string pic_name = "hisline";
- pic_name = pic_name + to_string(chn);
- pic_name=pic_name+ ".jpg";
- imwrite(pic_name, hist1);
- his.hisBal();
- his.getPdf();
- // //======畫均衡化後直方圖並保存============
- his.drawHistogram(his.pdf, hist2);
- string pic_name0 = "his_balanceline";
- pic_name0 = pic_name0 + to_string(chn);
- pic_name0 = pic_name0 + ".jpg";
- imwrite(pic_name0, hist2);
- // //=====圖像均衡化===
- his.imgBal(imageData);
- memcpy(planes[chn].data, imageData, planes[chn].cols*planes[chn].rows);
- delete[] imageData;
- imageData = NULL;
- }
- merge(planes, imgOut);//單通道合併
- imwrite("result.jpg", imgOut);
- return 0;
- }
參考資源
【1】http://blog.csdn.net/xiajun07061225/article/details/6910129
【2】數字圖像處理,岡薩雷斯著
【3】http://blog.csdn.net/bettyshasha/article/details/46940805
【4】http://blog.csdn.net/terryzero/article/details/6043821
【5】http://www.myexception.cn/image/1450848.html