OpenCV
导包
%matplotlib inline
%config InlineBackend.figure_format='svg' # 输出矢量图
import cv2
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 防中文乱码
定义图像显示函数
def cv_show(name, img, delay=0):
cv2.imshow(name, img)
cv2.waitKey(delay)
cv2.destroyAllWindows()
def plt_show(img, name = '', subplot = 111):
plt.subplot(subplot)
if len(img.shape) == 3:
plt.imshow(img[:, :, ::-1])
else:
plt.imshow(img, cmap='gray')
if len(name) > 0:
plt.title(name)
读取图像
# 读取彩色图
img = cv2.imread('cat.png')
# 读取灰度图
# img = cv2.imread('cat.png', cv2.IMREAD_GRAYSCALE)
常用方法
获得图片尺寸
img.shape # [高度 h, 宽度 w, 颜色 c]
(600, 960, 3)
修改图片尺寸
cv2.resize(img, (512, 512))
cv2.resize(img, (0, 0), fx=2, fy=3) # x 轴放大 2 倍,y 轴放大 3 倍
plt_show(img, '原图', 221)
plt_show(cv2.resize(img, (100, 200)), '100x200', 222)
plt_show(cv2.resize(img, (0, 0), fx=2, fy=3), 'fx=2, fy=3', 223)
显示图片
# cv_show('img', img)
plt_show(img, 'img')
截取部分图像数据
img[60:260, 230:470] # h: 200, w: 240
plt_show(img[60:260, 230:470], 'img[60:260, 230:470]')
颜色通道提取
b, g, r = cv2.split(img)
合并颜色通道
img = cv2.merge((b, g, r))
复制图片
plt_show(img.copy(), 'img.copy')
删除指定颜色通道
red_cat = img.copy()
red_cat[:, :, 0] = 0 # b
red_cat[:, :, 1] = 0 # g
green_cat = img.copy()
green_cat[:, :, 0] = 0 # b
green_cat[:, :, 2] = 0 # r
blue_cat = img.copy()
blue_cat[:, :, 1] = 0 # g
blue_cat[:, :, 2] = 0 # r
plt_show(img,'原图', 221)
plt_show(red_cat,'R 通道', 222)
plt_show(green_cat,'G 通道', 223)
plt_show(blue_cat,'B 通道', 224)
边界填充
top, bottom, left, right = (200, 200, 200, 200)
replicate = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_WRAP)
constant = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=(0, 0, 255)) # value=(b, g, r)
plt_show(img, '原图', 231)
plt_show(replicate, 'REPLICATE', 232)
plt_show(reflect, 'REFLECT', 233)
plt_show(reflect101, 'REFLECT_101', 234)
plt_show(wrap, 'WRAP', 235)
plt_show(constant, 'CONSTANT', 236)
- BORDER_REPLICATE:复制法,也就是复制最边缘像素;
- BORDER_REFLECT:反射法,对感兴趣的图像中的像素在两边进行复制,
hgfedcba|abcdefgh|hgfedcba
; - BORDER_REFLECT_1O1:反射法,也就是以最边缘像素为轴,对称,
hfedcb|abcdefgh|gfedcba
- BORDER_WRAP:外包装法,
abcdefgh|abcdefgh|abcdefgh
- BORDER_CONSTANT:常量法,常数值填充。
数值计算
使用 numpy 进行数值计算
plt_show(img + 50)
img[:5, :, 0]
array([[ 70, 69, 68, ..., 115, 115, 115], [ 72, 71, 69, ..., 115, 116, 116], [ 72, 71, 70, ..., 116, 117, 118], [ 71, 71, 70, ..., 117, 117, 118], [ 71, 71, 70, ..., 117, 117, 116]], dtype=uint8)
# 超过 255 会自动求余,相当于 % 256
(img + 70)[:5, :, 0]
array([[140, 139, 138, ..., 185, 185, 185], [142, 141, 139, ..., 185, 186, 186], [142, 141, 140, ..., 186, 187, 188], [141, 141, 140, ..., 187, 187, 188], [141, 141, 140, ..., 187, 187, 186]], dtype=uint8)
# 同尺寸图片可以相加
(img + img.copy())[:5, :, 0]
array([[140, 138, 136, ..., 230, 230, 230], [144, 142, 138, ..., 230, 232, 232], [144, 142, 140, ..., 232, 234, 236], [142, 142, 140, ..., 234, 234, 236], [142, 142, 140, ..., 234, 234, 232]], dtype=uint8)
使用 OpenCV 进行数值计算
plt_show(cv2.add(img, -50), '-50', 221)
plt_show(img, '原图', 222)
plt_show(cv2.add(img, 50), '+50', 223)
img[:5, :, 0]
array([[ 70, 69, 68, ..., 115, 115, 115], [ 72, 71, 69, ..., 115, 116, 116], [ 72, 71, 70, ..., 116, 117, 118], [ 71, 71, 70, ..., 117, 117, 118], [ 71, 71, 70, ..., 117, 117, 116]], dtype=uint8)
# 超过 255 则为 255
cv2.add(img, 70)[:5, :, 0]
array([[140, 139, 138, ..., 185, 185, 185], [142, 141, 139, ..., 185, 186, 186], [142, 141, 140, ..., 186, 187, 188], [141, 141, 140, ..., 187, 187, 188], [141, 141, 140, ..., 187, 187, 186]], dtype=uint8)
图像阈值
- src:输入图,只能输入单通道图像,通常来说为灰度图
- dst:输出图
- thresh:阈值
- maxval:当像素值超过了阈值(或者小于阈值,根据 type 来决定),所赋予的值
- type:二值化操作的类型
cv2.THRESH_BINARY
超过阈值部分取maxval
(最大值),否则取0
cv2.THRESH_BINARY_INV
THRESH_BINARY
的反转cv2.THRESH_TRUNC
大于阈值部分设为阈值,否则不变cv2.THRESH_TOZERO
大于阈值部分不改变,否则设为0
cv2.THRESH_TOZERO_INV
THRESH_TOZERO
的反转
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
ret, thresh2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV)
ret, thresh3 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TRUNC)
ret, thresh4 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO)
ret, thresh5 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO_INV)
plt_show(img_gray, '原图', 231)
plt_show(thresh1, 'THRESH_BINARY', 232)
plt_show(thresh2, 'THRESH_BINARY_INV', 233)
plt_show(thresh3, 'THRESH_TRUNC', 234)
plt_show(thresh4, 'THRESH_TOZERO', 235)
plt_show(thresh5, 'THRESH_TOZERO_INV', 236)
图片融合
img_dog = cv2.imread('dog.jpg')
img_dog = cv2.resize(img_dog, (img.shape[1], img.shape[0]))
plt_show(cv2.addWeighted(img, 0.4, img_dog, 0.6, 0))
形态学
腐蚀操作
img_dege = cv2.imread('dege.png')
# 卷积核大小 3x3
kernel = np.ones((3, 3), np.uint8)
# 迭代次数为 1
img_erode = cv2.erode(img_dege, kernel, iterations=2)
plt_show(img_dege, '原图', 121)
plt_show(img_erode, '腐蚀', 122)
膨胀操作
img_dilate = cv2.dilate(img_dege, kernel, iterations=2)
img_dilate2 = cv2.dilate(img_erode, kernel, iterations=2)
plt_show(img_dege, '原图', 221)
plt_show(img_erode, '腐蚀', 222)
plt_show(img_dilate, '膨胀', 223)
plt_show(img_dilate2, '膨胀', 224)
开运算与闭运算
- 开运算:先腐蚀,再膨胀
- 闭运算:先膨胀,再腐蚀
# 开运算
opening = cv2.morphologyEx(img_dege, cv2.MORPH_OPEN, kernel)
# 闭运算
closing = cv2.morphologyEx(img_dege, cv2.MORPH_CLOSE, kernel)
plt_show(img_dege, '原图', 221)
plt_show(opening, '开运算', 222)
plt_show(closing, '闭运算', 223)