机器学习CV代码练习(八)之数字图像处理
- 使用OpenCV进行数字图像处理和计算机视觉任务。例如:读写图像、旋转缩放、图像滤波、亮度调整、边缘检测、Hough 变换检测几何形状的物体
读取和显示图像---- 方法一:matplotlib.image显示图像
from matplotlib import image as mpimg#画图、读图片
from matplotlib import pyplot as plt
import numpy as np
%matplotlib inline
img1 = mpimg.imread('cat.jpg')#直接变为numpy.ndarray
plt.imshow(img1)
type(img1)
读取和显示图像---- 方法二:cv2
import cv2
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
img2 = cv2.imread('cat.jpg')#opencv保存的是:bgr
plt.imshow(img2)
# type(img2)
#注意图像的色彩由问题.因为cv2加载图像后保存为BGR, 而非RGB的格式. 需要如下方式变换:
img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2RGB)
plt.imshow(img2)
读取和显示图像---- 方法三:常用的图像处理库 - PIL
from PIL import Image
import matplotlib.pyplot as plt
%matplotlib inline
img3 = Image.open('cat.jpg')#PIL.JpegImagePlugin.JpegImageFile
plt.imshow(img3)
type(img3)
#注意此时的图像类型是 JpegImageFile - 而非 numpy array. 这种类型的数据适合PIL库的函数/方法. 可以转换为numpy array:
img3 = np.array(img3)#可以转换成np.array
# 大多数时候我们使用numpy array来表达图像. 可以使用如下方法保存numpy array:
# Save the image保存numpy array
np.save('cat.npy', img3)
#Load the image
img3 = np.load('cat.npy')
# 将np.array-numpy数组转换为PIL Image对象
orig_img = Image.fromarray(img3)
缩放图像
from PIL import Image, ImageOps
import matplotlib.pyplot as plt
%matplotlib inline
# 将np.array-numpy数组转换为PIL Image对象
orig_img = Image.fromarray(img3)
# 缩放为 200 x 200
target_size = (200,200)
new_img = orig_img.resize(target_size)#缩放
n_h, n_w = new_img.size
print('New size:', n_h, 'x', n_w)
- 图像缩放造成了图像形变. 我们可以按照原来图像宽高比缩放图像, 避免形变.
from PIL import Image, ImageOps
scaled_img = orig_img.copy()
scaled_img.thumbnail(target_size, Image.ANTIALIAS)
scaled_height, scaled_width = scaled_img.size
print('Scaled size:', scaled_height, 'x', scaled_width)
画图
import matplotlib.pyplot as plt
%matplotlib inline
fig = plt.figure(figsize=(12, 12))
# Subplot for original image
a=fig.add_subplot(2,1,1)
imgplot = plt.imshow(orig_img)
a.set_title('Before')
plt.show()
查看图像的数值特征
from PIL import Image
import matplotlib.pyplot as plt
%matplotlib inline
img3 = Image.open('cat.darkened.jpeg')
img3 = np.array(img3)
img3.dtype#dtype('uint8'),数组包含8位的整数值. 值的范围0-255. RGB色彩通道每一个像素可能的值.
直方图和CDF都预示图像的值的分布不均衡.
查看–直方图
一个比较自然的图像的值的分布应该是均匀分布的, 可以通过直方图查看.
import matplotlib.pyplot as plt
%matplotlib inline
# Plot a histogram - we need to use ravel to "flatten" the 3 dimensions
plt.hist(img3.ravel())#直方图
plt.show()
查看–累积分布函数 (CDF)图
import matplotlib.pyplot as plt
%matplotlib inline
plt.hist(img3.ravel(), bins=255, cumulative=True)#CDF图
plt.show()
调整调整图像的像素值使得其值变为均匀分布
from PIL import Image, ImageOps
%matplotlib inline
# Equalize the image - but we need to convert the numpy array back to the PIL image format
# ImageOps.equalize():通过调整图像的像素值使得其值变为均匀分布.
img3PIL_eq = ImageOps.equalize(Image.fromarray(img3))
使用滤波器去噪声
添加随机噪声:模拟低亮度时拍摄的照片, 包括大量随机噪声
import skimage#sklearn中的做图像处理的操作
%matplotlib inline
img3_n = skimage.util.random_noise(img3_eq)#添加噪声
plt.imshow(img3_n)
高斯滤波器:使用一个像素临近区域的像素的加权均值代替原来的值.
from scipy.ndimage.filters import gaussian_filter as gauss
%matplotlib inline
img3_gauss = gauss(img3_n, sigma=1) #采用高斯滤波器去除噪声 ,sigma控制滤波强度,越大越虚
plt.imshow(img3_gauss)
中值滤波:使用一个像素临近区域的像素的中间值代替原来的值.
from scipy.ndimage.filters import median_filter as med
%matplotlib inline
img3_med = med(img3_n, size=3)#采用中值滤波器去除噪声
plt.imshow(img3_med)
特征提取——边缘检测
Sobel 边缘检测:寻找图像中在纵横方向上面值变化比较大的区域
步骤:
- 将彩色图像转换为灰度图像.
- 计算横向和纵向的梯度.
- 计算梯度的大小.
- 规范化梯度值.
from PIL import Image, ImageOps
import numpy as np
from PIL import Image
from scipy import ndimage
%matplotlib inline
sx = ndimage.sobel(img, axis=0, mode='constant')#x方向的sobel边缘检测
sy = ndimage.sobel(img, axis=1, mode='constant')#y方向的sobel边缘检测
sob = np.hypot(sx, sy)#x和y方向的sobel边缘检测
Canny边缘检测
from scipy import ndimage
from skimage.feature import canny
canny_edges = canny(img, sigma=5)#canny边缘检测
Harris Corner Detector 哈里斯边角侦测:检测在所有方向像素值变化都比较大的区域, 这些区域被称为corner, 边角.
import numpy as np
import cv2
from matplotlib import pyplot as plt
filename = 'chessboard.jpg'
img = cv2.imread(filename)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
gray = np.float32(gray)
plt.imshow(gray),plt.show()
dst = cv2.cornerHarris(gray,2,3,0.04)#cornerHarris边角检测为一个值dst
#result is dilated for marking the corners, not important
dst = cv2.dilate(dst,None)#结果边角增强些,看得清楚
# Threshold for an optimal value, it may vary depending on the image.
img[dst>0.01*dst.max()]=[0,0,255]
plt.imshow(img),plt.show()