OpenCV

基本操作

创建图像

新建

  • 灰度图等价于numpy的二维矩阵 注意dtype应为np.unit8
    img = np.zeros((720,1280), dtype=np.uint8)
  • 彩色图像默认通道顺序为BGR,numpy三维矩阵
    img = np.zeros((720,1280,3), dtype=np.uint8)

读取

读取图像

  • 参数cv2.IMREAD_GRAYSCALE读取为灰度,不带参数默认读取为BGR图像
    img = cv2.imread("./mask.png", cv2.IMREAD_GRAYSCALE)
  • 获取彩色图像的长宽:
    h, w = img.shape[:2]

读取视频并逐帧访问

  • 读入视频vidcap = cv2.VideoCapture('source.mp4')
  • 逐帧访问success,image = vidcap.read()
  • 参考
    import cv2
    vidcap = cv2.VideoCapture('source.mp4')
    success,image = vidcap.read()
    count = 0
    while success:
      cv2.imwrite("frame%d.png" % count, image)     # save frame as JPEG file      
      success,image = vidcap.read()
      print('Read a new frame: ', success)
      count += 1

写入

写入图片

cv2.imwrite(filename, img)

颜色空间/数据格式

默认数据类型

  • OpenCV默认的彩色图像三个通道依次为B、G、R
    • 青色:(255, 255, 0)
    • 黄色:(0, 255, 255)
    • 紫色:(255, 0, 255)
  • 灰度转RGB 转换时将会直接将一个通道的数值复制三份
    img2 = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
  • 转HSV色彩空间 从BGR色彩空间转换为HSV,并取出某个特定通道。H:hue色调,S:saturation饱和度,V:value明度
    hsv = cv2.cvtColor(self.img, cv2.COLOR_BGR2HSV)
    h = hsv[:,:,0]
    s = hsv[:,:,1]
    v = hsv[:,:,2]

与其它包所使用的数据类型相互转换

skimage与OpenCV image的互相转换
  • skimage转OpenCV image分为两个步骤:
    1. skimage的mask可能是numpy.bool_类型的,先将其转换为数值,转换方式为
      mask = np.where(sk_imge==True, 255, 0)
      同理处理mask时可以将其它值替换为0/1
    2. np.where转换后数据类型为numpy.int32,使用img.astype(np.uint8)转换为OpenCV的图像数据类型
与Matplotlib或者标准RGB格式的之间的转换
  • 色彩空间的转换:cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

显示图像

  • 显示图像可以用imshow('title', img)

  • 使用Matplotlib

    • 需将BGR格式转为RGB格式,参考
    • 灰度图像以灰色而不是伪彩色显示
    plt.imshow(img, cmap='Greys_r', interpolation='nearest')
  • 鼠标悬浮在像素上时显示对应点的值(使用Matplotlib):

import matplotlib.pyplot as plt
 
plt.imshow(masked_image)
plt.show()
  • 显示一张图片并等待ESC键退出
def display_img(img):
    cv2.imshow('image', img)
    show_window = True
    while show_window:
        k = cv2.waitKey(0) & 0xFF
        if k == 27:#ESC
            cv2.destroyAllWindows()
            show_window = False
  • 持续显示(视频)
while True:
    ## get image here
    cv2.imshow('image', img)
    if cv2.waitKey(25) & 0xFF == 27:
        break

缩放图像

  • 使用cv2.resize()
cropped_img = cv2.resize(img[y1:y2,x1:x2], (640,480))
  • OpenCV和Pillow对图像进行resize的算法不同,会导致结果差异:参考1参考2

裁剪图像、将处理后的ROI放回原图像

  • 直接通过numpy矩阵进行操作
img_range = [[x1,y1],[x2,y2]]
roi = img[img_range[0][1]:img_range[1][1], img_range[0][0]:img_range[1][0], :]
roi_updated = YOUR_CV_FUNC(roi)
img_update = copy.deepcopy(img)
img_update[img_range[0][1]:img_range[1][1], img_range[0][0]:img_range[1][0], :] = roi_updated

拼接图像

  • 直接通过numpy矩阵进行操作
  • 水平方向拼接
hori = np.concatenate((img1, img2), axis=1)
  • 竖直方向拼接
verti = np.concatenate((img1, img2), axis=0)

直方图

  • 注意对一个numpy矩阵求最值时返回的类型将为<class 'numpy.uint16'>或者是numpy的浮点数类型,需进行类型转换后再作为calcHist的参数
x_max = int(img.max())
 
hist = cv2.calcHist([img],[0],None,[x_max],[0,x_max])
y_max = int(hist[1:,].max())
 
plt.plot(hist[1:,])
plt.xlim([0,x_max])
plt.ylim([0,y_max])
plt.show()

用矩阵进行图像的旋转拉伸位移与点的变换

  • 得到一个旋转角度(单位为度)以及旋转的中心-> 得到变换矩阵 -> 调用warpAffine进行旋转
rotate_matrix = cv2.getRotationMatrix2D(center=center, angle=angle, scale=1)
rotated_image = cv2.warpAffine(src=img, M=rotate_matrix, dsize=(width, height))
  • 找到点在新的空间中的投射 np.dot(a,b)a.dot(b)的结果是一样的
r_mat = cv2.getRotationMatrix2D((100/2, 300/2),-30,1)
 
# points
points = np.array([[35.,  0.],
                   [175., 0.],
                   [105., 200.],
                   [105., 215.],
                  ])
# add ones
ones = np.ones(shape=(len(points), 1))
points_ones = np.hstack([points, ones])
 
# transform points
transformed_points = np.dot(r_mat, points_ones.T).T