2022-12 opencv教程 task5

17 鼠标操作与响应

鼠标事件与回调

cv.setMouseCallback(winname,onMouse,userdata)
- winname 监听鼠标事件的窗口
- onMouse 响应函数,即当鼠标事件触发时调用的函数
- userdata 默认0

typedef void(* cv::MouseCallback) (int event, int x, int y, int flags, void \*userdata)

  • EVENT_LBUTTONDOWN 鼠标左键按下

  • EVENT_MOUSEMOVE 鼠标移动

  • EVENT_LBUTTONUP 鼠标左键弹起

  • 以上是三个非常重要的鼠标事件

  • EVENT_FLAG_LBUTTON 1 按住左键拖拽

  • EVENT_FLAG_RBUTTON 2 按住右键拖拽

  • EVENT_FLAG_MBUTTON 4 按住中键拖拽

鼠标操作

  • 回调函数参数 int event, int x, int y, int flags, void *userdata
    - event 鼠标事件
    - (x, y) 当前鼠标位置
    - flags 鼠标状态
    - userdata 回调用户数据,可以为空
  • 鼠标响应简单来说就是当鼠标位于对应的图像窗口内时,时刻检测鼠标状态,当鼠标状态发生改变时调用回调函数,根据回调函数中的判断逻辑选择执行相应的操作。
import cv2 as cv
import numpy as np

x1 = -1
x2 = -1 #定义矩形左上角坐标
y1 = -1
y2 = -1 #定义矩形右下角坐标

b1 = cv.imread("starry_night.jpg");
img = np.copy(b1)

def mouse_drawing(event, x, y, flags, param):
    global x1, y1,x2, y2
    if event == cv.EVENT_LBUTTONDOWN: #一旦鼠标左键按下,获取第一个坐标
        x1 = x
        y1 = y
    if event == cv.EVENT_MOUSEMOVE:
        if x1 < 0 or y1 < 0: #左键没有按下
            return;
        x2 = x
        y2 = y #右下角坐标赋值
        dx = x2 - x1
        dy = y2 - y1
        if dx > 0 and dy > 0: #确认左上角和右下角不是同一个点
            b1[:,:,:] = img[:,:,:] #将复制的图赋给原图,这样保证上次的画图痕迹被擦除
            cv.rectangle(b1, (x1, y1), (x2,y2), (255, 0,0), 2, 8, 0) #绘制矩形
        if event == cv.EVENT_LBUTTONUP: #最后左键抬起,绘制结束
            x2 = x
            y2 = y
            dx = abs(x2 - x1)
            dy = abs(y2 - y1)
            if dx > 0 and dy > 0:
                b1[:,:,:] = img[:,:,:] #将复制的图赋给原图,这样保证上次的画图痕迹被擦除
                cv.rectangle(b1, (x1, y1), (x2,y2), (255, 0,0), 2, 8, 0) #绘制矩形
            x1 = -1
            y1 = -1
            x2 = -1
            y2 = -1 #最后完全重置,开启下一次

def mouse_demo():
    cv.namedWindow("mouse_demo", cv.WINDOW_AUTOSIZE)
    cv.setMouseCallback("mouse_demo", mouse_drawing)
    while True:
        cv.imshow("mouse_demo", b1)
        c = cv.waitKey(10)
        if c == 27:
            break;
    cv.destroyAllWindows()
    
if __name__ == '__main__':
    mouse_demo()

18 图像像素类型转换与归一化

  • 图像归一化就是把需要处理的像素数据经过归一化处理后即通过某些算法,将这些数据限制在一定范围的之内。
  • 数据归一化的作用是为了后面数据处理的方便,其次是保证程序运行时收敛加快。
  • 归一化的具体作用是归纳统一样本的统计分布性。归一化在0-1之间是统计的概率分布,归一化在某个区间上是统计的坐标分布。
  • 归一化的目的,是使得没有可比性的数据变得具有可比性,同时又保持相比较的两个数据之间的相对关系,如大小关系;或是为了作图,原来很难在一张图上作出来,归一化后就可以很方便的给出图上的相对位置等。

四种归一化方法支持

  • NORM_MINMAX 根据 delta = max-min 用原始像素值减去最小值除以delta即为原始像素值归一化后的值
  • NORM_INF 根据最大值 用原始像素值除以所有原始像素值中的最大值即为原始像素值归一化后的值
  • NORM_L1 依据和为1 用原始像素值除以所有像素值之和即为原始像素值归一化后的值
  • NORM_L2 依据单位向量为1 用原始像素值除以所有原始像素值平方值之和的平方根即为原始像素值归一化后的值
  • 最常用 NORM_MINMAX
  • NORM_L1与NOEM_L2范数
  • 总的来说,norm 的各种算法得出的最终产物都会是一个数,然后要归一的对象都来除以这个数,得到的最后结果才是归一之后的结果。也就是说 norm (范式)就是那个要被除以的数

归一化函数

cv.normalize(src, dst[, alpha[, beta[, norm_type[, dtype[, mask]]]]])->dst
- src 输入图像,dst 输出图像
- alpha beta默认是1,0,是归一化的区间值(alpha是NORM_MINMAX时候低值,beta是NORM_MINMAX高值)
- norm_type默认是NORM_L2(只有alpha)
- norm_type常用是NORM_MINMAX

  • dtype = -1,默认类型与src一致
  • mask默认为空

数据转换

  • imread读入默认是uint8,转换为float32,通过imshow显示之前。必须归一化到[0~1]之间
import cv2 as cv
import numpy as np

img = cv.imread("starry_night.jpg");
print(img.dtype)
cv.imshow("img",img)
img_f32 = np.float32(img)
cv.imshow("img_f32",img_f32)
cv.normalize(img_f32, img_f32,1,0,cv.NORM_MINMAX)
cv.imshow("morn_f32",img_f32)
cv.waitKey(0)
cv.destroyAllWindows()

19 图像几何变换

几何变换-函数支持

仿射变换
cv.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]] ) -> dst
- 一般先构建变换矩阵,然后用仿射函数cv2.warpAffine()进行变换

  • dst_(x,y) = src( M_{11} x + M_{12} y + M_{13} ,$M_{21}$ x + M_{22} y + M_{23} )
    - src 输入图像
    - M 表示 2x3 变换矩阵
    - dsize 表示目标图像 dst 的大小
    - flags 插值方法的组合 int类型,默认为 cv2.INTER_LINEAR 线性插值
    • cv2.INTER_NEAREST 最近邻插值
    • cv2.INTER_AREA 区域插值
    • cv2.INTER_CUBIC 三次样条插值
    • cv2.INTER_LANCZOS4 Lanczos插值
      - borderMode 边界像素模式 int类型
      - borderValue 边界填充值,默认为0,填充黑色
      - 支持平移变换、放缩变换、旋转变换

平移变换

  • 构造移动矩阵 - 改变 截距b,即 M_{13} M_{23}
  • 再获取行和列,即高,宽

放缩变换

`cv2.resize(src, dsize=None, fx, fy, interpolation)``
- src:原图
- dsize:输出尺寸,与比例因子二选一
- fx::沿水平轴的比例因子
- fy:沿垂直轴的比例因子
- interpolation: 插值方法

  • cv2.INTER_NEAREST(最近邻插值)
  • cv2.INTER_AREA (区域插值)
  • cv2.INTER_CUBIC(三次样条插值)
  • cv2.INTER_LANCZOS4(Lanczos插值)

旋转变换

  • 旋转矩阵

    屏幕坐标跟笛卡尔坐标,中心位置的差异(0, 0)=(cx, cy)

获取旋转矩阵

  • 旋转矩阵获取 cv.getRotationMatrix2D
    - center 旋转中心
    - angle 度数
    - scale 缩放比例, >0 逆时针旋转,scale 放缩尺度大小

翻转与特殊角度旋转

cv.flip(src, flipCode[, dst])->dst
cv.rotate(src, rotateCode[, dst])->dst
- src 输入图像
- flipCode支持0水平、1垂直、-1对角线翻转
- rotateCode支持旋转 90^0, 180^0, 270^0

仿射变换

仿射变化需要一个M矩阵进行变换,但由于仿射变换比较复杂,一般直接找很难找到这个矩阵,因此cv2通过利用3个点前后变换的关系,使得图像完成平移、旋转、缩放、剪切、反射的变换。

cv2.getAffineTransform(pos1, pos2)
- pos1: 变换前的位置
- pos2: 变换后的位置

import cv2 as cv
import numpy as np

img = cv.imread("starry_night.jpg");
cv.imshow("original", img)
h,w = img.shape[:2]
cx = int(w/2)
cy = int(h/2)

M = np.float32([[.7, 0, 0], [0, .7, 0]]) #构造变换矩阵2x3 缩放0.7
dst = cv.warpAffine(img, M, (int(w*.7), int(h*.7)))
cv.imshow("rescaled", dst)

cv.waitKey(0)
cv.destroyAllWindows()

import cv2 as cv
import numpy as np

img = cv.imread("starry_night.jpg");
cv.imshow("original", img)
h,w = img.shape[:2]
cx = int(w/2)
cy = int(h/2)

#获取旋转矩阵,degree > 0 逆时针转,原点在左上角
M = cv.getRotationMatrix2D((w/2, h/2), 45.0, 1.0)
dst = cv.warpAffine(img, M, (w, h))
cv.imshow("rotated", dst)

dst = cv.flip(img, 0)
cv.imshow("flipped", dst)

cv.waitKey(0)
cv.destroyAllWindows()

20 视频读写处理

视频标准与格式

  • SD Standard Definition 标清480P
  • HD High Definition 高清720P/1080P
  • UHD Ultra High Definition 超高清 4K/2160P
  • 分辨率表示
  • SD - 640x480,704x480,720x480,848x480等
  • HD - 960x720,1280x720,1440x1080,1920x1080
  • UHD - 4K,2160P

视频读取函数


- filename 视频文件
- index USB摄像头/web camera的索引
- apiPreference = CAP_ANY 意思自动决定第三方视频库,如: cv.CAP_FFMPEG,cv.CAP_DSHOW

查询视频属性

  • VideoCaput的get方法
  • cv.CAP_PROP_FRAME_WIDT
  • cv.CAP_PROP_FRAME_HEIGHT
  • cv.CAP_PROP_FPS
  • cv.CAP_PROP_FOURCC
  • cv.CAP_PROP_FRAME_COUNT

视频文件保存

 cv.VideoWriter(
	 filename,  #保存文件名称
	 fourcc,    #编码方式
	 fps,       #帧率
	 frameSize, #视频帧大小,与实现大小相符
	 [, isColor]
 ) -> <VideoWriter object>
浙ICP备19012682号