文章目录
为什么需要图像预处理?
图像预处理的主要目的是消除图像中无关的信息,恢复有用的真实信息,增强有关信息的可检测性和最大限度地简化数据,从而改进特征抽取、图像分割、匹配和识别的可靠性。
图像预处理流程
一般的图像预处理步骤为:灰度化 ——>几何变换——>图像增强
一,灰度化
灰度化,在RGB模型中,如果R=G=B时,则彩色表示一种灰度颜色,其中R=G=B的值叫灰度值,因此,灰度图像每个像素只需一个字节存放灰度值(又称强度值、亮度值),灰度范围为0-255。一般有分量法,最大值法,平均值法,加权平均法四种方法对彩色图像进行灰度化。
(1)分量法
三个灰度图像的灰度值是彩色图像中三分量中任意一个分量的亮度值,可以是R分量作为灰度值,也可以是G分量和B分量
f1(i,j)=R(i,j)f2(i,j)=G(i,j)f3(i,j)=B(i,j)
from PIL import Image
import numpy as np
def image2array(image):
"""
:param image: 图片
:return: 图片的数组
"""
image = np.array(image)
return image
def array2image(arrimg):
"""
:param arrimg: 图片的数组
:return: 图片
"""
image = Image.fromarray(arrimg.astype('uint8')).convert('RGB')
return image
def convert2gray(img):
"""
:param img: 数组形式的图片
:return: 分量法灰度化后的图片数组
"""
if len(img.shape) > 2:
r, g, b = img[:, :, 0], img[:, :, 1], img[:, :, 2]
gray = r # 可以是r,也可以是g,b
return gray
else:
return img
if __name__ == '__main__':
image = Image.open("a.jpg")
image = image2array(image)
image = convert2gray(image)
image = array2image(image)
image.show()
(2)最大值法
f(i,j)=max(R(i,j),G(i,j),B(i,j))
def convert2gray(img):
"""
:param img: 图片的数组
:return: 最大值法灰度化后的图片数组
"""
grayimg = np.zeros(shape=(img.shape[0],img.shape[1]))
if len(img.shape) > 2:
for i in range(img.shape[0]):
for j in range(img.shape[1]):
grayimg[i,j] = max(img[i,j][0], img[i,j][1], img[i,j][2])
return grayimg
else:
return img
(3)平均值法
f(i,j)=(R(i,j)+G(i,j)+B(i,j)) /3
def convert2gray(img):
"""
:param img: 图片的数组
:return: 最大值法灰度化后的图片数组
"""
"""
:param img: 图片的数组
:return: 平均法灰度化后的图片数组
"""
grayimg = np.zeros(shape=(img.shape[0], img.shape[1]))
if len(img.shape) > 2:
for i in range(img.shape[0]):
for j in range(img.shape[1]):
grayimg[i, j] = (int(img[i, j][0])+int(img[i, j][1])+int(img[i, j][2]))/3
return grayimg
else:
return img
(4)加权平均法
f(i,j)=0.2989R(i,j)+0.5870G(i,j)+0.1140B(i,j)
def convert2gray(img):
"""
:param img: 数组形式的图片
:return: 加权平均法灰度化后的图片数组
"""
if len(img.shape) > 2:
r, g, b = img[:, :, 0], img[:, :, 1], img[:, :, 2]
gray = 0.2989 * r + 0.5870 * g + 0.1140 * b
return gray
else:
return img
二,几何变换
图像几何变换又称为图像空间变换,通过平移、转置、镜像、旋转、缩放等几何变换对采集的图像进行处理,用于改正图像采集系统的系统误差和仪器位置(成像角度、透视关系乃至镜头自身原因)的随机误差。此外,还需要使用灰度插值算法,因为按照这种变换关系进行计算,输出图像的像素可能被映射到输入图像的非整数坐标上。通常采用的方法有最近邻插值、双线性插值和双三次插值
(1)opencv来进行图像的空间变换
#!/usr/bin/python3
# __*__ coding: utf-8 __*__
import cv2
import numpy as np
from matplotlib import pyplot as plt
from pylab import mpl
mpl.rcParams['font.sans-serif'] = ['FangSong'] # 指定默认字体
mpl.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
"""
尺度变换
尺度变换(缩放,拉伸)是调整图像大小,使其变大或变小。
但实际操作时要比想象的复杂一些,因为调整大小带来了像素如何插值(放大)或合并(减少)的问题。
cv2.resize(src,dsize,fx=0,fy=0,interpolation=cv2.INTER_LINEAR)
cv2.INTER_LINEAR 双线性插值法
cv2.INTER_NEAREST 最近邻插值
cv2.INTER_AREA 像素区域重采样(默认)
cv2.INTER_CUBIC 双三次插值
cv2.INTER_LANCZ0S4 插值(超过8×8个邻域)
"""
img1 = cv2.imread("a.jpg")
# 绝对尺寸
height,width = img1.shape[:2]
res = cv2.resize(img1,(2*width,2*height),interpolation=cv2.INTER_CUBIC)
# 相对尺寸
res1 = cv2.resize(img1,None,fx=0.3,fy=0.3)
"""
平移
cv2.warpAffine(src, M, dsize)
src:输入图像
M:移动矩阵
dsize:输出图像大小
"""
tx = 500
ty = 100
M = np.float32([[1,0,tx],[0,1,ty]])
dst = cv2.warpAffine(img1,M,(img1.shape[1]+tx,img1.shape[0]+ty))
tx = 500
ty = 200
M = np.float32([[1,0,tx],[0,1,ty]])
dst1 = cv2.warpAffine(img1,M,(1300,1000))
"""
旋转变换
cv2.getRotationMatrix2D(center, angle, scale)
cv2.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) → dst
center–表示旋转的中心点
angle–表示旋转的角度degrees
scale–图像缩放因子
src – 输入的图像
M – 2 X 3 的变换矩阵.
dsize – 输出的图像的size大小
dst – 输出的图像
flags – 输出图像的插值方法(参考尺度变换)
borderMode – 图像边界的处理方式
"""
rows, cols = img1.shape[:2]
# 这里(cols / 2, rows / 2)为旋转中心,60旋转角度,第三个为旋转后的缩放因子
# 可以通过设置旋转中心,缩放因子,以及窗口大小来防止旋转后超出边界的问题
M = cv2.getRotationMatrix2D((cols / 2, rows / 2), 60, 1)
dst2 = cv2.warpAffine(img1, M, (cols, rows))
"""
翻转
cv2.flip(src, flipCode[, dst]) → dst1
src – 输入的图像
dst – 输出的图像
flipCode – 翻转模式:
flipCode==0垂直翻转(沿X轴翻转)
flipCode>0水平翻转(沿Y轴翻转)
flipCode<0水平垂直翻转(先沿X轴翻转,再沿Y轴翻转,等价于旋转180°)
"""
# 水平翻转
dst3 = cv2.flip(img1, 1)
# 垂直翻转
dst4 = cv2.flip(img1, 0)
# 水平垂直翻转
dst5 = cv2.flip(img1, -1)
"""
仿射变换
仿射变换具体到图像中的应用,主要是对图像的缩放scale,
旋转rotate,剪切shear,翻转flip和平移translate的组合
"""
pts1 = np.float32([[500,500],[2000,500],[500,2000]])
pts2 = np.float32([[100,1000],[2000,500],[1000,2500]])
M = cv2.getAffineTransform(pts1,pts2)
img2 = cv2.warpAffine(img1,M,(rows,cols))
"""
透视变换
"""
pts1 = np.float32([[200,200],[200,3000],[4800,200],[4800,3000]])
pts2 = np.float32([[200,200],[200,3000],[4800,600],[4800,2000]])
M = cv2.getPerspectiveTransform(pts1,pts2)
img3=cv2.warpPerspective(img1,M,(cols,rows),0.6)
# 图像显示
plt.figure()
plt.subplot(431)
plt.title("原始")
plt.imshow(img1)
plt.subplot(432)
plt.title("绝对扩大")
plt.imshow(res)
plt.subplot(433)
plt.title("相对缩小多少倍")
plt.imshow(res1)
plt.subplot(434)
plt.title("平移(右移500,下移100)")
plt.imshow(dst)
plt.subplot(435)
plt.title("平移(右移500,下移200)")
plt.imshow(dst1)
plt.subplot(436)
plt.title("旋转60度")
plt.imshow(dst2)
plt.subplot(437)
plt.title("水平翻转")
plt.imshow(dst3)
plt.subplot(438)
plt.title("垂直翻转")
plt.imshow(dst4)
plt.subplot(439)
plt.title("水平垂直翻转")
plt.imshow(dst5)
plt.subplot(4,3,10)
plt.title("仿射变换")
plt.imshow(img2)
plt.subplot(4,3,11)
plt.title("透视变换")
plt.imshow(img3)
plt.show()
(2)双线性插值算法实现缩放
双线性插值的特点:
1.计算过程中充分的考虑到了各邻点的特征,具有灰度平滑过渡的特点;
2.一般情况下可以得到满意的结果;
3.具有低通滤波的特性,使图像轮廓变的模糊;
4.平滑作用会使图像细节退化,尤其是在放的的时候;
5.不连续性会产生不希望的结果。
#!/usr/bin/python3
# __*__ coding: utf-8 __*__
'''
双线性插值图像缩放算法
'''
import numpy as np
import cv2 as cv
import math
def bi_linear(src, dst, target_size):
pic = cv.imread(src) # 读取输入图像
th, tw = target_size[0], target_size[1]
emptyImage = np.zeros(target_size, np.uint8)
for k in range(3):
for i in range(th):
for j in range(tw):
# 首先找到在原图中对应的点的(X, Y)坐标
corr_x = (i+0.5)/th*pic.shape[0]-0.5
corr_y = (j+0.5)/tw*pic.shape[1]-0.5
point1 = (math.floor(corr_x), math.floor(corr_y)) # 左上角的点
point2 = (point1[0], point1[1]+1)
point3 = (point1[0]+1, point1[1])
point4 = (point1[0]+1, point1[1]+1)
fr1 = (point2[1]-corr_y)*pic[point1[0], point1[1], k] + (corr_y-point1[1])*pic[point2[0], point2[1], k]
fr2 = (point2[1]-corr_y)*pic[point3[0], point3[1], k] + (corr_y-point1[1])*pic[point4[0], point4[1], k]
emptyImage[i, j, k] = (point3[0]-corr_x)*fr1 + (corr_x-point1[0])*fr2
cv.imwrite(dst, emptyImage)
def main():
src = 'a.jpg'
dst = 'b.png'
target_size = (300, 200, 3) # 变换后的图像大小
bi_linear(src, dst, target_size)
if __name__ == '__main__':
main()
三,图像增强
增强图像中的有用信息,它可以是一个失真的过程,其目的是要改善图像的视觉效果,针对给定图像的应用场合,有目的地强调图像的整体或局部特性,将原来不清晰的图像变得清晰或强调某些感兴趣的特征,扩大图像中不同物体特征之间的差别,抑制不感兴趣的特征,使之改善图像质量、丰富信息量,加强图像判读和识别效果,满足某些特殊分析的需要。
图像增强可分成两大类:频率域法和空间域法。
(1)频率域法
频率域法把图像看成一种二维信号,对其进行基于二维傅里叶变换的信号增强。
高频图像是指强度变化很多的图像,亮度水平从一个像素到另一个像素变化很快。低频图像可能是亮度比较均匀或变化很慢的图像。
在频谱中,图像中心处对应了图像中变化较平缓的区域,四周对应了图像边缘、噪音或者变化陡峭的部分。
因此我们可以将代表了图像边缘、噪音或者变化陡峭的高频率成分滤除掉,只留下变化平缓的低频率成分,再由频域变换回时域,这就相当于对图像进行了平滑处理;相反,若滤去低频率成分,只留下高频率成分,就相当于对图像进行了锐化处理
频域增强的原理十分简单,其应用的重点问题在于滤波半径阈值如何选取。
滤波数学表达式:
其中G(x,y)、 H(u,v)、F(u,v)分别是g(x,y)、h(x,y)、f(x,y)的傅立叶变换。
常用的高通滤波器:
高通滤波器 = 1- 低通滤波器
# coding = utf-8
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
def array2image(arrimg):
"""
:param arrimg: 图片的数组
:return: 图片
"""
image = Image.fromarray(arrimg.astype('uint8')).convert('RGB')
return image
def make_transform_matrix(image_arr, d0, ftype='low'):
"""
构建高斯高/低通滤波
:param image_arr: 图像数组
:param d0: 通带半径
:param ftype: 类型
:return: 滤波器
"""
# 构建滤波器
transfor_matrix = np.zeros(image_arr.shape, dtype=np.float32)
w, h = image_arr.shape
for i in range(w):
for j in range(h):
distance = np.sqrt((i - w / 2) ** 2 + (j - h / 2) ** 2)
# Gaussian滤波函数
transfor_matrix[i, j] = np.e ** (-1 * (distance ** 2 / (2 * d0 ** 2)))
if ftype == 'low':
return transfor_matrix
elif ftype == 'high':
return 1 - transfor_matrix
# 图像灰度化
img_arr = np.array(Image.open('a.jpg').convert('L'))
# 将图像从空间域转换到频率域,傅里叶变换
f = np.fft.fft2(img_arr)
fshift = np.fft.fftshift(f)
# 生成低通滤波器
F_filter1 = make_transform_matrix(img_arr, 30, 'low')
# 滤波
result = fshift * F_filter1
# 将图像从频率域转换到空间域,傅里叶反变换
img_d1 = np.abs(np.fft.ifft2(np.fft.ifftshift(result)))
# 可视化
plt.imshow(array2image(img_d1))
plt.show()
(2)空间域法
空间域图像增强技术指在空间域中,通过线性和非线性变换来增强构成图像的像素
增强的方法主要分为点运算算法和邻域去噪算法
点运算算法即灰度级校正、灰度变换(伽马变换、对数增强)和直方图修正等,目的或使图像成像均匀,或扩大图像动态范围,扩展对比度。
邻域增强算法分为图像平滑和锐化两种。平滑一般用于消除图像噪声,但是也容易引起边缘的模糊。常用算法有均值滤波、中值滤波。锐化的目的在于突出物体的边缘轮廓,便于目标识别。锐化常用算法有梯度法(如Roberts梯度法)、算子法(Sobel算子和拉普拉斯算子等)、掩模匹配法、统计差值法等常用算法有梯度法、算子、高通滤波、掩模匹配法、统计差值法等。
(1)点运算算法
from skimage import exposure
import numpy as np
from PIL import Image
from matplotlib import pyplot as plt
from pylab import mpl
mpl.rcParams['font.sans-serif'] = ['FangSong'] # 指定默认字体
mpl.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
def image2array(image):
"""
:param image: 图片
:return: 图片的数组
"""
image = np.array(image)
return image
def array2image(arrimg):
"""
:param arrimg: 图片的数组
:return: 图片
"""
image = Image.fromarray(arrimg.astype('uint8')).convert('RGB')
return image
def image_gamma_transform(pil_im, gamma):
"""
伽马变换
:param pil_im: 图片
:return: 处理后的图片
"""
image_arr = np.array(pil_im)
image_arr2 = exposure.adjust_gamma(image_arr, gamma)
return array2image(image_arr2)
def image_gamma_transform2(pil_im, gamma):
"""
伽马变换2(源码实现)
:param pil_im: 图片
:return: 处理后的图片
"""
image_arr = np.array(pil_im)
image_arr2 = np.power(image_arr / float(np.max(image_arr)), gamma)
return array2image(image_arr2*float(np.max(image_arr)))
def image_log_transform(pil_im):
"""
图像对数增强
:param pil_im: 图片
:return: 处理后的图片
"""
image_arr = image2array(pil_im)
if len(image_arr.shape) == 3:
for i in range(3):
image_arr[:,:,i] = 255/np.log(255+1)*np.log(1+image_arr[:,:,i])
return array2image(image_arr)
elif len(image_arr.shape) == 2:
# image_arr = 255/np.log(np.max(image_arr)+1)*np.log(1+image_arr)
image_arr = 255/np.log(255+1)*np.log(1+image_arr)
return array2image(image_arr)
def image_histeq(pil_im):
"""
直方图均衡化
:param pil_im: 图片
:return: 处理后的图片
"""
# 计算图像的直方图
image_arr = image2array(pil_im)
imhist, bins = np.histogram(image_arr.flatten(), 256, normed=True)
cdf = imhist.cumsum() # 累计分布函数
cdf = 255*cdf/cdf[-1] # 归一化
# 使用累计分布函数的线性插值计算新的像素值
image_arr2 = np.interp(image_arr.flatten(), bins[:-1], cdf)
return array2image(image_arr2.reshape(image_arr.shape))
if __name__ == '__main__':
image = Image.open('a.jpg').convert('L')
image1 = image_gamma_transform(image,2.7)
image2 = image_gamma_transform2(image,0.3)
image3 = image_log_transform(image)
image4 = image_histeq(image)
plt.figure()
plt.subplot(221)
plt.title("伽马变换,gamma值设置为2.7")
plt.imshow(image1)
plt.subplot(222)
plt.title("伽马变换,gamma值设置为0.3")
plt.imshow(image2)
plt.subplot(223)
plt.title("图像对数增强")
plt.imshow(image3)
plt.subplot(224)
plt.title("直方图均衡化")
plt.imshow(image4)
plt.show()
(2)领域去噪算法
#!/usr/bin/python3
# __*__ coding: utf-8 __*__
from scipy.ndimage import filters
from scipy.signal import convolve2d
from skimage import exposure
import numpy as np
from PIL import Image
from matplotlib import pyplot as plt
from pylab import mpl
mpl.rcParams['font.sans-serif'] = ['FangSong'] # 指定默认字体
mpl.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
def image2array(image):
"""
:param image: 图片
:return: 图片的数组
"""
image = np.array(image)
return image
def array2image(arrimg):
"""
:param arrimg: 图片的数组
:return: 图片
"""
image = Image.fromarray(arrimg.astype('uint8')).convert('RGB')
return image
def image_mean_filter(pil_im):
"""
均值滤波
:param pil_im: 图片
:return: 处理后的图片
"""
image_arr = image2array(pil_im)
dst_arr = np.zeros_like(image_arr)
# 卷积核-均值算子
mean_operator = np.array([[1, 1, 1],
[1, 1, 1],
[1, 1, 1]]) / 9
if len(image_arr.shape) == 3:
for i in range(3):
dst_arr[:, :, i] = convolve2d(image_arr[:, :, i], mean_operator, mode="same")
elif len(image_arr.shape) == 2:
dst_arr = convolve2d(image_arr, mean_operator, mode="same")
return array2image(dst_arr)
def image_medium_filter(pil_im, sigma=5):
"""
中值滤波
中值平滑只对特别尖锐的信号平滑
:param pil_im: 图片
:return: 处理后的图片
"""
image_arr = image2array(pil_im)
if len(image_arr.shape) == 3:
for i in range(3):
image_arr[:,:,i] = filters.median_filter(image_arr[:,:,i], sigma)
return image_arr
elif len(image_arr.shape) == 2:
image_arr = filters.median_filter(image_arr, sigma)
return array2image(image_arr)
def image_laplace_filter(pil_im,sigma):
'''
拉普拉斯算子增强
sigma越大图像越模糊
INPUT -> 单张图文件
OUTPUT -> 处理后的图文件
'''
image_arr = np.array(pil_im)
dst_arr = np.zeros(image_arr.shape, dtype=np.uint8)
filter_arr = dst_arr
# 卷积核-拉普拉斯算子
laplace_operator = np.array([[0, -1, 0],
[-1, 4, -1],
[0, -1, 0]])
if len(image_arr.shape) == 3:
for i in range(3):
dst_arr[:,:,i] = convolve2d(image_arr[:,:,i], laplace_operator, mode="same")
filter_arr[:,:,i] = filters.gaussian_filter(dst_arr[:,:,i], sigma)
elif len(image_arr.shape) == 2:
dst_arr = convolve2d(image_arr, laplace_operator, mode="same")
filter_arr = filters.gaussian_filter(dst_arr, sigma)
dst_arr = image_arr + filter_arr
dst_arr = dst_arr / 255.0
# 饱和处理
mask_1 = dst_arr < 0
mask_2 = dst_arr > 1
dst_arr = dst_arr * (1-mask_1)
dst_arr = dst_arr * (1-mask_2) + mask_2
return array2image(dst_arr*255)
if __name__ == '__main__':
image = Image.open('a.jpg').convert('L')
image1 = image_mean_filter(image)
image2 = image_medium_filter(image)
image3 = image_laplace_filter(image,sigma=5)
plt.figure()
plt.subplot(221)
plt.title("均值滤波")
plt.imshow(image1)
plt.subplot(222)
plt.title("中值滤波")
plt.imshow(image2)
plt.subplot(223)
plt.title("拉普拉斯算子增强")
plt.imshow(image3)
plt.show()
来源:CSDN
作者:桐瑾灬
链接:https://blog.csdn.net/qq_43106863/article/details/103196747