本文主要参考自 OpenCV官方文档
一、图像的基本操作
-
访问、修改像素值
import cv2 img = cv2.imread('../../Resources/messi15.jpg') px = img[100, 100] print(px) # 仅访问单一通道像素值 blue = img[100, 100, 0] print(blue) # 修改像素值 img[100, 100] = [255, 255, 255] print(img[100, 100]) # 更好的像素访问和编辑方法,返回标量 # 访问 RED 值 print(img.item(10, 10, 2)) # 修改RED值 img.itemset((10, 10, 2), 100) print(img.item(10, 10, 2))
-
访问图像属性
# 图像形状 print(img.shape) # 图像像素值总数 print(img.size) # 图像数据类型 print(img.dtype)
-
图像感兴趣区域ROI
使用Numpy索引获得ROI,选择球并将其复制到图像中的另一个区域:import cv2 img = cv2.imread('../../Resources/messi15.jpg') ball = img[280:340, 330:390] img[273:333, 100:160] = ball cv2.imshow('messi', img) cv2.waitKey(0) cv2.destroyAllWindows()
效果图如下:
-
为图像设置边框(了解即可)
如果要在图像周围创建边框(如相框),则可以使用 cv.copyMakeBorder() 。
其参数如下:
src
:输入图像top
,bottom
,left
,right
:边界宽度(以相应方向上的像素数为单位)borderType
:定义要添加哪种边框的标志。它可以是以下类型:cv.BORDER_CONSTANT
:添加恒定的彩色边框。该值应作为下一个参数给出。cv.BORDER_REFLECT
:边框将是边框元素的镜像,如下所示: fedcba | abcdefgh | hgfedcbcv.BORDER_REFLECT_101
或cv.BORDER_DEFAULT
与上述相同,但略有变化,例如: gfedcb | abcdefgh | gfedcbacv.BORDER_REPLICATE
:最后一个元素被复制,像这样: aaaaaa | abcdefgh | hhhhhhhcv.BORDER_WRAP
:难以解释,它看起来像这样: cdefgh | abcdefgh | abcdefgvalue
:边框的颜色,如果边框类型为cv.BORDER_CONSTANT
import cv2 from matplotlib import pyplot as plt BLUE = [255, 0, 0] img1 = cv2.imread('../../Resources/opencv-logo.jpg') replicate = cv2.copyMakeBorder(img1, 10, 10, 10, 10, cv2.BORDER_REPLICATE) reflect = cv2.copyMakeBorder(img1, 10, 10, 10, 10, cv2.BORDER_REFLECT) reflect101 = cv2.copyMakeBorder(img1, 10, 10, 10, 10, cv2.BORDER_REFLECT_101) wrap = cv2.copyMakeBorder(img1, 10, 10, 10, 10, cv2.BORDER_WRAP) constant = cv2.copyMakeBorder(img1, 10, 10, 10, 10, cv2.BORDER_CONSTANT, value=BLUE) print(img1, reflect) plt.subplot(231), plt.imshow(img1, 'gray'), plt.title('ORIGINAL') plt.subplot(232), plt.imshow(replicate, 'gray'), plt.title('REPLICATE') plt.subplot(233), plt.imshow(reflect, 'gray'), plt.title('REFLECT') plt.subplot(234), plt.imshow(reflect101, 'gray'), plt.title('REFLECT_101') plt.subplot(235), plt.imshow(wrap, 'gray'), plt.title('WRAP') plt.subplot(236), plt.imshow(constant, 'gray'), plt.title('CONSTANT') plt.show()
效果图如下(图像是采用matplotlib显示的,因此红色和蓝色通道将互换):
二、图像运算
- 图像加法
注意: OpenCV 加法和 Numpy 加法之间有区别
① OpenCV 加法是饱和运算
② 而 Numpy 加法是模运算import cv2 img1 = cv2.imread('../../Resources/3D-Matplotlib.png') img2 = cv2.imread('../../Resources/mainsvmimage.png') add = img1 + img2 # 模运算,250+10 = 260 % 256 = 4 cv_add = cv2.add(img1, img2) # 像素点值相加,所以图片变白,50+10 = 260 => 255 cv2.imshow('add', add) cv2.imshow('cv_add', cv_add) cv2.waitKey(0) cv2.destroyAllWindows()
- 图像融合
公式: d s t = s r c 1 ∗ α + s r c 2 ∗ β + γ dst = src1 * α + src2 * β + γ dst=src1∗α+src2∗β+γ
效果图如下import cv2 img1 = cv2.imread('./Image/3D-Matplotlib.png') img2 = cv2.imread('./Image/mainsvmimage.png') weighted = cv2.addWeighted(img1, 0.6, img2, 0.4, 0) # 设置权重进行叠加 cv2.imshow('weighted', weighted) cv2.waitKey(0) cv2.destroyAllWindows()
- 按位运算
① 或运算,求并集,加法:cv2.bitwise_or(img1, img2)
② 与运算,求交集,重叠部位:cv2.bitwise_and(img1, img2)
③ 非运算,求空集,取反色:cv2.bitwise_not(img1)
④ 异或运算,相同为0,不同为1:
cv2.bitwise_xor(img1, img1)
,cv2.bitwise_xor(img1, img2)
效果图如下img1 = cv2.imread('../../Resources/3D-Matplotlib.png') img2 = cv2.imread('../../Resources/mainlogo.png') rows, cols, channels = img2.shape roi = img1[0:rows, 0:cols] img2_gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) ret, mask = cv2.threshold(img2_gray, 220, 255, cv2.THRESH_BINARY_INV) mask_inv = cv2.bitwise_not(mask) img1_bg = cv2.bitwise_and(roi, roi, mask=mask_inv) img2_fg = cv2.bitwise_and(img2, img2, mask=mask) dst = cv2.add(img1_bg, img2_fg) img1[0:rows, 0:cols] = dst # cv2.imshow('img_', img2_gray) # cv2.imshow('img_1', mask) # cv2.imshow('img_2', mask_inv) # cv2.imshow('img_3', img1_bg) # cv2.imshow('img_4', img2_fg) # cv2.imshow('mask', mask) cv2.imshow('new_img', img1) cv2.waitKey(0) cv2.destroyAllWindows()
三、视频练习
- 要求:向视频中添加动态字幕、矩形…
实现的部分视频效果如下import cv2 import random import numpy as np import pandas as pd from PIL import Image, ImageDraw, ImageFont import time # 颜色 def rand_color(): font_r = random.randint(128, 255) font_g = random.randint(128, 255) font_b = random.randint(128, 255) return font_r, font_g, font_b # 矩形坐标读取 def rectangle_point(index): data = pd.read_table("coordinate.txt", sep=",", header=None) point_x, point_y = [], [] for i_ in range(len(data)): point_1 = (data[0][i_], data[1][i_]) point_2 = (data[2][i_], data[3][i_]) point_x.append(point_1) point_y.append(point_2) return point_x[index], point_y[index] # 画矩形框 def draw_rectangle(frame_, point1, point2): cv2.rectangle(frame_, point1, point2, rand_color(), random.randint(1, 2)) # 中文读取 def chinese_text(): data_1 = pd.read_table("text.txt", header=None) text_list = [] for i_ in range(len(data_1)): text_list.append(data_1[0][i_]) return text_list # 绘制中文字体 def paint_chinese(frame_, chinese, pos, color): img_ = Image.fromarray(cv2.cvtColor(frame_, cv2.COLOR_BGR2RGB)) draw = ImageDraw.Draw(img_) font = ImageFont.truetype(r'./msyh.ttc', 20, encoding='utf-8') fill_color = color # (255,0,0) position = pos # (100,100) draw.text(position, chinese, font=font, fill=fill_color) image_ = cv2.cvtColor(np.array(img_), cv2.COLOR_RGB2BGR) return image_ # 视频保存 def save_video(cap_): width_ = int(cap_.get(3)) height_ = int(cap_.get(4)) fps_ = cap.get(cv2.CAP_PROP_FPS) fourcc_ = cv2.VideoWriter_fourcc(*'mp4v') new_video = cv2.VideoWriter(r'./new_video.mp4', fourcc_, fps_, (width_, height_)) return new_video if __name__ == '__main__': start = time.time() path = r'../../Resources/cat.mp4' cap = cv2.VideoCapture(path) new_video_ = save_video(cap) fps = cap.get(cv2.CAP_PROP_FPS) total_fps = cap.get(cv2.CAP_PROP_FRAME_COUNT) current_frame = 0 while True: ret, frame = cap.read() if cv2.waitKey(int(np.ceil(total_fps / fps)) // 2) & 0xFF == ord('q'): break elif ret is False: break for i in range(len(chinese_text())): start_frame = i * (total_fps / 5) end_frame = (i + 1) * (total_fps / 5) # print(current_frame, start_frame, end_frame, rectangle_point(i)[0], rectangle_point(i)[1]) if start_frame <= current_frame <= end_frame: draw_rectangle(frame, rectangle_point(i)[0], rectangle_point(i)[1]) new_img = paint_chinese(frame, chinese_text()[i], (200, 750), rand_color()) new_video_.write(new_img) cv2.imshow('cat', new_img) if current_frame > total_fps: break current_frame += 1 cap.release() new_video_.release() cv2.destroyAllWindows() end = time.time() print(end - start)