直方图均衡算法及结合自动色阶的改进
? ? ? ??直方圖均衡,顧名思義,是處理影像灰度在統(tǒng)計直方圖上分布問題,是一種圖像增強算法。以圖像某灰度值分布概率以及低于該值得所有值得分布概率之和p與該圖像所有灰度級別L的乘積作為該灰度值均衡后的值。
? ? ? ? 直方圖均衡公式:
? ? ? ??以8位灰度圖像的直方圖均衡為例,第一步是統(tǒng)計圖像所有灰度值在0~255分布概率;第二步通過從低到高累加各個灰度級別概率p(i),直方均衡公式p(i)*255計算出對應(yīng)值,生成查找表;第三部通過原圖對應(yīng)查找表生成直方均衡后圖形。
? ? ? ??統(tǒng)計概率分布和直方均衡計算:
private Map<Integer, Double> getPDF(BufferedImage image) {Map<Integer, Double> map = new HashMap<>();int width = image.getWidth();int height = image.getHeight();double totalPixel = 3 * width * height;for (int i = 0; i < 256; i++) {map.put(i, 0.0);// 通過循環(huán),往集合里面填充0~255個位置,初始值都為0}//分別統(tǒng)計圖像上0~255上分布總數(shù)for (int i = 0; i < image.getWidth(); i++) {for (int j = 0; j < image.getHeight(); j++) {int rgb = image.getRGB(i, j);int r = (rgb >> 16) & 0xff;int g = (rgb >> 8) & 0xff;int b = rgb & 0xff;map.put(r, map.get(r) + 1);map.put(g, map.get(g) + 1);map.put(b, map.get(b) + 1);}} 直方均衡計算,生成查找表: private void getTable(Map<Integer, Double> map) {double param = 0.0;for(int i = 0;i < 256;i++) {param += map.get(i);table[i] = (int)Math.round(param * 255);}}?測試圖像:
分布概率直方圖:
直方均衡后:
直方均衡后概率分布:
? ? ? ??從圖像和概率直方圖分布看,原圖的灰度峰值在50左右,且大部分都分布在較小灰度值上,經(jīng)過直方圖均衡后,圖像變亮,且灰度值在0~255上分布比較均勻。這是傳統(tǒng)直方圖均衡實現(xiàn)方式,但其中存在缺陷,由于中間部分灰度因為占據(jù)較小概率分布,有可能被其附近較大概率的灰度淹沒。例如,灰度值為100的統(tǒng)計概率為50%,那么均衡后值為128,而110處概率分布為50.1%,那么均衡計算后值仍為128,原圖中100~110之間灰度也就被淹沒。從測試圖像細節(jié)中也可以發(fā)現(xiàn)這個問題,如下所示:
原圖部分細節(jié):
? ? ? ??從圖像上可以看到三叉路口存在較明顯的亮度差異形成的邊界線。那么再看直方均衡后圖像細節(jié)。
? ? ? ??由于直方均衡的作用,部分灰度級被淹沒,三叉路口路面邊界線已經(jīng)丟失,整個路面也完全變?yōu)榘咨?#xff0c;丟失了大量細節(jié)。目前直方圖均衡算法的改進也有很多,一種是基于HSI色彩空間。由于RGB色彩空間灰度值為離散整數(shù)值,在計算過程中容易丟失精度。將圖像從RGB色彩空間轉(zhuǎn)換為HSI色彩空間,分離出來的亮度I值為連續(xù)變換值,在直方均衡過程中更容易保留更多細節(jié)。那么首先要將RGB轉(zhuǎn)換為HSI。
RGB轉(zhuǎn)HSI代碼:
public Double[] rgb2HSI(int[] rgb) {double sum = rgb[0] + rgb[1] + rgb[2];double r = rgb[0] / sum;double g = rgb[1] / sum;double b = rgb[2] / sum;double s1 = 0.5 * ((r - g) + (r - b));double s2 = Math.pow((r - g), 2) + (r - b) * (g - b);double s3 = s1 / Math.sqrt(s2);double h = 0.0;if (b <= g) {h = Math.acos(s3);} else if (b > g) {h = 2 * Math.PI - Math.acos(s3);}double s = 1 - 3 * Math.min(r, Math.min(g, b));double H = ((h * 180.0) / Math.PI);double S = s * 100.0;double I = sum / 3;return new Double[] { H, S, I };}HSI轉(zhuǎn)換RGB代碼:
public Integer[] hsi2RGB(Double[] hsi) {double h = (hsi[0] * Math.PI) / 180.0;double s = hsi[1] / 100.0;double i = hsi[2] / 255.0;double x = i * (1 - s);double y = i * (1 + (s * Math.cos(h)) / Math.cos(Math.PI / 3.0 - h));double z = 3 * i - (x + y);double r = 0, g = 0, b = 0;if (h < ((2 * Math.PI) / 3)) {b = x;r = y;g = z;} else if (h >= ((2 * Math.PI) / 3) && h < ((4 * Math.PI) / 3)) {h = h - ((2 * Math.PI) / 3.0);x = i * (1 - s);y = i * (1 + (s * Math.cos(h)) / Math.cos(Math.PI / 3.0 - h));z = 3 * i - (x + y);r = x;g = y;b = z;} else if (h >= ((4 * Math.PI) / 3) && h < ((2 * Math.PI))) {h = h - ((4 * Math.PI) / 3.0);x = i * (1 - s);y = i * (1 + (s * Math.cos(h)) / Math.cos(Math.PI / 3.0 - h));z = 3 * i - (x + y);g = x;b = y;r = z;}int red = (int) Math.round((r * 255));int green = (int) Math.round((g * 255));int blue = (int) Math.round((b * 255));return new Integer[] { red, green, blue};}? ? ? ?
? ? ? ? 盡管HSI色彩空間可以解決直方均衡中灰度級丟失問題,但HSI與RGB色彩空間的轉(zhuǎn)換需要耗費大量計算,導致圖像處理過程比較緩慢。下面就介紹一下博主自己想到的一種解決辦法。
? ? ? ??雖然使用傳統(tǒng)直方均衡容易丟失部分灰度級,但仍然可以采用傳統(tǒng)方式進行直方均衡計算,將直方均衡計算后圖像與原圖進行均值融合,便可以恢復(fù)部分丟失的灰度值。盡管該方法不能完全恢復(fù)丟失的灰度級別,但相對于傳統(tǒng)直方均衡,已經(jīng)有了很大改善。處理流程為:對原圖分別進行直方均衡和自動色階,將計算后的圖像進行均值融合,得到最終圖像。
效果圖:
? ? ? ? 相對于傳統(tǒng)直方均衡,該方法計算后圖像稍暗,但可以保留更多細節(jié)。再看細節(jié)部分。
? ? ? ? 從放大后的細節(jié)上看,三叉路口處的邊界線仍然清晰可辨。路面也沒有完全變?yōu)榘咨?/p>
? ? ? ? 實際上,編程實現(xiàn)還可以對算法進一步優(yōu)化,由于自動色階算法同樣需要概率分布計算,那么直方圖均衡和自動色階的概率分布計算可以一起做!然后根據(jù)概率分布分別計算直方圖均衡和自動色階查找表,之后取出原圖每個像素,利用查找表計算直方圖均衡和自動色階對應(yīng)的值,對兩個值求均值即可。
實現(xiàn)代碼:
public BufferedImage histogramEqualization(BufferedImage image) {BufferedImage resultImage = new BufferedImage(image.getWidth(), image.getHeight(), image.getType());Map<Integer, Double> map = getPDF(image);getTable(map); //初始化直方圖均衡查找表// 自動色階前裁切掉最暗和最亮部分占比較少的值int min = getMin(map, 0.0001);int max = getMax(map, 0.0001);int[] arr = new int[] { min, max };getContrastByMaxMin(arr); // 初始化自動色階查找表int width = image.getWidth();int height = image.getHeight();for (int i = 0; i < width; i++) {for (int j = 0; j < height; j++) {int rgb = image.getRGB(i, j);int R = (rgb >> 16) & 0xff;int G = (rgb >> 8) & 0xff;int B = rgb & 0xff;double hisR = histogramtTable[R];double hisG = histogramtTable[G];double hisB = histogramtTable[B];double contrastR = autoContrastTable[R];double contrastG = autoContrastTable[G];double contrastB = autoContrastTable[B];R = (int) Math.round((hisR + contrastR) / 2);G = (int) Math.round((hisG + contrastG) / 2);B = (int) Math.round((hisB + contrastB) / 2);rgb = (255 & 0xff) << 24 | (R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff);resultImage.setRGB(i, j, rgb);}}return resultImage;}? ? ??
?
總結(jié)
以上是生活随笔為你收集整理的直方图均衡算法及结合自动色阶的改进的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 无人机图像处理工具-亮度、对比度、饱和度
- 下一篇: 神经网络激活函数sigmoid、tanh