灰度线性变换最常见的就是图像反转,在灰度图像灰度级范围[0,L-1]中,其反转的公式如下所示:
其中,r表示原始图像的灰度级,s表示变换后的灰度级。
低灰度部分经过灰度反转可以得到扩展,看到更多的细节。所以对数变换对照度不均图像中低灰度部分的细节增强很实用。
分段线性灰度变换能将感兴趣的灰度范围线性扩展,相对抑制不感兴趣的灰度区域。
设f(x,y)灰度范围为[0,Mf],g(x,y)灰度范围为[0,Mg]。如下图所示的变换函数的运算结果是将原图在a到b之间的灰度拉伸到c到d之间。如果一幅图像的灰度集中在较暗的区域而导致图像偏暗,可以用灰度拉伸功能来拉伸(斜率>1)物体灰度区间以改善图像;同样如果图像灰度集中在较亮的区域而导致图像偏亮,也可以用灰度拉伸功能来压缩(斜率<1)物体灰度区间以改善图像质量。
main函数:
from functions import *
def stretch():
path1 = 'Brain_CT.jpg'
image1 = image_inten(path1,256)
image1.show('Oringinal image')
image1.get_bar()
image1.stretch(100,0,200,255)
image1.show('After stretching')
image1.get_bar()
def equalization():
path2 = 'Brain_CT.jpg'
image2 = image_inten(path2,256)
image2.show('Original image')
image2.get_bar()
image2.equalize()
image2.show('After equalization')
image2.get_bar()
def remove_noise():
path3 = 'Brain_CT.jpg'
# type of noise
noise_mode = 's&p'
# linear filter
filter = np.ones([5,5])
# filter = [[1,2,1],[2,4,2],[1,2,1]] set the filter by yourself
image3 = image_inten(path3,256)
image3.show('Original image')
image3.get_bar("Original image")
# add noise
# image3.add_noise(noise_mode)
image3.show('Image with {} noise'.format(noise_mode))
# filter
filter = np.array(filter)
# gaussian noise: image3.filt(filter)
# s&p noise :
image3.medium_filter(3)
image3.show('After filtering')
if __name__ == '__main__':
# remove_noise()
stretch()
equalization()
remove_noise()
functions:
import numpy as np
import skimage
from skimage import io,data,color
import matplotlib.pyplot as plt
import os
import copy
''' image intensification '''
class image_inten():
def __init__(self,img_path,L):
self.img_path = img_path
self.img = io.imread(self.img_path) # 带一个参数,表示需要读取的文件路径。读取的图片以numpy数组形式计算。
# Get the grayscale L
self.L = L # 白色为255 ,黑色为0,故黑白图片也称灰度图像
# create the histogram
self.bar = np.zeros(self.L)
# get the size of the input image
self.size = self.img.shape
self.num_pixels = self.size[0] * self.size[1]
# self.max_value = np.max(self.img) ?
# self.min_value = np.max(self.img) ?
# Convert the RGB image to gray image
if len(self.size)!=2:
self.img = color.rgb2gray(self.img)
self.img = skimage.img_as_ubyte(self.img)
self.size = self.img.shape
self.original_img = copy.deepcopy(self.img)
def show(self,title=''):
plt.imshow(self.img,plt.cm.gray) # 画黑白图,如果默认就会画成RGB
plt.title(title)
plt.show()
# Obtain gray statistical histogram
def get_bar(self,title = ''):
self.bar = np.zeros(self.L)
image = copy.deepcopy(self.img)
img = image.reshape(self.num_pixels)
for pixel in img:
self.bar[pixel] +=1
x = np.arange(self.L)
plt.bar(x,self.bar)
plt.title(title)
plt.show()
return self.bar
# gray stretch
def stretch(self,r1,s1,r2,s2):
assert(r1<=r2<self.L and s1<=s2<self.L)
if r1 == r2:
# r1 == r2 && s1 == s2 nothing changes
if s1 == s2:
return
# s1 != s2 threshold processing
else:
self.img[self.img<=r1] = s1
self.img[self.img>r1] = s2
else:
k1 = s1/r1
k2 = (s2-s1)/(r2-r1)
k3 = (self.L-1-s2)/(self.L-1-r2)
b1 = 0
b2 = s2 - k2*r2
b3 = s2 - k3*r2
for i in range(self.size[0]):
for j in range(self.size[1]):
if self.img[i,j]<r1:
self.img[i,j] = self.img[i,j]*k1 + b1
elif r1 <= self.img[i,j] <r2:
self.img[i,j] = self.img[i,j]*k2 + b2
else:
self.img[i,j] = self.img[i,j]*k3 + b3
# histogram equalization
def equalize(self):
bar = copy.deepcopy(self.bar)
# sk = T(rk)
for i in range(self.L):
sum =0
for j in range(i):
sum += bar[j]
self.bar[i] = int(((self.L-1)/self.num_pixels)*sum + 0.5)
for i in range(self.size[0]):
for j in range(self.size[1]):
self.img[i,j] = self.bar[self.img[i,j]]
# add noise to the image
def add_noise(self,noise_mode='gaussian'):
self.img = skimage.util.random_noise(self.img,mode=noise_mode)
def filt(self,filter):
if not isinstance(filter,np.ndarray):
filter = np.array(filter)
filter_size = filter.shape
# the filter should have dimension 2
assert(len(filter_size) == 2)
# calculate the padding number
padding = filter_size[0]//2
larger_image = np.zeros([self.size[0]+2*padding,self.size[1]+2*padding])
# pad the image with 0
larger_image[padding:larger_image.shape[0]-padding,padding:larger_image.shape[1]-padding] = copy.deepcopy(self.img)
# convolution
for i in range(self.size[0]):
for j in range(self.size[1]):
self.img[i,j] = np.sum(larger_image[i:i+filter_size[0],j:j+filter_size[1]] * filter)
self.img[i,j] = self.img[i,j]/np.sum(filter)
# median filter
def medium_filter(self,filter_size):
padding = filter_size
larger_image = np.zeros([self.size[0]+2*padding,self.size[1]+2*padding])
larger_image[padding:larger_image.shape[0] - padding, padding:larger_image.shape[1] - padding] = copy.deepcopy(
self.img)
for i in range(self.size[0]):
for j in range(self.size[1]):
# sort and choose the middle number
self.img[i,j] = np.sort(larger_image[i:i+filter_size,j:j+filter_size].reshape(filter_size**2))[(filter_size**2)//2]
在下图的参数中具体调节了三个参数的值,分别是a,b,和d-c。设a为x1,b为x2,(d-c)为y,取Mg和Mf均为256,x1在100到150之间每隔10取一次值,x2在150到190之间每隔10取一次值,y在180到230之间每隔10取一次值。
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
def gray_trans(img, x1 ,x2 ,y):
temp = img
rows = temp.shape[0]
cols = temp.shape[1]
for i in range(rows):
for j in range(cols):
if temp[i][j] < x1:
temp[i][j] = (256-y)*temp[i][j]/(256-x2+x1)
elif temp[i][j] >= x1 and temp[i][j] <= x2:
temp[i][j] = (256-y)*x1/(256-x2+x1)+y/(x2-x1)*(temp[i][j]-x1)
elif temp[i][j] > x2:
temp[i][j] = (256-y)*(temp[i][j]-x2+x1)/(256-x2+x1)+y
return temp
for i in range(100, 150, 10):
for j in range(150, 190, 10):
for k in range(180, 230, 10):
path = './Brain_CT.jpg'
img = cv.imread(path, 0)
gam_img = gray_trans(img, i, j, k)
cv.imshow('GrayTrans Image x1:'+str(i)+'x2:'+str(j)+'y'+str(k), gam_img)
cv.waitKey(0)