opencv-python使用
.jpg 格式为有损格式,若图像array保存为 .jpg 格式,再读入时,array内容和保存前的会又误差;若需要精准数据,使用.png的无损保存格式。
1. 基本处理函数
0)
img = cv2.imread(img_path)
height, widtdh, channels = img.shape # rows, cols
cv2.imwrite(img_path, img_array) # img_path shouldn't contain 中文
* cv2.imread读入的对象的通道顺序为BGR,图像文件中是有标注通道的,所以知道哪个是R、G、B通道,cv2读入是进行转换为BGR即可。
* cv2.imwrite则是将当前 array 的三个通道分别视为B、G、R通道,保存。array中只是数据,并不能标记r、g、b通达,需要代码处理好。
参考博客中 “读取bgr格式图片为bgr格式读入;读取rgb格式图片为rgb格式读入” 错误,应该是src.jpg是正确读入了(进行了BGR转换),而src_rgb.jpg中的R、G、B在保存时分别被视为B、G、R通道,再用cv2读入时无需转换通道,即读入后array中的通道B、G、R分别对应src.jpg中的R、G、B,所以图片展示效果不一样。
* 若图片路径中包含中文,不便修改,可以用如下方法读写: ——参考博客
import cv2 import numpy as np file_path = '中文.jpg' img = cv2.imdecode(np.fromfile(file_path, dtype=np.uint8), -1) # read cv2.imencode('.jpg', img )[1].tofile(file_path) # write
1)cv2.waitKey(t) #等待t ms后继续执行,t=0则无限等待,返回值为键盘输入的键值的ASCII值
...
input = cv2.waitKey(0) # input is ASCII value of key
...
cv2.waitKey(0) # will not stop waitting
...
2)灰度转换
img = cv2.imread('xx.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img_rgb = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
* 问题:灰度图抓BGR三通道彩色图时遇到问题:VScn::contains(scn) && VDcn::contains(dcn) && VDepth::contains(depth) in function 'cv::CvtHelper<struct cv::Set<1,-1,-1>,struct cv::Set<3,4,-1>,struct cv::Set<0,2,5>,2>::CvtHelper'
具体来讲是图像的深度不受支持,根据GitHub上的回答,opencv只将[0, 1]范围内的值视为float类型,而前面BGR2GRAY后,灰度图的范围是[0, 255],会被视为整数,但它要处理float类型的,解决办法为转换为uint8类型:
img = img.astype('uint8')
3)二值化/阈值化 ——功能解析参考opencv和opencv解析
ret,thresh = cv2.threshold(img,127,255,cv2.THRESH_BINARY) # (img, threshold, max_value, mode)
4) resize
img = cv2.resize(img, (400, 500)) # (img, (width, height))
* 将图像转换为目标大小的一种方法 (h, w ——> height, width)
先通过加黑边的方式把图像的纵横比调整为目标大小的纵横比,再resize到目标大小,可以保持图像内容不变形。非精准变换,可能会有轻微的形变。
def resize(input_img, height, width): h, w, _ = input_img.shape t, b, l, r = 0, 0, 0, 0 if h/w < height/width: # it's short in h add = w*height/width - h t = add//2 b = add-t else: # it's short in w add = h*width/height - w l = add//2 r = add-l # add boder to keep the same ratio of w and h with target (width and height) input_img = cv2.copyMakeBorder(input_img, int(t), int(b), int(l), int(r), cv2.BORDER_CONSTANT) # add black boder return cv2.resize(input_img, (width, height))
5)图像边界扩展 ——增强结果参考博客
a = cv2.copyMakeBorder(img,50,50,50,50, cv2.BORDER_REPLICATE) # 将原边界上的像素向外平行复制50个像素的距离,相当于边界上像素的拉伸,形如:A..... a = cv2.copyMakeBorder(img,50,50,50,50, cv2.BORDER_REFLECT) # 以原边界为轴,分别将四条边内的50个像素内的内容翻折出去,形如: q|p a = cv2.copyMakeBorder(img,50,50,50,50, cv2.BORDER_CONSTANT,value=[0,255,0]) # 在四条边外个添加50个像素宽的内容,添加的为值为value的像素
6)翻转与旋转
def flip(src, flipCode, dst=None),flipCode: 0- > 上下翻转,大于0 -> 左右翻转,小于0 -> 上下+左右翻转
i_flip = cv2.flip(img, 0)
def rotate(src, rotateCode, dst=None),顺时针旋转,rotateCode有90°,180°,270°三种可选
lp1 = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE) # 90 lp2 = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE) # 270(即-90) lp3 = cv2.rotate(img, cv2.ROTATE_180) # 180
2. opencv读取的图片不管是视频帧还是图片都是矩阵形式,即np.array,要转PIL.Image格式用PIL.Image.fromarray()函数,参见:cv2和PIL图片的颜色通道
3.以下是opencv-python可以获取视频的相关信息,可以通过从0开始的序号获取
0 CV_CAP_PROP_POS_MSEC 视频文件的当前位置(以毫秒为单位)或视频捕获时间戳。
1 CV_CAP_PROP_POS_FRAMES 接下来要解码/捕获的帧的基于0的索引
2 CV_CAP_PROP_POS_AVI_RATIO 视频文件的相对位置:0 - 电影的开始,1 - 电影的结尾。
3 CV_CAP_PROP_FRAME_WIDTH 视频流中帧的宽度
4 CV_CAP_PROP_FRAME_HEIGHT 视频流中帧的高度
5 CV_CAP_PROP_FPS 帧速率
6 CV_CAP_PROP_FOURCC 编解码器的4字符代码
7 CV_CAP_PROP_FRAME_COUNT 视频文件中的帧数
8 CV_CAP_PROP_FORMAT 返回的Mat对象的格式 retrieve()
9 CV_CAP_PROP_MODE 指示当前捕获模式的特定于后端的值
10 CV_CAP_PROP_BRIGHTNESS 图像的亮度(仅适用于相机)
11 CV_CAP_PROP_CONTRAST 图像对比度(仅适用于相机)
12 CV_CAP_PROP_SATURATION 图像的饱和度(仅适用于相机)
13 CV_CAP_PROP_HUE 图像的色调(仅适用于相机)
14 CV_CAP_PROP_GAIN 图像的增益(仅适用于相机)
15 CV_CAP_PROP_EXPOSURE 曝光(仅适用于相机)
16 CV_CAP_PROP_CONVERT_RGB 布尔标志,指示是否应将图像转换为RGB
17 CV_CAP_PROP_WHITE_BALANCE_U 白平衡设置的U值(注意:目前仅支持DC1394 v 2.x后端)
18 CV_CAP_PROP_WHITE_BALANCE_V 白平衡设置的V值(注意:目前仅支持DC1394 v 2.x后端)
19 CV_CAP_PROP_RECTIFICATION 立体摄像机的整流标志(注意:目前仅支持DC1394 v 2.x后端)
20 CV_CAP_PROP_ISO_SPEED 摄像机 的ISO速度(注意:目前仅支持DC1394 v 2.x后端)
21 CV_CAP_PROP_BUFFERSIZE 存储在内部缓冲存储器中的帧数(注意:目前仅支持DC1394 v 2.x后端)
如视频时长 = cap.get(7)/cap.get(5),单位为s
原文链接
4. 有的函数处理后,像素值范围在0-1,直接用cv2保存会以0-255的范围进行map,显得一片黑,可以用normalize——参考博客
img = cv2.normalize(img, img, 0, 255, cv2.NORM_MINMAX)
img = cv2.convertScaleAbs(img)
5. 经典的图像处理功能函数
1)滤波函数 ——参考博客
import cv2 img = cv2.imread('cat.jpg') img_mean = cv2.blur(img, (5, 5)) # 均值滤波,滤波核为(5,5) img_Guassian = cv2.GaussianBlur(img,(5,5),0) # 高斯滤波 img_median = cv2.medianBlur(img, 5) # 中值滤波 img_bilater = cv2.bilateralFilter(img,9,75,75) # 双边滤波
2)膨胀与腐蚀
kernel = np.ones((5, 5), np.uint8) # 设置卷积核5*5 erosion = cv2.erode(src, kernel) # 腐蚀,默认迭代次数 dst = cv2.dilate(erosion, kernel) # 膨胀
开操作 = 腐蚀 + 膨胀,断开小间隔,消除突出物,使轮廓更光滑
闭操作 = 膨胀 + 腐蚀,填充小间隔,小空洞,断裂线,使轮廓更光滑
iopen = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) # 开 iclose = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel) # 闭 top_hat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel) # 顶帽,突出图像中比周围亮的部分 black_hat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel) # 黑帽,突出图像中比周围暗的部分 gradient = cv2.morphologyEx(img, cv2.MORPH_GRADENT, kernel) # 形态学梯度
* 基本梯度:形态学梯度,dst-erosion,拟合边界; 内部梯度:img-erosion,拟合内轮廓; 外部梯度:dst-img,拟合外轮廓。
4)边缘算子
# sobel horizontal = cv2.Sobel(gray,0, 1,0, cv2.CV_64F) # 垂直边缘 vertical = cv2.Sobel(gray,0, 0,1, cv2.CV_64F) # 水平边缘 # laplacian lappy = cv2.Laplacian(gray, cv2.CV_64F) # # canny canny=cv2.Canny(gray, 40, 140) # Canny算子的上下灰度阈值分别取140,40
4. 视频处理 —— 另一篇博文