【python】图像数据预处理
图像数据预处理:颜色空间转换(1)彩色图像灰度化(2)更换三通道顺序BGR为RGB(3)BGR和HSV颜色空间转换、坐标变换(1)图像的平移(2)图像的旋转(3)图像的镜像(4)图像的缩放、灰度变换、伽玛变换、基于直方图的灰度变化、图像滤波(1)中值滤波器(2)均值滤波器(3)高速滤波(4)锐化.........
安装cv2
pip install -i https://pypi.douban.com/simple opencv-python
1. 基本操作
(1)用opencv读取图像
代码
import cv2
# 读取一幅图像 第一个参数是图像路径
# 第二个参数代表读取方式,1表示3通道彩色,0表示单通道灰度
im = cv2.imread(r"emo1.jpg", 1)
# 在“test”窗口显示图像im
cv2.imshow("test", im)
# 等待用户按键反馈
cv2.waitKey()
(2)打印图像数据的类型和图像的尺寸
代码
# 打印图像数据的数据结构类型
print(type(im))
# 打印图像的尺寸
print(im.shape)
运行结果
输出了图像的数据类型和图像的尺寸,328×447×3表示是一个三通道的彩色图像。
(3)将图像保存到指定的路径
代码
# 将图像保存到指定路径
cv2.imwrite('emo.jpg', im)
返回True表示图像保存成功
2. 颜色空间转换
(1)彩色图像灰度化
使用opencv里的cvtColor将图像变成灰度图像,再显示这幅灰度图
代码
import cv2
im = cv2.imread(r"emo1.jpg")
cv2.imshow("Gray0", im)
# 使用opencv里的cvtColor进行颜色空间变化 cv2.COLOR_BGR2GRAY 代表 BGR to gray
img_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
cv2.imshow("Gray1", img_gray)
cv2.waitKey()
运行结果
这是原始图像
这是变换后的灰度图像
(2)更换三通道顺序BGR为RGB
可以转换三个通道的顺序,将一个BGR的彩色图像转换成一个RBG的彩色图像,同样调用的是opencv里的cvtColor
代码
import cv2
im = cv2.imread(r"emo1.jpg")
cv2.imshow("BRG", im)
# 使用opencv里的cvtColor进行颜色空间变化 cv2.COLOR_BGR2RGB 代表 BGR to RGB
im_rgb = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
#当图像数据为3通道时,imshow函数认为数据是BGR的
#使用imshow显示RGB数据,会发现图片显示颜色畸变
cv2.imshow("RGB", im_rgb)
cv2.waitKey()
运行结果
这是原始图像
这是图像转换后的一个结果
(3)BGR和HSV颜色空间转换
把一个BGR的图像转换成一个HSV的彩色图像
代码
import cv2
im = cv2.imread(r"emo1.jpg")
cv2.imshow("BRG", im)
# 使用opencv里的cvtColor进行颜色空间变化 cv2.COLOR_BGR2HSV 代表 BGR to HSV
im_rgb = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)
#当图像数据为3通道时,imshow函数认为数据是BGR的
#使用imshow显示HSV数据,会将HSV分量强行当做BGR进行显示
cv2.imshow("RGB", im_rgb)
cv2.waitKey()
运行结果
这是原始图像
这是转换的结果
3. 坐标变换
(1)图像的平移
A.定义平移的函数
a.首先需要获取图像的一个尺寸
b.然后再定义平移的一个矩阵
c.再调用仿射变换的函数实现图像平移(需要指定三个参数,第一个是输入图像,第二个是平移矩阵,第三个是获取图像的一个尺寸)
B.调用定义的平移函数来对图像进行平移操作
代码
import numpy as np
import cv2
# 定义平移translate函数
def translate(img, x, y):
#获取图像尺寸
(h, w) = img.shape[:2]
#定义平移矩阵
M = np.float32([[1, 0, x], [0, 1, y]])
#使用OpenCV仿射变换函数实现平移操作
shifted = cv2.warpAffine(img, M, (w, h))
#返回转换后的图像
return shifted
# 加载图像并显示
im = cv2.imread("emo1.jpg")
cv2.imshow("Orig", im)
# 对原图做平移操作
# 下移50像素
shifted = translate(im, 0, 50)
cv2.imshow("Shift1", shifted)
# 左移100像素
shifted = translate(im, -100, 0)
cv2.imshow("Shift2", shifted)
# 右移50,下移100像素
shifted = translate(im, 50, 100)
cv2.imshow("Shift3", shifted)
cv2.waitKey()
运行结果
这是原始图像
这是不同的平移尺寸后的效果
(2)图像的旋转
A.定义一个旋转的函数
a.获取图像的尺寸
b.如果旋转中心值缺失的话,就把旋转中心定义为图像的中心
c.然后调用opencv当中的getRotationMatrix2D计算旋转矩阵
d.然后我们再用opencv当中的仿射变换函数实现旋转操作
代码
import numpy as np
import cv2
# 定义旋转rotate函数
def rotate(img, angle, center = None, scale = 0.7):
# 获取图像尺寸
(h, w) = img.shape[:2]
# 旋转中心的缺失值为图像中心
if center is None:
center = (w/2, h/2)
# 调用计算旋转矩阵函数
M = cv2.getRotationMatrix2D(center, angle, scale)
# 使用opencv仿射变换函数实现旋转操作
rotated = cv2.warpAffine(img, M, (w, h))
# 返回旋转后的图像
return rotated
im = cv2.imread("emo1.jpg")
cv2.imshow("Orig", im)
# 对原图像做旋转操作
# 逆时针45度
rotated = rotate(im, 45)
cv2.imshow("Rotatel", rotated)
# 顺时针20度
rotated = rotate(im, -20)
cv2.imshow("Rotate2", rotated)
# 逆时针90度
rotated = rotate(im, 90)
cv2.imshow("Rotate3", rotated)
cv2.waitKey()
运行结果
这是原图
这是将图片逆时针旋转45度的效果
这是顺时针旋转45度的效果
这是将图片逆时针旋转90度的效果
(3)图像的镜像
调用opencv中的flip来实现图像镜像,需要传入两个参数,第一个参数是要读取的图像,第二个参数如果是零的话代表水平镜像,如果是一的话代表执行垂直镜像
代码
import numpy as np
import cv2
im = cv2.imread("emo1.jpg")
cv2.imshow("orig", im)
# 进行水平镜像
im_flip0 = cv2.flip(im, 0)
cv2.imshow("flip vertical", im_flip0)
# 进行垂直镜像
im_flip1 = cv2.flip(im, 1)
cv2.imshow("flip horizontal", im_flip1)
cv2.waitKey()
运行结果
这是图像水平镜像和垂直镜像后的效果
(4)图像的缩放
实现缩放变换,首先要获取整个图像的一个尺寸,然后再定义目标缩放尺寸,用opencv里面的resize对图像进行缩放,需要实例化三个参数。第一个是需要缩放的图像,第二是播放后图像的尺寸,第三个是插值的方法,这里使用的是最邻近插值法,也可以用双线性插值法进行缩放。
代码
import numpy as np
import cv2
im = cv2.imread("emo1.jpg")
cv2.imshow("orig", im)
# 获取图像尺寸
(h, w) = im.shape[:2]
# 缩放的目标尺寸
dst_size = (200, 300)
# 最邻近插值
method = cv2.INTER_NEAREST
# 进行缩放
resized = cv2.resize(im, dst_size, interpolation = method)
cv2.imshow("resized1", resized)
# 缩放的目标尺寸
dst_size = (800,600)
# 双线性插值
method = cv2.INTER_LINEAR
# 进行缩放
resized = cv2.resize(im, dst_size, interpolation = method)
cv2.imshow("resized2", resized)
cv2.waitKey()
运行结果
这是原始的图像
这是用最邻近插值法缩放后的图像
这是用双线性插值法缩放后的图像
4.灰度变换
首先定义一个线性灰度变换的函数,输入包括原始图像k值
(1)如果k的取值范围在0~1的范围内就对灰度值进行压缩
(2)如果k的取值范围大于1的话,就对灰度值进行拉伸
(3)如果k=-1且b=255的话,就对图像进行灰度反转
代码
import numpy as np
import cv2
from matplotlib import pyplot as plt
#定义线性灰度变化函数
#k>1时实现灰度数值的拉伸
#0<k<1时实现灰度数值的压缩
#k=-l b=255 实现灰度反转
def linear_trans(img, k, b=0):
#计算灰度线性变换的映射表
trans_list = [(np.float32(x)*k+b) for x in range(256)]
#将列表转换为np.array
trans_table = np.array(trans_list)
#将超过[0,245]灰度范围的数值进行调整,并指定数据类型为uint8
trans_table[trans_table>255] = 255
trans_table[trans_table<0] = 0
trans_table = np.round(trans_table).astype(np.uint8)
#使用opencv的look up table函数修改图像的灰度值
return cv2.LUT(img, trans_table)
im = cv2.imread("emo1.jpg")
cv2.imshow("orig", im)
# 反转
im_inversion = linear_trans(im, -1, 255)
cv2.imshow("inversion", im_inversion)
# 灰度拉伸
im_stretch = linear_trans(im, 1.2)
cv2.imshow("garystrech", im_stretch)
# 灰度压缩
im_compress = linear_trans(im, 0.8)
cv2.imshow("graycompress", im_compress)
cv2.waitKey()
运行结果
这是原始图像
这是我们对图像进行灰度压缩后的效果,可以看到图像的对比度降低了
这是灰度拉伸的效果,图像的对比度增强了
这是灰度反转的一个效果图
5. 伽玛变换
首先定义一个伽玛的变换函数,首先将图片当中的灰度值全都归一化到0-1的范围内,然后执行伽马变换,最后再将图像的灰度值恢复到0~255的范围之内
代码
import numpy as np
import cv2
from matplotlib import pyplot as plt
# 定义伽马变化函数
def gamma_trans(img, gamma):
#先归一化到1,做伽马计算,再还原到[0,255]
gamma_list = [np.power(x/255.0, gamma) * 255 for x in range(256)]
#将列表转换为np.array,并指定数据类型为uint8
gamma_table = np.round(np.array(gamma_list)).astype(np.uint8)
#使用opencv的look up table函数修改图像的灰度值
return cv2.LUT(img, gamma_table)
im = cv2.imread("emo1.jpg", 0)
cv2.imshow("orig", im)
# 使用伽玛值为0.5的变化,实现对暗部的拉伸,亮部的压缩
img_gamma05 = gamma_trans(im, 0.5)
cv2.imshow("gamma0.5", img_gamma05)
# 使用伽玛值为2的变化,实现对暗部的压缩,亮部的拉伸
img_gamma2 = gamma_trans(im, 2)
cv2.imshow("gamma2", img_gamma2)
cv2.waitKey()
运行结果
原始图像
这是通过伽玛等于0.5后的伽玛变化的结果,可以看到图像的暗部灰度值的动态范围是被拉伸了的,图像亮度灰度值的动态范围被压缩
这是做伽玛等于2的伽玛变化后的结果,可以看到亮部灰度值的动态范围被拉伸,而暗部灰度值的动态范围被压缩,所以整个画面会显得比较暗。
6. 基于直方图的灰度变化
可以用pyplot绘制图像的直方图,直方图当中灰度级的动态范围是从0~255,一共有256个灰度级。
代码
import cv2
from matplotlib import pyplot as plt
# 读取并显示图像
im = cv2.imread("emo1.jpg", 0)
cv2.imshow("orig", im)
# 绘制灰度图像的直方图
plt.hist(im.ravel(), 256, [0,256])
plt.show()
cv2.waitKey()
运行结果
这是原始图像以及原始图像对应的直方图
可以调用opencv当中的equalizeHist对图像进行直方图均衡化
代码
# import cv2
from matplotlib import pyplot as plt
im = cv2.imread("emo1.jpg", 0)
cv2.imshow("orig", im)
# 调用opencv的直方图均衡化API
im_equl = cv2.equalizeHist(im)
cv2.imshow("equal", im_equl)
# 显示原始图像的直方图
plt.subplot(2, 1, 1)
plt.hist(im.ravel(), 256, [0,256], label="orig")
plt.legend()
# 显示均衡化图像的直方图
plt.subplot(2, 1, 2)
plt.hist(im_equl.ravel(), 256, [0,256], label="equalize")
plt.legend()
plt.show()
cv2.waitKey()
运行结果
这是对原始图像进行直方图均值化后的图像
这是其对应的直方图,可以看到图像整个的对比度被增强了,暗处的一些细节信息更明显了
7. 图像滤波
(1)中值滤波器
可以调用opencv当中的medianBlur这个API对图像进行中值滤波。需要实例化两个参数,第一个是输入的图像,第二个是中值滤波器的大小,5代表中值滤波器的大小是5×5
代码
import cv2
import numpy as np
im = cv2.imread("dog.jpg")
cv2.imshow("orig", im)
# 调用opencv的中值模糊API
im_medianblur = cv2.medianBlur(im, 5)
cv2.imshow("median_blur",im_medianblur )
cv2.waitKey()
运行结果
这是一个原图,可以看到原图里面是充满了噪声,这个噪声就是salt & pepper(椒盐噪声)。
这是对图像进行中值滤波后的效果
通过中值滤波之后,可以看到图像明显变得清晰了。这就是中值滤波的优点,它可以达到降噪的效果,同时可以保留原始图像的一个锐度。
(2)均值滤波器
A.我们调用opencv当中的blur这个API对图像进行均值滤波,均值滤波器的大小是3×3的
B.也可以自己定义一个均值算子,就需要创建一个矩阵,这里矩阵的大小是3×3,矩阵中的每一个元素都是1,最后对窗口当中的9个元素取均值,这就是均值算子。然后用opencv中的filter,用这个均值算子对图像进行均值滤波
代码
#方法一:直接调用opencv的API
import cv2
import numpy as np
im = cv2.imread("emo1.jpg")
cv2.imshow ("orig", im)
#调用opencv的均值模糊API
im_meanblur1 = cv2.blur(im, (3, 3))
cv2.imshow("mean_blur_1", im_meanblur1)
cv2.waitKey ()
#方法二:使用均值算子和filter2D自定义滤波操作import cv2
import cv2
import numpy as np
im = cv2.imread("emo1.jpg")
cv2.imshow ("orig", im)
# 均值算子
mean_blur = np.ones([3,3], np.float32)/9
# 使用filter2D进行滤波操作
im_meanblur2 = cv2.filter2D(im, -1, mean_blur)
cv2.imshow("mean_blur_2", im_meanblur2)
cv2.waitKey()
运行结果
这是原始图像
这是对图像进行均值滤波后的效果,可以看到图像明显变得模糊化了,这就是均值滤波的一个效果,它可以达到图像平滑的一个效果
(3)高斯滤波
A.可以直接调用opencv当中的GaussianBlur这个API对图像进行高斯滤波
代码
#方法一:直接调用opencv的API
import cv2
import numpy as np
im = cv2.imread("emo1.jpg")
cv2.imshow ("orig", im)
# 调用opencv的高斯模糊API
im_gaussianblur1 = cv2.GaussianBlur(im, (5, 5), 0)
cv2.imshow("gaussian_blur_1", im_gaussianblur1)
cv2.waitKey()
运行结果
B.也可以自己建一个高斯filter,然后用opencv当中filter2D对图像进行滤波
代码
#方法二:使用高斯算子和filter2D自定义滤波操作
import cv2
import numpy as np
im = cv2.imread("emo1.jpg")
cv2.imshow ("orig", im)
# 高斯算子
gaussian_blur = np.array([
[1, 4, 7, 4, 1],
[4, 16 , 26, 16, 4],
[7, 26, 41, 26, 7],
[4, 16 , 26, 16, 4],
[1, 4, 7, 4, 1]],np.float32)/273
# 使用filter2D进行滤波操作
im_gaussianblur2 = cv2.filter2D(im, -1, gaussian_blur)
cv2.imshow("gaussian_blur_2", im_gaussianblur2)
运行结果
相较于刚才均值滤波器的效果,如果用高斯滤波的话,可以一定程度的减少图像的模糊化
(4)锐化
图像的锐化分为两个步骤,第一是对图像进行边缘检测,第二步是原始图像乘以一定的系数然后再加上边缘检测后的效果图。锐化算子一般分为基于一阶梯度的和基于二阶梯度的。基于一阶梯度的锐化算子最典型的就是Sobel梯度算子,基于二阶梯度的锐化算子最典型的就是拉普拉斯算子。
这里我们建立的两个锐化算子都是二阶的锐化算子
代码
import cv2
import numpy as np
im = cv2.imread("emo1.jpg")
cv2.imshow ("orig", im)
# 锐化算子
sharpen_1 = np.array([
[-1, -1, -1],
[-1, 9, -1],
[-1, -1, -1]
])
# 使用filter2D进行滤波操作
im_sharpen_1 = cv2.filter2D(im, -1, sharpen_1)
cv2.imshow("sharpen_1", im_sharpen_1)
# 锐化算子3
sharpen_2 = np.array([
[0, -1, 0],
[-1, 8, -1],
[0, 1, 0]])/4.0
# 使用filter2D进行滤波操作
im_sharpen_2 = cv2.filter2D(im, -1, sharpen_2)
cv2.imshow("sharpen_2", im_sharpen_2)
cv2.waitKey()
运行结果
这是原始图像
这是图像锐化后的一个效果
这是用第二个锐化算进行图像液化后的果,可以观察到第二个锐化算子最后有一个除以四的过程,就可以增加图像的一个模糊化。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)