opencv python


须知:图像是RGB,opencv 处理 BGR


定义图像显示函数

def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyWindow(name)

显示图像

# 原图
img = cv2.imread('cat.jpg')
cv_show('img', img)

# 灰度图
img = cv2.imread('cat.jpg', cv2.IMREAD_GRAYSCALE)
cv_show('img', img)

# 保存
cv2.imwrite('saveimg.jpg', img)

显示视频

vc = cv2.VideoCapture('test.mp4')
if vc.isOpened():
    open, frame = vc.read()
else:
    open = False

while open:
    ret, frame = vc.read()
    if frame is None:
        break
    if ret == True:
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        cv2.imshow('reslut', gray)
        if cv2.waitKey(34) & 0xFF == 27:
            break
vc.release()
cv2.destroyWindow('reslut')

RoI 区域

感兴趣区域,截取图像

img = cv2.imread('cat.jpg')
cat = img[0:200, 0:200]  # x为0到200, y为0到200
cv_show('cat', cat)

颜色通道提取

b, g, r = cv2.split(img)
cv_show('b', b)
cv_show('g', g)
cv_show('r', r)

还原

img = cv2.merge((b, g, r))

阈值

ret, dst = cv2.threshold(src, thresh, maxval, type)
ret, 输出 = cv2.threshold(输入, 阈值, maxval, 类型)

maxval 由类型决定;
类型:
	cv2.THRESH_BINARY 超过阈值取最大值,否则置0
	cv2.THRESH_BINARY_INV 与上相反
	cv2.THRESH_TRUNC 超过阈值取阈值,否则不变
	cv2.THRESH_TOZERO 超过阈值不变,否则置0
	cv2.THRESH_TOZERO_INV 与上相反
import cv2
import matplotlib.pyplot as plt

ret, dst1 = cv2.threshold(src, 127, 255, cv2.THRESH_BINARY)
ret, dst2 = cv2.threshold(src, 127, 255, cv2.THRESH_BINARY_INV)
ret, dst3 = cv2.threshold(src, 127, 255, cv2.THRESH_TRUNC)
ret, dst4 = cv2.threshold(src, 127, 255, cv2.THRESH_TOZERO)
ret, dst5 = cv2.threshold(src, 127, 255, cv2.THRESH_TOZERO_INV)

titles = ['original', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [src, dst1, dst2, dst3, dst4, dst5]
for i in range(6):
    plt.subplot(2, 3, i+1)
    plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述

# 灰度
src = cv2.imread('cat.jpg', cv2.IMREAD_GRAYSCALE) 

在这里插入图片描述BINARY:亮点全为白(>127 255),暗点全为黑( <127 0)
BINARY_INV:与上相反(>127 0, <127 255)
TRUNC:降低白点的亮度,暗点保留 (>127 127 , <127 不变)
TOZERO:(>127 不变,<127 0)
TOZERO_INV:(>127 0,<127 不变)


平滑

消除噪点

import cv2
# import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('cat.jpg')
#
# # 均值滤波、方框滤波、高斯滤波、中值滤波
blur = cv2.blur(img, (3, 3))
box = cv2.boxFilter(img, -1, (3, 3), normalize=True)
gaussian = cv2.GaussianBlur(img, (5, 5), 1)
median = cv2.medianBlur(img, 5)
#
# res = np.hstack((blur, box, gaussian, median))
# cv_show('666', res)

titles = ['blur', 'box', 'gaussian', 'median']
images = [blur, box, gaussian, median]
s = [[1, 1], [1, 2], [2, 2], [2, 2], [2, 3], [2, 3], [2, 4], [2, 4], [3, 3]]
for i in range(len(images)):
    row, col = s[len(images)-1]
    plt.subplot(row, col, i+1)
    plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

均值滤波,使用 3 × 3 3\times 3 3×3 滤波器,滤波器的值相同,内积取平均值。

方框滤波,与均值滤波类似

高斯滤波,使用 5 × 5 5\times 5 5×5 滤波器,滤波器中心点为均值,均值最大,远离均值越小。

在这里插入图片描述


形态学操作

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('cat.jpg')

# 腐蚀(去刺),膨胀
kernel = np.ones((3, 3), np.uint8)  # 3 x 3 滤波器全为1
erosion = cv2.erode(img, kernel, iterations=1)  # 腐蚀1次
dilate = cv2.dilate(img, kernel, iterations=1)  # 膨胀1次

# 开运算(去刺膨胀),闭运算(膨胀去刺)
kernel2 = np.ones((5, 5), np.uint8)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel2)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel2)

# 梯度运算(膨胀-腐蚀)
kernel3 = np.ones((7, 7), np.uint8)
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)

# 顶帽(输入-开运算),黑帽(闭运算-输入)
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)


titles = ['original', 'erosion', 'dilate', 'opening=\nerosion+dilate', 'closing=\ndilate+erosion', 'gradient=\ndialte-erosion', 'tophat=\nimg-opening', 'blackhat=\nclosing-img']
images = [img, erosion, dilate, opening, closing, gradient, tophat, blackhat]
for i in range(8):
    plt.subplot(2, 4, i+1)
    plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述
在这里插入图片描述


边缘检测

sobel

水平方向梯度:右边 - 左边
G x = [ − 1 0 + 1 − 2 0 + 2 − 1 0 + 1 ] ∗ A G_x=\begin{bmatrix} -1 & 0&+1 \\ -2 & 0& +2\\ -1 & 0 &+1\end{bmatrix}*A Gx=121000+1+2+1A

垂直方向梯度:下边 - 上边
G y = [ − 1 − 2 − 1 0 0 0 + 1 + 2 + 1 ] ∗ A G_y=\begin{bmatrix} -1 & -2&-1 \\ 0 & 0& 0\\ +1 & +2 &+1\end{bmatrix}*A Gy=10+120+210+1A

#sobel
import matplotlib.pyplot as plt
img = cv2.imread('cat.jpg', cv2.IMREAD_GRAYSCALE)

sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)  # 水平梯度
sobelx_ = cv2.convertScaleAbs(sobelx)
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)  # 垂直梯度
sobely_ = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0) # 0为偏置

titles = ['original', 'sobelx', 'sobelx_abs', 'sobely', 'sobely_abs', 'sobelxy']
images = [img, sobelx, sobelx_, sobely, sobely_, sobelxy]
s = [[1, 1], [1, 2], [2, 2], [2, 2], [2, 3], [2, 3], [2, 4], [2, 4], [3, 3]]
for i in range(len(images)):
    row, col = s[len(images)-1]
    plt.subplot(row, col, i+1)
    plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述

在这里插入图片描述


scharr

水平方向梯度:右边 - 左边
G x = [ − 3 0 + 3 − 10 0 + 10 − 3 0 + 3 ] ∗ A G_x=\begin{bmatrix} -3 & 0&+3 \\ -10 & 0& +10\\ -3 & 0 &+3\end{bmatrix}*A Gx=3103000+3+10+3A

垂直方向梯度:下边 - 上边
G y = [ − 3 − 10 − 3 0 0 0 + 3 + 10 + 3 ] ∗ A G_y=\begin{bmatrix} -3 & -10&-3 \\ 0 & 0& 0\\ +3 & +10 &+3\end{bmatrix}*A Gy=30+3100+1030+3A

scharr 的值比 sobel 更大,计算大差异也更大,因此 scharr 对边缘更敏感。

import matplotlib.pyplot as plt
img = cv2.imread('cat.jpg', cv2.IMREAD_GRAYSCALE)

scharrx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)  # 水平梯度
scharrx_ = cv2.convertScaleAbs(scharrx)
scharry = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)  # 垂直梯度
scharry_ = cv2.convertScaleAbs(scharry)
scharrxy = cv2.addWeighted(scharrx, 0.5, scharry, 0.5, 0) # 0为偏置

titles = ['original', 'scharrx', 'scharrx_abs', 'scharry', 'scharry_abs', 'scharrxy']
images = [img, scharrx, scharrx_, scharry, scharry_, scharrxy]
s = [[1, 1], [1, 2], [2, 2], [2, 2], [2, 3], [2, 3], [2, 4], [2, 4], [3, 3]]
for i in range(len(images)):
    row, col = s[len(images)-1]
    plt.subplot(row, col, i+1)
    plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述
sobel 和 scharr 对比:
在这里插入图片描述


拉普拉斯算子

用中心点周围的四个点,如果它不是边缘的话,结果为零,即梯度为零。拉普拉斯算子缺点是对噪声比较敏感。
G x = [ 0 1 0 1 − 4 1 0 1 0 ] G_x=\begin{bmatrix} 0 & 1&0 \\ 1 & -4& 1\\ 0 & 1 &0\end{bmatrix} Gx=010141010

laplacian = cv2.Laplacian(img, cv2.CV_64F)
laplacian = cv2.convertScaleAbs(laplacian)

在这里插入图片描述

canny

  1. 高斯滤波(归一化高斯滤波)
  2. 计算每个像素的梯度强度 G = G x 2 + G y 2 G = \sqrt{Gx^2+G_y^2} G=Gx2+Gy2 和方向 θ = arctan ⁡ G X G y \theta = \arctan \frac{G_X}{G_y} θ=arctanGyGX
  3. 非极大值抑制(NMS)
  4. 双阈值
  5. 抑制孤立的弱边缘

G x = S x ∗ A G_x=S_x * A Gx=SxA
G y = S y ∗ A G_y=S_y * A Gy=SyA

S x = [ − 1 0 + 1 − 2 0 + 2 − 1 0 + 1 ] ∗ A S_x=\begin{bmatrix} -1 & 0&+1 \\ -2 & 0& +2\\ -1 & 0 &+1\end{bmatrix}*A Sx=121000+1+2+1A

S y = [ + 1 + 2 + 1 0 0 0 − 1 − 2 − 1 ] ∗ A S_y=\begin{bmatrix} +1 & +2 &+1\\ 0 & 0& 0\\ -1 & -2&-1 \end{bmatrix}*A Sy=+101+202+101A

非极大值抑制

从左到右, c a b
如果在a点处不是边缘,则 a - c 约等于 b - a
如果在a点处是边缘,则 a - c > b - a ,或者 a - c < b - a

双阈值

梯度值大于最大值,为边界
梯度值介于最小值和最大值:如果与边界相连则为边界,否则舍弃
梯度值小于最小值,舍弃

import matplotlib.pyplot as plt
img = cv2.imread('cat.jpg', cv2.IMREAD_GRAYSCALE)

v1 = cv2.Canny(img, 80, 150)
v2 = cv2.Canny(img, 50, 150)
v3 = cv2.Canny(img, 30, 150)

v4 = cv2.Canny(img, 80, 120)
v5 = cv2.Canny(img, 50, 100)
v6 = cv2.Canny(img, 30, 80)

v7 = cv2.Canny(img, 80, 100)
v8 = cv2.Canny(img, 50, 80)
v9 = cv2.Canny(img, 30, 50)

titles = ['80, 150', '50, 150', '30, 150', '80, 120', '50, 100', '30, 80', '80, 100', '50, 80', '30, 50']
images = [v1, v2, v3, v4, v5, v6, v7, v8, v9]
s = [[1, 1], [1, 2], [2, 2], [2, 2], [2, 3], [2, 3], [2, 4], [2, 4], [3, 3]]
for i in range(len(images)):
    row, col = s[len(images)-1]
    plt.subplot(row, col, i+1)
    plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述

轮廓

cv2.findContour(img, mode, method)
mode:轮廓检索模式
	RETR_EXTERNAL : 只检索最外面的轮廓
	RETR_LIST :检索所有轮廓并保存到链表
	RETR_CCOMP :检索所有轮廓,并将他们组织为两层,顶层是各部分的外部边界,第二层是空洞的边界
	RETR_TREE :检索所有轮廓,并重构嵌套轮廓的整个层次

method :轮廓逼近方法
	CHAIN_APPROX_NONE : 以 Freeman 连链码的方式输出轮廓,所有其他方法输出多边形(顶点顺序)
	CHAIN_APPROC_SIMPLE : 保留角点,去掉线
img = cv2.imread('5.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2) # -1 所有的轮廓,(0, 0, 255) BGR 红色,2 线条宽度
cv_show('res', res)

-1所有轮廓

0 只有一个轮廓

1

在这里插入图片描述

轮廓特征

cnt = contours[0]
cv2.contourArea(cnt)
cv2.arcLength(cnt, True)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值