OpenCV 视觉编程

本文最后更新于:3 个月前

opencv基本信息opencv 实战

图像处理的基础


Chapter0 注意事项

  • opencv的图像是 先宽度 再高度,这点是与numpy不同的
    • img.shape[0:2] # 0可省略,返回图像的宽和高(长和宽)
    • img.shape[0:3] # 包括通道数一起返回,要3个参数接收
  • imread 的图像路径如果包含中文会有bug(可能是win特供, 在ubuntu下可以),因此可以使用imdecode 来代替
  • resize 要慎用,因为插值的方法不一定能保证图片前后像素的一致性(除非等倍放缩)

图像裁剪「👷‍♀️中」https://blog.csdn.net/hfutdog/article/details/82351549

Chapter1 基本图像操作

1.1 图像的基本I/O操作

  • 注意waitKey() 有返回值,其值是16位int形式的ASCII码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import cv2
import numpy as np

# 这是一个展示图片的函数,之后都会调用它来精简代码。 {name} 中填图片路径即可
def cv_show(name):
img = cv2.imread(name) # 读入是可以添加其他选项的
while True:
cv2.imshow(name, img)
key = cv2.waitKey(10)
if key & 0xFF == ord("q"):
break

# 生成窗口的函数
cv2.namedWindow("video", cv2.WINDOW_NORMAL)
cv2.resizeWindow("video", 640, 800)


cv_show("niya.png") # 直接填图片路径

1.2 视频I/O

1.2.1视频(调用摄像头来输入)

1
2
3
4
5
6
7
8
# 摄像头输入
cap = cv2.VideoCapture(0) # 默认为摄像头0
while cap.isOpened():
ret, frame = cap.read()
if not ret: #没捕捉到画面,就离开
break
cv_show('video', frame) #对每一帧调用cv_show
cap.release()

1.2.2将鼠标引入

1
2
3
4
5
6
7
# event 指鼠标事件,x,y为坐标,flags为组合按键
def mouse_callback(event, x, y, flags, userdata):
print(event, x, y, flags, userdata)
if event == 2: # 右键退出
cv2.destroyAllWindows()

cv2.setMouseCallback("窗口名", mouse_callback, "")

1.3 C++中的Mat在python接口处的转化

Mat是OpenCV C++中的数据结构,在python中被转化为 numpy的ndarray

  • Mat 由header + data构成,header中记录图片的维数、大小、数据类型等
  • 利用numpy提供的深浅拷贝方法,可以实现Mat的拷贝
    • img.view() # 浅拷贝
    • img.copy() # 深拷贝
  • 访问ndarray的属性,就相当于访问Mat图像的属性
    • 包括.shape, .size, .dtype(注意uint这个格式) 等

1.4 图像通道的分类与合并

  • spilt(mat) 分割通道, merge((ch1, ch2, ch3)) 融合通道
1
2
3
4
5
6
7
8
9
10
11
b, g, r = cv2.split(img) # 先划分出来,它们会成为单独的图片

b[10:100, 10:100] = 255 # 在图像上划分出一个白色的方块(意义不明)
g[10:100, 10:100] = 255

img2 = cv2.merge((b, g, r)) # 图像合并

cv_show("b", b)
cv_show("g", g)
cv_show("r", r)
cv_show("img2", img2)

1.5图像绘制

  • line(img, pt1, pt2, color, thickness, lineType, shift) 画直线

    • img: 在哪个图像上画线
    • pt1, pt2: 开始点, 结束点. 指定线的开始与结束位置
    • color: 颜色
    • thickness: 线宽
    • lineType: 线型.线型为-1, 4, 8, 16, 默认为8
    • shift: 坐标缩放比例.
  • rectangle() 参数同上 画矩形

  • circle(img, center, radius, color[, thickness[, lineType[, shift]]]) 中括号内参数表示可选参数. 画圆

  • ellipse(img, 中心点, 长宽的一半, 角度, 从哪个角度开始, 从哪个角度结束,...)

  • polylines(img, pts, isClosed, color[, thickness[, lineType[, shift]]]) 画多边形

  • fillPoly 填充多边形

  • putText(img, text, org, fontFace, fontScale, color[, thickness[, lineType[, bottomLeftOrigin]]]) 绘制文本

    • text 要绘制的文本
    • org 文本在图片中的左下角坐标
    • fontFace 字体类型即字体
    • fontScale 字体大小
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
img = np.zeros((480, 640, 3), np.uint8)  # 创建画布(可以用numpy直接创建)

# 画线
cv2.line(img, (10, 20), (300, 400), (0, 0, 255), 5, 4)
cv2.line(img, (80, 100), (380, 480), (0, 0, 255), 5, 16)

# 画矩形
cv2.rectangle(img, (10, 10), (100, 100), (0, 0, 255), -1)

# 画圆
cv2.circle(img, (320, 240), 100, (0, 0, 255))
cv2.circle(img, (320, 240), 5, (0, 0, 255), -1)

# 画椭圆
cv2.ellipse(img, (320, 240), (100, 50), 15, 0, 360, (0, 0, 255), -1)

# 画多边形
pts = np.array([(300, 10), (150, 100), (450, 100)], np.int32)
cv2.polylines(img, [pts], True, (0, 0, 255))
# 填充多边形(上色)
cv2.fillPoly(img, [pts], (255, 255, 0))

# 写字
cv2.putText(img, "Hello OpenCV!", (10, 400), cv2.FONT_HERSHEY_TRIPLEX, 3, (255, 0, 0))
  • 结合鼠标callback的方法,我们就可以使用opencv来绘图了

Chapter2 图像的基本处理

2.1 图像基本变换

2.1.1 放大/缩小

  • resize(src, dsize[, dst[, fx [, fy[, interpolation]]]])

    • src: 要缩放的图片

    • dsize: 缩放之后的图片大小, 元组和列表表示均可.

    • dst: 可选参数, 缩放之后的输出图片

    • fx, fy: x轴和y轴的缩放比, 即宽度和高度的缩放比.

    • interpolation: 插值算法, 主要有以下几种:

      • INTER_NEAREST, 邻近插值, 速度快, 效果差.
      • INTER_LINEAR, 双线性插值, 使用原图中的4个点进行插值. 默认.
      • INTER_CUBIC, 三次插值, 原图中的16个点.
      • INTER_AREA, 区域插值, 效果最好, 计算时间最长.
1
2
3
4
dog = cv2.imread('dog.jpg')

new_dog = cv2.resize(dog, dsize=(800, 800), interpolation=cv2.INTER_NEAREST)
cv_show(new_dog)

2.1.2 旋转/翻转

  • flip(src, flipCode) # 翻转

    • flipCode = 0 表示上下翻转

    • flipCode > 0 表示左右翻转

    • flipCode < 0 上下 + 左右

  • rotate(img, rotateCode=___) # 旋转

    • ROTATE_90_CLOCKWISE 90度顺时针
    • ROTATE_180 180度
    • ROTATE_90_COUNTERCLOCKWISE 90度逆时针

2.2 图像的仿射变换

仿射变换:图像旋转、缩放、平移都可以用仿射变换来描述。其本质是 变换矩阵和图片矩阵的矩阵运算。

  • warpAffine(src, M, dsize, flags, mode, value)
    • M:变换矩阵
    • dsize: 输出图片大小
    • flag: 与resize中的插值算法一致
    • mode: 边界外推法标志
    • value: 填充边界值

2.2.1 平移矩阵

  • 矩阵中的每个像素由(x,y)组成,(x, y)表示这个像素的坐标. 假设沿x轴平移\(t_x\), 沿y轴平移\(t_y\), 那么最后得到的坐标为\((\hat x, \hat y) = (x + t_x, y + t_y)\), 用矩阵表示就是:
  • $ ( \[\begin{matrix}\hat x \\\hat y \\1\end{matrix}\] ) = ( \[\begin{matrix}1 & 0 & t_x\\0 & 1 & t_y\\0 & 0 & 1\end{matrix}\] )( \[\begin{matrix}x \\y \\1\end{matrix}\] ) $
1
2
3
h, w, ch = img.shape
M = np.float32([[1, 0, 0], [0, 1, -100]]) # 最终代码长这样
new_img = cv2.warpAffine(img, M, (w, h))

2.2.2 获取变换矩阵W (通过这个API获取你想要进行的变换的 变换矩阵W,然后调用warpAffine)

  • getRotationMatrix2D(center, angle, scale)

  • center 中心点 , 以图片的哪个点作为旋转时的中心点.

  • angle 角度: 旋转的角度, 按照逆时针旋转.

  • scale 缩放比例: 想把图片进行什么样的缩放.

1
2
M = cv2.getRotationMatrix2D((w/2, h/2), 15, 1.0)
new = cv2.warpAffine(img, M, (w, h))
  1. 按照病例来划分训练和测试集,不使用比例划分的方式,修改训练代码,不使用轮次batch喂模型
  2. 优化多边形和方形裁剪的方式,不用边缘回归了,直接图像中心裁剪后padding为224**输入模型