依据作用域的不同,图像增强分为空域内处理和频域内处理;
环境:python3.6、Pycharm、Opencv、matplotlib
测试用图像(密码1234)百度网盘 请输入提取码百度网盘为您提供文件的网络备份、同步和分享服务。空间大、速度快、安全稳固,支持教育网加速,支持手机端。注册使用百度网盘即可享受免费存储空间https://pan.baidu.com/s/1uFdLfs-Jml6nZokkPdnuug
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
import cv2
#利用CV2读取文件,第一个变量是文件名,第二个变量表示读取文件的形式
image_0 = cv2.imread('couple.tiff',cv2.IMREAD_GRAYSCALE)
plt.subplot(121)
plt.imshow(image_0)
plt.subplot(122)
#后面的参数是为了显示灰度图像,官网有介绍
plt.imshow(image_0,vmin=0,vmax=255,cmap='gray')
plt.show()
灰度变换增强是在空间域内对图像进行增强的一种简单而有效的方法,不改变原图中像素的位置,只改变像素的灰度值,并逐点进行。依据变换方式,分为线性变换、分段线性和非线性。
进行灰度变换,首先要获取图像的直方图。
matplotlib直方图函数hist,
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
import cv2
#利用CV2读取文件,第一个变量是文件名,第二个变量表示读取文件的形式
image_0 = cv2.imread('couple.tiff',cv2.IMREAD_GRAYSCALE)
plt.subplot(121)
#后面的参数是为了显示灰度图像,官网有介绍
plt.imshow(image_0,vmin=0,vmax=255,cmap='gray')
#转化为矩阵并拉平
img_np = np.array(image_0).flatten()
plt.subplot(122)
plt.hist(x=img_np,bins=255)
plt.show()
代码2:统计各个灰度值的像素数来画直方图
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
import cv2
#利用CV2读取文件,第一个变量是文件名,第二个变量表示读取文件的形式
image_0 = cv2.imread('couple.tiff',cv2.IMREAD_GRAYSCALE)
plt.subplot(121)
#后面的参数是为了显示灰度图像,官网有介绍
plt.imshow(image_0,vmin=0,vmax=255,cmap='gray')
img_np = np.array(image_0) #转化为矩阵
width,height = img_np.shape #获取宽与高
N = np.zeros(shape=(1,256),dtype='float') #构造零矩阵,用以统计像素数
#遍历各个灰度值统计个数
for i in range(0,width):
for j in range(0,height):
k = img_np[i,j]
N[0][k] = N[0][k] + 1
N = N.flatten() #扁平化
plt.subplot(122)
plt.bar([i for i in range(0,256)],height=N,width=1)
plt.show()
由于该灰度图的直方图显示其灰度值在0~255之间均有分布,因此更换图像为lena.tiff
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
import cv2
#利用CV2读取文件,第一个变量是文件名,第二个变量表示读取文件的形式
image_0 = cv2.imread('lena.tiff',cv2.IMREAD_GRAYSCALE)
plt.subplot(221)
#后面的参数是为了显示灰度图像,官网有介绍
plt.imshow(image_0,vmin=0,vmax=255,cmap='gray')
img_np = np.array(image_0) #转化为矩阵
width,height = img_np.shape #获取宽与高
N = np.zeros(shape=(1,256),dtype='float') #构造零矩阵,用以统计像素数
#遍历各个灰度值统计个数
for i in range(0,width):
for j in range(0,height):
k = img_np[i,j]
N[0][k] = N[0][k] + 1
N = N.flatten() #扁平化
plt.subplot(222)
plt.bar([i for i in range(0,256)],height=N,width=1)
#线性变化
plt.subplot(223)
J = img_np.astype('float')
J = 0 + (J-42) * (255-0)/(232-42) #利用公式转换
#像素值小于0或大于255的分别赋值为0和255
for i in range(0,width):
for j in range(0,height):
if J[i,j] < 0 :
J[i,j] = 0
elif J[i,j] > 255:
J[i,j] = 255
image_1 = J.astype('uint8')
plt.imshow(image_1,vmin=0,vmax=255,cmap='gray')
plt.subplot(224)
J = J.flatten()
plt.hist(J,bins=255)
plt.show()
上方图片是原图及其直方图,下方图片是修改后的图片及其直方图。原图的直方图显示其灰度值在42~232之间,利用线性变换将灰度值均匀分布在0~255之间。图像变得更加清晰。
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
import cv2
# 利用CV2读取文件,第一个变量是文件名,第二个变量表示读取文件的形式
image_0 = cv2.imread('lena.tiff', cv2.IMREAD_GRAYSCALE)
plt.subplot(321)
# 后面的参数是为了显示灰度图像,官网有介绍
plt.imshow(image_0, vmin=0, vmax=255, cmap='gray')
img_np = np.array(image_0) # 转化为矩阵
width, height = img_np.shape # 获取宽与高
N = np.zeros(shape=(1, 256), dtype='float') # 构造零矩阵,用以统计像素数
# 遍历各个灰度值统计个数
for i in range(0, width):
for j in range(0, height):
k = img_np[i, j]
N[0][k] = N[0][k] + 1
N = N.flatten() # 扁平化
plt.subplot(322)
plt.bar([i for i in range(0, 256)], height=N, width=1)
# 灰度变换-线性变化
plt.subplot(323)
J = img_np.astype('float')
J = 0 + (J - 42) * (255 - 0) / (232 - 42) # 利用公式转换
# 像素值小于0或大于255的分别赋值为0和255
for i in range(0, width):
for j in range(0, height):
if J[i, j] < 0:
J[i, j] = 0
elif J[i, j] > 255:
J[i, j] = 255
image_1 = J.astype('uint8')
plt.imshow(image_1, vmin=0, vmax=255, cmap='gray')
plt.subplot(324)
J = J.flatten()
plt.hist(J, bins=255)
# 灰度变换-分段线性变换
Q = img_np.astype('float')
for i in range(0, width):
for j in range(0, height):
if 0 <= Q[i, j] < 100:
Q[i, j] = 0 + Q[i, j] * (50 / 100)
elif 100 <= Q[i, j] < 200:
Q[i, j] = 50 + ( Q[i, j] - 100 ) * (200 - 50) / (200 - 100)
elif 200 <= Q[i,j] <255:
Q[i,j] = 200 + ( Q[i,j] - 200 )* (255 - 200) / (255 - 200)
for i in range(0, width):
for j in range(0, height):
if Q[i,j] <= 0 :
Q[i,j] = 0
elif Q[i,j] >= 255:
Q[i,j] = 255
image_2 = Q.astype('uint8')
plt.subplot(325)
plt.imshow(image_2,vmin=0,vmax=255,cmap='gray')
plt.subplot(326)
plt.hist(Q.flatten(),bins=255)
plt.show()
变换显示在最下方的图片中,对于0~100的灰度值进行压缩,对100~200的灰度值进行变化。
2.1.3 非线性变换
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
import cv2
import math
# 利用CV2读取文件,第一个变量是文件名,第二个变量表示读取文件的形式
image_0 = cv2.imread('lena.tiff', cv2.IMREAD_GRAYSCALE)
plt.subplot(221)
# 后面的参数是为了显示灰度图像,官网有介绍
plt.imshow(image_0, vmin=0, vmax=255, cmap='gray')
img_np = np.array(image_0) # 转化为矩阵
width, height = img_np.shape # 获取宽与高
N = np.zeros(shape=(1, 256), dtype='float') # 构造零矩阵,用以统计像素数
# 遍历各个灰度值统计个数
for i in range(0, width):
for j in range(0, height):
k = img_np[i, j]
N[0][k] = N[0][k] + 1
N = N.flatten() # 扁平化
plt.subplot(222)
plt.bar([i for i in range(0, 256)], height=N, width=1)
# 灰度变换-非线性变化(对数变换)
plt.subplot(223)
J = img_np.astype('float')
for i in range(0, width):
for j in range(0, height):
J[i,j] = 0 + math.log(J[i,j] + 1)/(0.06 * math.log(2))
image_1 = J.astype('uint8')
plt.imshow(image_1,vmin=0,vmax=255,cmap='gray')
plt.subplot(224)
J = J.flatten()
plt.hist(J,bins=255)
plt.show()
只尝试了对数变换的效果,指数变换代码也很容易编写。
直方图均衡化是一种利用灰度变换自动调节图像对比度质量的方法,基本思想是通过灰度级的概率密度函数求出灰度变换函数,它是一种以累计分布函数变换法为基础的直方图修正法。