一开始是直接看的官方文档,然后再看的是TCCP上的openCV教程
推荐还是先看官方文档https://docs.opencv.org/3.4.1/d6/d00/tutorial_py_root.html
1.Getting Started with Images
首先是如何读取一张图片
import numpy as np import cv2 as cv # Load an color image in grayscale img = cv.imread('mywife.jpg',-1) cv.imshow('image',img) cv.waitKey(0)
#需要保存的话cv.imwrite(filename,img),需要指定格式 cv.destroyAllWindows()
imread():中可以指定,-1,0,1分别代表彩色图,灰度图,加载图片alpha通道
waitKey(n):代表等待n毫秒,如果传递0,它将无限期地等待击键。还可以将其设置为检测特定的按键,例如是否按下了按键q或者esc。
destroyAllWindows():销毁所有窗口
比如说你可以这样来设置waitKey() 这样将在你按下esc(ASCLL)后关闭,按下s键后保存
import numpy as np import cv2 as cv img = cv.imread('mywife.jpg',0) cv.imshow('image',img) k = cv.waitKey(0) if k == 27: # wait for ESC key to exit cv.destroyAllWindows() elif k == ord('s'): # wait for 's' key to save and exit cv.imwrite('mywife.png',img)#同名但格式不同不会覆盖 cv.destroyAllWindows()
--用matplotlib展示图像
import numpy as np import cv2 as cv from matplotlib import pyplot as plt img = cv.imread('mywife.jpg',1) plt.imshow(img) plt.show()
结果会很奇怪,颜色明显有问题
查阅后:openCV默认是BGR颜色通道,matplolib默认是RGB通道,所以需要通道转化
img = cv.cvtColor(img,cv.COLOR_BGR2RGB)
比如我们现在来print(img)对比一下,可以发现的确是应为通道不一致
2.视频读取和摄像头调用
--先来调用一下摄像头吧
import numpy as np import cv2 as cv cap = cv.VideoCapture(0)#创建一个videoCapture对象0代表第一台设备(支持多设备) while(True): # Capture frame-by-frame ret, frame = cap.read()
#cap.read()返回一个bool变量,来判断是否读取成功,可以用cap.isOpened()来判断 # Our operations on the frame come here cv.imshow('frame',frame) #cv.imwrite('frame.jpg',frame)#保存最后的画面图片 if cv.waitKey(1) & 0xFF == ord('q'):#q键退出 break # When everything done, release the capture cap.release()#释放 cv.destroyAllWindows()
运行后会调用电脑的摄像头,如果没有摄像头或者摄像头权限关闭的话,程序会报错
如果要保存这一段视频的话,需要将主体代码修改为
fourcc = cv.VideoWriter_fourcc(*'XVID')
#fourcc:是用于指定视频编解码器的4字节代码。可用代码列表可在fourcc.org中找到。它取决于平台。遵循编解码器对视频来说效果较好。用XVID就行了 out = cv.VideoWriter('outvideo.avi',fourcc,30,(640,480)) while(cap.isOpened()): ret , frame = cap.read() if ret == True: #frame = cv.flip(frame,0)用于将图像翻转 out.write(frame) cv.imshow("frame",frame) if cv.waitKey(1) &0xFF == ord('q'): break else: break
--读取一个视频
import numpy as np import cv2 as cv cap = cv.VideoCapture('1.mp4') while(cap.isOpened()): ret, frame = cap.read() #gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY) cv.imshow('frame',frame) if cv.waitKey(1) & 0xFF == ord('q'): break cap.release() cv.destroyAllWindows()
这里wiatKey(n)中n值越大视频播放的速度越慢
提醒一下:这里如果格式或者文件名字指定错误,不会报错,而是直接运行结束
3.图像平滑和阈值
首先理解一下什么叫阈值:当像素值高于阈值时,我们给这个像素赋予一个新值,否则给他赋予另一个值。
比如这样,左边是原始图像右边是进行阈值处理的,黑和白进行了反转
这里threshold(img, threshold, maxval,type)
img:处理的图像
threshold:设置的阈值(下中的127)
maxval:是当灰度值大于(或小于)阈值时将该灰度值赋成的值(下中的255)
type:处理方法
import numpy as np import cv2 as cv from matplotlib import pyplot as plt img = cv.imread('circle.jpg',1) ret , thresh= cv.threshold(img,127,255,cv.THRESH_BINARY_INV) images = np.hstack((img,thresh)) plt.imshow(images) plt.show()
这只是一种方法,阈值处理一共有6种,这里全部展示出来,含义看注解和图像就可以理解
import numpy as np import cv2 as cv from matplotlib import pyplot as plt img = cv.imread('color.jpg',1) ret,thres1 = cv.threshold(img,127,255,cv.THRESH_BINARY)#超过阈值的取max值,否在取0 ret,thres2 = cv.threshold(img,127,255,cv.THRESH_BINARY_INV)#BINARY的反转即超过阈值取0否在max ret,thres3 = cv.threshold(img,127,255,cv.THRESH_TRUNC)#大于阈值的设置为阈值,其他不变 ret,thres4 = cv.threshold(img,127,255,cv.THRESH_TOZERO)#大于阈值的不变,其余为0 ret,thres5 = cv.threshold(img,127,255,cv.THRESH_TOZERO_INV)#反TOZERO title = ["original","BINARY","BINRAY_INV","TRUNC","TOZERO","TOZERO_INV"] images = [img,thres1,thres2,thres3,thres4,thres5] for i in range(6): plt.subplot(2,3,i+1) plt.title(title[i]) plt.imshow(images[i],"gray") plt.axis("off") plt.show()
接下来做图像平滑处理,原理可以看这篇文档
例如均值滤波的原理就是用一个3x3的卷积核去和图像相乘,然后做均值处理
import numpy as np import cv2 as cv from matplotlib import pyplot as plt img = cv.imread('lena.jpg',1) img = cv.cvtColor(img,cv.COLOR_BGR2RGB) #均值滤波 blur = cv.blur(img,(3,3)) #方框滤波 box = cv.boxFilter(img,-1,(3,3),normalize = True) #高斯滤波 gaussian = cv.GaussianBlur(img,(5,5),1) #中值滤波 middle = cv.medianBlur(img,5) res = np.hstack((img,blur,box,gaussian,middle)) plt.imshow(res) plt.show()
中值滤波是这几个里面最模糊的
4.图像的基本操作
。图像属性,以lena这张图为例
img = cv.imread('lena.jpg',1) print(img.shape) print(img.size) print(img.dtype)
输出结果分别为
(263, 263, 3)
207507
uint8
--shape值为(263,263,3)代表263行263列,3个通道数(BGR)
--size代表像素点数:这个207507 = 263 * 263 * 3
--dtype代表图像数据类型 uint8代表8位无符号整型
官网中特意提醒到:img.dtype在调试时非常重要,因为OpenCV-Python代码中的大量错误是由无效的数据类型引起的。
。分割和合并图像通道
当我们仅需要某一通道颜色时使用下面的方法
b,g,r = cv.split(img)#分别获取B,G,R img = cv.merge((b,g,r))
#或者也可以这样
b = img[:,:,0]
g = img[:,:,1]
r = img[:,:,2]
#再用cv.merge()合并
img = cv.merge((r,g,b))
官方又给了一个warning:cv.split()是一项昂贵的操作(就时间而言)。因此,仅在需要时才这样做。否则请进行Numpy索引。
--图像边框填充
import cv2 as cv import numpy as np from matplotlib import pyplot as plt BLUE = [255,0,0] img1 = cv.imread('lena.jpg') replicate = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REPLICATE) reflect = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT) reflect101 = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT_101) wrap = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_WRAP) constant= cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_CONSTANT,value=BLUE) 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()
cv.copyMakeBorder()这个函数的参数:src,top,bottom,left,right, bordertype
src指定图像,后面4个代表各个方向上填充的边框宽度,bordertype指定填充类型
cv.BORDER_REFLECT-边框将是边框元素的镜像,如下所示:fedcba | abcdefgh | hgfedcb
cv.BORDER_REFLECT_101或cv.BORDER_DEFAULT-与上述相同,但略有变化,例如:gfedcb | abcdefgh | gfedcba
cv.BORDER_REPLICATE-最后一个元素被复制,像这样:aaaaaa | abcdefgh | hhhhhhh 相当于再重复
cv.BORDER_WRAP-它看起来像这样: cdefgh|abcdefgh|abcdefg, 大概可以近似理解为左边界当右填充,右边界当左填充
cv.BORDER_CONSTANT:以常量填充,就最后那个样子