1. 數字圖像處理python實現圖像灰度變換、直方圖均衡、均值濾波
import CV2
import
import numpy as np
import random
使用的是pycharm
因為最近看了《銀翼殺手2049》,裡面Joi實在是太好看了所以原圖像就用Joi了
要求是灰度圖像,所以第一步先把圖像轉化成灰度圖像
# 讀入原始圖像
img = CV2.imread('joi.jpg')
# 灰度化處理
gray = CV2.cvtColor(img, CV2.COLOR_BGR2GRAY)
CV2.imwrite('img.png', gray)
第一個任務是利用分段函數增強灰度對比,我自己隨便寫了個函數大致是這樣的
def chng(a):
if a < 255/3:
b = a/2
elif a < 255/3*2:
b = (a-255/3)*2 + 255/6
else:
b = (a-255/3*2)/2 + 255/6 +255/3*2
return b
rows = img.shape[0]
cols = img.shape[1]
cover = .deep(gray)
for i in range(rows):
for j in range(cols):
cover[i][j] = chng(cover[i][j])
CV2.imwrite('cover.png', cover)
下一步是直方圖均衡化
# histogram equalization
def hist_equal(img, z_max=255):
H, W = img.shape
# S is the total of pixels
S = H * W * 1.
out = img.()
sum_h = 0.
for i in range(1, 255):
ind = np.where(img == i)
sum_h += len(img[ind])
z_prime = z_max / S * sum_h
out[ind] = z_prime
out = out.astype(np.uint8)
return out
covereq = hist_equal(cover)
CV2.imwrite('covereq.png', covereq)
在實現濾波之前先添加高斯雜訊和椒鹽雜訊(代碼來源於網路)
不知道這個椒鹽雜訊的名字是誰起的感覺隔壁小孩都饞哭了
用到了random.gauss()
percentage是雜訊佔比
def GaussianNoise(src,means,sigma,percetage):
NoiseImg=src
NoiseNum=int(percetage*src.shape[0]*src.shape[1])
for i in range(NoiseNum):
randX=random.randint(0,src.shape[0]-1)
randY=random.randint(0,src.shape[1]-1)
NoiseImg[randX, randY]=NoiseImg[randX,randY]+random.gauss(means,sigma)
if NoiseImg[randX, randY]< 0:
NoiseImg[randX, randY]=0
elif NoiseImg[randX, randY]>255:
NoiseImg[randX, randY]=255
return NoiseImg
def PepperandSalt(src,percetage):
NoiseImg=src
NoiseNum=int(percetage*src.shape[0]*src.shape[1])
for i in range(NoiseNum):
randX=random.randint(0,src.shape[0]-1)
randY=random.randint(0,src.shape[1]-1)
if random.randint(0,1)<=0.5:
NoiseImg[randX,randY]=0
else:
NoiseImg[randX,randY]=255
return NoiseImg
covereqg = GaussianNoise(covereq, 2, 4, 0.8)
CV2.imwrite('covereqg.png', covereqg)
covereqps = PepperandSalt(covereq, 0.05)
CV2.imwrite('covereqps.png', covereqps)
下面開始均值濾波和中值濾波了
就以n x n為例,均值濾波就是用這n x n個像素點灰度值的平均值代替中心點,而中值就是中位數代替中心點,邊界點周圍補0;前兩個函數的作用是算出這個點的灰度值,後兩個是對整張圖片進行
#均值濾波模板
def mean_filter(x, y, step, img):
sum_s = 0
for k in range(x-int(step/2), x+int(step/2)+1):
for m in range(y-int(step/2), y+int(step/2)+1):
if k-int(step/2) 0 or k+int(step/2)+1 > img.shape[0]
or m-int(step/2) 0 or m+int(step/2)+1 > img.shape[1]:
sum_s += 0
else:
sum_s += img[k][m] / (step*step)
return sum_s
#中值濾波模板
def median_filter(x, y, step, img):
sum_s=[]
for k in range(x-int(step/2), x+int(step/2)+1):
for m in range(y-int(step/2), y+int(step/2)+1):
if k-int(step/2) 0 or k+int(step/2)+1 > img.shape[0]
or m-int(step/2) 0 or m+int(step/2)+1 > img.shape[1]:
sum_s.append(0)
else:
sum_s.append(img[k][m])
sum_s.sort()
return sum_s[(int(step*step/2)+1)]
def median_filter_go(img, n):
img1 = .deep(img)
for i in range(img.shape[0]):
for j in range(img.shape[1]):
img1[i][j] = median_filter(i, j, n, img)
return img1
def mean_filter_go(img, n):
img1 = .deep(img)
for i in range(img.shape[0]):
for j in range(img.shape[1]):
img1[i][j] = mean_filter(i, j, n, img)
return img1
完整main代碼如下:
if __name__ == "__main__":
# 讀入原始圖像
img = CV2.imread('joi.jpg')
# 灰度化處理
gray = CV2.cvtColor(img, CV2.COLOR_BGR2GRAY)
CV2.imwrite('img.png', gray)
rows = img.shape[0]
cols = img.shape[1]
cover = .deep(gray)
for i in range(rows):
for j in range(cols):
cover[i][j] = chng(cover[i][j])
CV2.imwrite('cover.png', cover)
covereq = hist_equal(cover)
CV2.imwrite('covereq.png', covereq)
covereqg = GaussianNoise(covereq, 2, 4, 0.8)
CV2.imwrite('covereqg.png', covereqg)
covereqps = PepperandSalt(covereq, 0.05)
CV2.imwrite('covereqps.png', covereqps)
meanimg3 = mean_filter_go(covereqps, 3)
CV2.imwrite('medimg3.png', meanimg3)
meanimg5 = mean_filter_go(covereqps, 5)
CV2.imwrite('meanimg5.png', meanimg5)
meanimg7 = mean_filter_go(covereqps, 7)
CV2.imwrite('meanimg7.png', meanimg7)
medimg3 = median_filter_go(covereqg, 3)
CV2.imwrite('medimg3.png', medimg3)
medimg5 = median_filter_go(covereqg, 5)
CV2.imwrite('medimg5.png', medimg5)
medimg7 = median_filter_go(covereqg, 7)
CV2.imwrite('medimg7.png', medimg7)
medimg4 = median_filter_go(covereqps, 7)
CV2.imwrite('medimg4.png', medimg4)
2. 圖像直方圖均衡化
一. 直方圖均衡化:
直方圖均衡化是使圖像直方圖變轎尺得平坦的操作。直方圖均衡化能夠有效地解決圖像整體過暗、過亮的問題,增加圖像的清晰度。
具體流程如下所示。其中S是總的像素數,Zmax是像素的最大取值(8位灰度圖像為255),h(i)為圖像像素取值為 i 及 小於 i 的像素的總數。
二. python實現直方圖均衡化操作
import cv2
import numpy as np
import matplotlib.pyplot as plt
# histogram equalization
def hist_equal(img, z_max=255):
H, W = img.shape
S = H * W * 1.
out = img.()
局敬 sum_h = 0.
for i in range(1, 255):
ind = np.where(img == i)
sum_h += len(img[ind])
z_prime = z_max / S * sum_h
out[ind] = z_prime
out = out.astype(np.uint8)
return out
# Read image
img = cv2.imread("../head_g_n.jpg",0).astype(np.float)
# histogram normalization
out = hist_equal(img)
# Display histogram
plt.hist(out.ravel(), bins=255, rwidth=0.8, range=(0, 255))
plt.show()
plt.savefig("out_his.png")
# Save result
cv2.imshow("result", out)
cv2.imwrite("out.jpg", out)
cv2.waitKey(0)
cv2.destroyAllWindows()
三. 實驗結果:
可以看到,直方圖均衡化桐帆慎後的圖像看起來比原來的圖像更加清晰。對於圖像亮度整體偏暗或者偏亮的圖像,我們可以採用直方圖均衡化的方法處理圖像,使得它們看上去更加清晰。
四. matlab 實現圖像直方圖均衡化:
可以參考一篇優秀的博文: https://blog.csdn.net/Ibelievesunshine/article/details/79961027
五. 參考內容:
https://www.cnblogs.com/wojianxin/p/12510797.html
https://blog.csdn.net/Ibelievesunshine/article/details/104922449
3. 直方圖均衡化
想像一下,如果一副圖像中的大多是像素點的像素值都集中在一個像素值范圍之內會怎樣呢?例如,如果一幅圖片整體很亮,那所有的像素值應該都會很高。但是一副高質量的圖像的像素值分布應該很廣泛。所以你應該把它的直方圖做一個橫向拉伸(如下圖),這就是直方圖均衡化要做的事情。通常情況下,這種操作會改善圖像的對比度。
這種方法通常用來增加許多圖像的全局 對比度 ,尤其是當圖像的有用數據的對比度相當接近的時候。通過這種方法, 亮度 可以更好地在直方圖上分布。這樣就可以用於增強局部的對比度而不影響整體的對比度,直方圖均衡化通過有效地擴展常用的亮度來實現這種功能。
這種方法對於背景和前景都太亮或者太暗的圖像非常有用,這種方法尤其是可以帶來 X光 圖像中更好的 骨骼 結構顯示以及曝光過度或者曝光不足 照片 中更好的細節。這種方法的一個主要優勢是它是一個相當直觀的技術並且是 可逆 操作,如果已知均衡化 函數 ,那麼就可以恢復原始的直方圖,並且計算量也不大。這種方法的一個缺點是它對處理的數據不加選擇,它可能會增加背景 雜訊 的對比度並且降低有用 信號 的對比度。
我們先來看看相應的直方圖和累積直方圖,然後使用 OpenCV 進行直方圖均衡化。
我們可以看出來直方圖大部分在灰度值較高的部分,而且分布很集中。而我們希望直方圖的分布比較分散,能夠涵蓋整個 x 軸。所以,我們就需要一個變換函數幫助我們把現在的直方圖映射到一個廣泛分布的直方圖中,這就是直方圖均衡化。
**限制對比度自適應性直方圖均衡化 CLAHE **
在上邊做的直方圖均衡化會改變整個圖像的對比度,但是在很多情況下,這樣做的效果並不好。的確在進行完直方圖均衡化之後,圖片背景的對比度被改變了。但是你再對比一下兩幅圖像中雕像的面圖,由於太亮我們丟失了很多信息。
原理:
為了解決這個問題,我們需要使用自適應的直方圖均衡化 CLAHE (Contrast Limited Adaptive Histogram Equalization)。這種情況下,整幅圖像會被分成很多小塊,這些小塊被稱為「tiles」(在 OpenCV 中 tileGridSize默認是 8x8),然後再對每一個小塊分別進行直方圖均衡化(跟前面類似)。所以在每一個的區域中,直方圖會集中在某一個小的區域中(除非有雜訊干擾)。如果有雜訊的話,雜訊會被放大。為了避免這種情況的出現,要使用對比度限制。
CLAHE中,每一個像素鄰域都要進行對比度限制,從而得到對應的變換函數,被用來降低AHE中雜訊的增強,這主要是通過限制AHE中的對比度增強來實現的。像素周圍鄰域雜訊的增強主要是由變換函數的斜率造成的,由於像素鄰域的雜訊與鄰域的CDF成正比,因此也與鄰域直方圖在該中心像素位置的值成正比,CLAHE之所舉仿以能夠限制對比度,是因為它在計算鄰域的CDF之前在指定閾值處對直方正辯纖圖進行了修剪,如下圖所示,這一做法不僅限制了CDF的斜率,也限制了變換函數的斜率,其中對直方圖進行切割所使用的閾值,被稱作修剪限制度(clip limit),這個參數不僅依賴於直方圖的歸一化,而且依賴於像素鄰域的size大小,通常設為3到4之間。
對於每個小塊來說,如果直方圖中的 bin 超過對灶明比度的上限的話,就把其中的像素點均勻分散到其他 bins 中,然後在進行直方圖均衡化。最後,為了去除每一個小塊之間「人造的」(由於演算法造成)邊界,再使用雙線性差值,與原圖做圖層濾色混合操作(可選)。
實現:
參考文獻:
網址: 直方圖均衡化
Adaptive_histogram_equalization
書籍:《數字圖像處理》《OpenCV-Python 中文教程》
4. 圖像處理的Python問題,怎麼解決
imtools.py裡面也要有numpy 的引用才對
def histeq(im,nbr_bins=256):
"""對一幅灰度圖像進行直方圖均衡化"""
#計算圖像的直方圖
imhist,bins = histogram(im.flatten(),nbr_bins,normed=True)
cdf = imhist.cumsum() #累計分布函數
cdf = 255 * cdf / cdf[-1] #歸一化
#使用累計分布函數的線性插值,計算新的像素
im2 = interp(im.flatten(),bins[:-1],cdf)
return im2.reshape(im.shape),cdf
以上代碼我定義在imtools.py文件里並且放在了python2.7里
然後我在num.py里引用他
Python code?
1
2
3
4
5
6
7
8
9
10
from PIL import Image
from pylab import *
from numpy import *
import imtools
im= array(Image.open('E:\\daima\\pydaima\\shijue\\tupian1\\gang2.jpg').convert('L'))
im2,cdf =imtools.histeq(im)
出現以下錯誤:
Traceback (most recent call last):
File "<pyshell#56>", line 1, in <mole>
a=imtools.histeq(im)
File "E:\daima\pydaima\shijue\imtools.py", line 32, in histeq
NameError: global name 'histogram' is not defined