画图:
def show(image):
plt.imshow(image)
plt.axis('off')
plt.show()
image = np.zeros((300,300,3),dtype='uint8')
画线:
green = (0,255,0)
cv2.line(image, (0,0), (300,300), green)
show(image)
画矩形:
red = (255,0,0)
cv2.rectangle(image, (10,10), (60,60), red, 2)
show(image)
画圆形:
image = np.zeros((300,300,3),dtype='uint8')
(cX, cY) = image.shape[1]//2, image.shape[0]//2
white = (255,255,255)
for r in range(0,151,15):
cv2.circle(image, (cX,cY), r, white, 2)
show(image)
image = np.zeros((300,300,3),dtype='uint8')
for i in range(10):
# 半径取值
radius = np.random.randint(5,200)
# 颜色取值
color = np.random.randint(0,255,size=(3,)).tolist()
# 圆心取值
pt = np.random.randint(0,300,size=(2,))
# 画图
cv2.circle(image, tuple(pt), radius, color, -1)
show(image)
# 水平翻转
image = cv2.flip(image,1)
# 垂直翻转
image = cv2.flip(image,0)
# 水平+垂直翻转
image = cv2.flip(image,-1)
#裁剪
image = image[0:200,50:200]
# 图像加法
print(cv2.add(np.uint8([200]),np.uint8([100])))
# 普通加法
print(np.uint8([200])+np.uint8([100]))
# 生成跟图片形状相同的并且全为100的数据
M = np.ones(image.shape, dtype='uint8')*100
# 所有的像素加100
image = cv2.add(image, M)
# 生成跟图片形状相同的并且全为100的数据
M = np.ones(image.shape, dtype='uint8')*100
# 所有的像素减100
image = cv2.subtract(image, M)
bitwise_and是对二进制数据进行“与”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“与”操作,1&1=1,1&0=0,0&1=0,0&0=0
bitwise_or是对二进制数据进行“或”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“或”操作,1|1=1,1|0=1,0|1=1,0|0=0
bitwise_xor是对二进制数据进行“异或”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“异或”操作,1^1=0,1^0=1,0^1=1,0^0=0
bitwise_not是对二进制数据进行“非”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“非”操作,~1=0,~0=1
rectangle = np.zeros((300,300,3),dtype='uint8')
white = (255,255,255)
cv2.rectangle(rectangle, (25,25), (275,275), white, -1)
show(rectangle)
circle = np.zeros((300,300,3), dtype='uint8')
cv2.circle(circle, (150,150), 150, white, -1)
show(circle)
# AND,与操作,有黑就变黑
image = cv2.bitwise_and(rectangle, circle)
# OR,或操作,有白就变白
image = cv2.bitwise_or(rectangle, circle)
show(image)
# NOT, 非操作,颜色取反
image = cv2.bitwise_not(circle)
show(image)
# 创建遮挡
mask = np.zeros(image.shape,dtype='uint8')
white = (255,255,255)
cv2.rectangle(mask, (50,50), (250,350), white, -1)
show(mask)
# 对图像遮挡
masked = cv2.bitwise_and(image, mask)
show(masked)
#切片
(R, G, B) = cv2.split(image)
# 拉普拉斯金字塔
image = imread('image.jpg')
down_image1 = cv2.pyrDown(image)
down_image2 = cv2.pyrDown(down_image1)
up_image = cv2.pyrUp(down_image2)
laplacian = down_image1-up_image
show(laplacian)
Erosion腐蚀
其原理是在原图的小区域内取局部最小值,其函数是cv2.erode()。这个核也叫结构元素,因为形态学操作其实也是应用卷积来实现的,结构元素可以是矩形/椭圆/十字形,可以用cv2.getStructuringElement()来生成不同形状的结构元素。
for i in range(3):
erosion = cv2.erode(image, kernel1, iterations=i+1)
show(erosion)
Dilation膨胀
膨胀与腐蚀相反,取的是局部最大值。cv2.dilate()
for i in range(3):
dilation = cv2.dilate(image, kernel1, iterations=i+1)
show(dilation)
Opening开运算
先腐蚀后膨胀叫开运算,其作用是消除小白点。这类形态学操作用cv2.morphologyEx()函数实现。
# 去除白点
opening = cv2.morphologyEx(image2, cv2.MORPH_OPEN, kernel1)
show(opening)
Closing闭运算
闭运算则相反:先膨胀后腐蚀。其作用是消除小黑点。
# 去除黑点
closing = cv2.morphologyEx(image2, cv2.MORPH_CLOSE, kernel1)
show(closing)
Gradient形态学梯度
膨胀图减去腐蚀图,dilation - erosion,得到物体的轮廓
gradient = cv2.morphologyEx(image, cv2.MORPH_GRADIENT, kernel1)
show(gradient)
Top Hat顶帽/White Hat白帽
原图减去开运算后的图:src - opening
tophat = cv2.morphologyEx(image2, cv2.MORPH_TOPHAT, kernel1)
show(tophat)
Black Hat黑帽
闭运算后的图减去原图:closing - src
blackhat = cv2.morphologyEx(image2, cv2.MORPH_BLACKHAT, kernel1)
show(blackhat)
Averaging平均
计算卷积框覆盖区域所有像素的平均值得到卷积的结果
[[1 1 1 1 1]
[1 1 1 1 1]
[1 1 1 1 1]
[1 1 1 1 1]
[1 1 1 1 1]]
kernelsizes = [(3,3),(9,9),(15,15)]
plt.figure(figsize=(15,15))
for i,kernel in enumerate(kernelsizes):
plt.subplot(1,3,i+1)
# 平均平滑
blur = cv2.blur(image, kernel)
# 不显示坐标
plt.axis('off')
# 设置标题
plt.title('Blurred'+str(kernel))
plt.imshow(blur)
plt.show()
Gaussian高斯模糊
现在把卷积核换成高斯核(简单来说,方框不变,将原来每个方框的值是 相等的,现在里面的值是符合高斯分布的,方框中心的值最大,其余方框根据 距离中心元素的距离递减,构成一个高斯小山包。原来的求平均数现在变成求 加权平均数,全就是方框里的值)
kernelsizes = [(3,3),(9,9),(15,15)]
plt.figure(figsize=(15,15))
for i,kernel in enumerate(kernelsizes):
plt.subplot(1,3,i+1)
# 平均平滑
blur = cv2.GaussianBlur(image, kernel, 0)
# 不显示坐标
plt.axis('off')
# 设置标题
plt.title('Blurred'+str(kernel))
plt.imshow(blur)
plt.show()
Median中值模糊¶
顾名思义就是用与卷积框对应像素的中值来替代中心像素的值。
plt.figure(figsize=(15,15))
for i,kernel in enumerate((3,9,15)):
plt.subplot(1,3,i+1)
# 平均平滑
blur = cv2.medianBlur(image, kernel)
# 不显示坐标
plt.axis('off')
# 设置标题
plt.title('Blurred'+str(kernel))
plt.imshow(blur)
plt.show()
Bilateral双边滤波
能在保持边界清晰的情况下有效的去除噪音。我们已经知道高斯滤波器是求中心点邻近区域像素的高斯加权平均值。这种高斯滤波器只考虑像素之间的空间关系,而不会考虑像素值之间的关系(像素的相似度)。所以这种方法不会考虑一个像素是否位于边界。因此边界也会别模糊掉,而这正不是我们想要。
双边滤波在同时使用空间高斯权重和灰度值相似性高斯权重。空间高斯函数确保只有邻近区域的像素对中心点有影响,灰度值相似性高斯函数确保只有与中心像素灰度值相近的才会被用来做模糊运算。所以这种方法会确保边界不会被模糊掉,因为边界处的灰度值变化比较大。
params = [(11,21,7),(11,41,21),(15,75,75)]
plt.figure(figsize=(15,15))
# 邻域直径,灰度值相似性高斯函数标准差,空间高斯函数标准差
for i,(diameter,sigmaColor,sigmaSpace) in enumerate(params):
plt.subplot(1,3,i+1)
# 平均平滑
blur = cv2.bilateralFilter(image, diameter,sigmaColor,sigmaSpace)
# 不显示坐标
plt.axis('off')
# 设置标题
plt.title('Blurred'+str((diameter,sigmaColor,sigmaSpace)))
plt.imshow(blur)
plt.show()
RGB
FAO
FAO
RGB是从颜色发光的原理来设计定的,通俗点说它的颜色混合方式就好像有红、绿、蓝三盏灯,当它们的光相互叠合的时候,色彩相混,而亮度却等于两者亮度之总和,越混合亮度越高,即加法混合。
红、绿、蓝三个颜色通道每种色各分为256阶亮度,在0时“灯”最弱——是关掉的,而在255时“灯”最亮。当三色灰度数值相同时,产生不同灰度值的灰色调,即三色灰度都为0时,是最暗的黑色调;三色灰度都为255时,是最亮的白色调。
在电脑中,RGB的所谓“多少”就是指亮度,并使用整数来表示。通常情况下,RGB各有256级亮度,用数字表示为从0、1、2...直到255。注意虽然数字最高是255,但0也是数值之一,因此共256级。
256 x 256 x 256 = 16,777,216
image = imread('image.jpg')
(R, G, B) = cv2.split(image)
zeros = np.zeros(image.shape[:2],dtype='uint8')
show(cv2.merge([R,zeros,zeros]))
show(cv2.merge([zeros,G,zeros]))
show(cv2.merge([zeros,zeros,B]))
HSV
HSV是一种比较直观的颜色模型,HSV颜色空可以更好的数字化处理颜色。这个模型中颜色的参数分别是:色调(H, Hue),饱和度(S,Saturation),明度(V, Value)。
色调H:
用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,品红为300°
饱和度S:
饱和度S表示颜色接近光谱色的程度。一种颜色,可以看成是某种光谱色与白色混合的结果。其中光谱色所占的比例愈大,颜色接近光谱色的程度就愈高,颜色的饱和度也就愈高。饱和度高,颜色则深而艳。光谱色的白光成分为0,饱和度达到最高。通常取值范围为0%~100%,值越大,颜色越饱和。
明度V:¶
明度表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关;对于物体色,此值和物体的透射比或反射比有关。通常取值范围为0%(黑)到100%(白)。
image = imread('image.jpg')
hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)
zeros = np.zeros(image.shape[:2],dtype='uint8')
for (name,chan) in zip(('H','S','V'), cv2.split(hsv)):
cv2.imshow(name,chan)
cv2.waitKey(0)
cv2.destroyAllWindows()
L*a*b*
CIE1976Lab色空间(CIE LAB 色空间),是1976年由国际照明学会(CIE)推荐的均匀色空间。Lab颜色空间用于计算机色调调整和彩色校正。该空间是三维直角坐标系统。是目前最受广用的测色系统。以明度L和色度坐标a、b来表示颜色在色空间中的位置。l表示颜色的明度,a正值表示偏红,负值表示偏绿;b*正值表示偏黄,负值表示偏蓝
L* 表示颜色的明度;
a* 正值表示红色,负值表示绿色;
b* 正值表示黄色,负值表示蓝色;
image = imread('image.jpg')
lab = cv2.cvtColor(image, cv2.COLOR_RGB2LAB)
zeros = np.zeros(image.shape[:2],dtype='uint8')
for (name,chan) in zip(('L','A','B'), cv2.split(lab)):
cv2.imshow(name,chan)
cv2.waitKey(0)
cv2.destroyAllWindows()
在图像处理中,Thresholding中文翻译过来叫二值化或者阈值化。二值化就是把图片传换成只有white和black这两种颜色。通过Thresholding,可以让图片中感兴趣的颜色变成主角--white,其余的颜色全部隐藏--black。另外,二值化后的图片也便于计算机进行分析,因为边缘轮廓十分清晰,所以计算机可以轻松找到边界线。然而,在找边界这方面,Thresholding并不是特别好的算法,有些时候遇到某些特殊图片效果也不好。
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
plt.imshow(gray,'gray')
plt.axis('off')
plt.show()
ret1,thresh1 = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
ret2,thresh2 = cv2.threshold(gray,127,255,cv2.THRESH_BINARY_INV)
ret3,thresh3 = cv2.threshold(gray,127,255,cv2.THRESH_TRUNC)
ret4,thresh4 = cv2.threshold(gray,127,255,cv2.THRESH_TOZERO)
ret5,thresh5 = cv2.threshold(gray,127,255,cv2.THRESH_TOZERO_INV)
titles = ['original','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images = [gray, thresh1, thresh2, thresh3, thresh4, thresh5]
plt.figure(figsize=(15,5))
for i in range(6):
plt.subplot(2,3,i+1)
plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.axis('off')
plt.show()
Otsu’s Method
自动选择阈值
image = imread('image/opencv_logo.png')
show(image)
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
plt.imshow(gray,'gray')
plt.axis('off')
plt.show()
ret1,thresh1 = cv2.threshold(gray,0,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)
ret2,thresh2 = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
print('ret1:',ret1)
print('ret2:',ret2)
plt.imshow(thresh1,'gray')
plt.axis('off')
plt.show()
plt.imshow(thresh1,'gray')
plt.axis('off')
plt.show()
### Adaptive Thresholding自适应阈值
在前面的部分我们使用是全局阈值,整幅图像采用同一个数作为阈值。当
时这种方法并不适应与所有情况,尤其是当同一幅图像上的不同部分的具有不
同亮度时。这种情况下我们需要采用自适应阈值。此时的阈值是根据图像上的
每一个小区域计算与其对应的阈值。因此在同一幅图像上的不同区域采用的是
不同的阈值,从而使我们能在亮度不同的情况下得到更好的结果。
Adaptive Method- 指定计算阈值的方法。
– cv2.ADPTIVE_THRESH_MEAN_C:阈值取自相邻区域的平
均值
– cv2.ADPTIVE_THRESH_GAUSSIAN_C:阈值取值相邻区域
的加权和,权重为一个高斯窗口。
• Block Size - 邻域大小(用来计算阈值的区域大小)。
• C - 这就是是一个常数,阈值就等于平均值或者加权平均值减去这个常
数。
# 变灰度图
image = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
# 中值滤波
image = cv2.medianBlur(image,5)
# 普通二值化
ret,th1 = cv2.threshold(image,127,255,cv2.THRESH_BINARY)
# 平均值阈值
th2 = cv2.adaptiveThreshold(image,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,3)
# 高斯阈值
th3 = cv2.adaptiveThreshold(image,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,3)
titles = ['original', 'Global Thresholding', 'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [image, th1, th2, th3]
plt.figure(figsize=(10,5))
for i in range(4):
plt.subplot(2,2,i+1)
plt.imshow(images[i],'gray')
plt.axis('off')
plt.title(titles[i])
plt.show()
# 变灰度图
image = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
# 中值滤波
image = cv2.medianBlur(image,5)
# 普通二值化
ret,th1 = cv2.threshold(image,127,255,cv2.THRESH_BINARY)
# 平均值阈值
th2 = cv2.adaptiveThreshold(image,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,3)
# 高斯阈值
th3 = cv2.adaptiveThreshold(image,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,3)
titles = ['original', 'Global Thresholding', 'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [image, th1, th2, th3]
plt.figure(figsize=(10,5))
for i in range(4):
plt.subplot(2,2,i+1)
plt.imshow(images[i],'gray')
plt.axis('off')
plt.title(titles[i])
plt.show()
图像梯度:
I是图像像素的值(如:RGB值)
一阶导数:
x的梯度:Gx = I(x+1,y)-I(x,y)
y的梯度:Gy = I(x,y+1)-I(x,y)
二阶导数:
x的梯度:I(x+1,y)+I(x-1,y)-2I(x,y) y的梯度:I(x,y+1)+I(x,y-1)-2I(x,y) OpenCV 提供了三种不同的梯度滤波器,或者说高通滤波器: Sobel,Scharr 和 Laplacian。Sobel, Scharr 其实就是求一阶或二阶导数。 Scharr 是对 Sobel的优化。Laplacian 是求二阶导数。
梯度大小和方向的公式为:
G=(G2x+G2y)⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯√G=(Gx2+Gy2)
θ=tan−1(GxGy)θ=tan−1(GxGy) 梯度的方向一般总是与边界垂直。梯度方向被归为四类:垂直,水平,和两个对角线。
FAO
Sobel算子和Scharr算子:
Sobel 算子是高斯平滑与微分操作的结合体,所以它的抗噪声能力很好。你可以设定求导的方向(xorder 或 yorder)。还可以设定使用的卷积核的大小(ksize)。
FAO
如果 ksize=-1,会使用 3x3 的 Scharr 滤波器,它的的效果要比 3x3 的 Sobel 滤波器好(而且速度相同,所以在使用 3x3 滤波器时应该尽量使用 Scharr 滤波器)。 3x3 的 Scharr 滤波器卷积核如下:
FAO
Laplacian算子:
def gradient(image):
image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
# cv2.CV_64F输出图像的深度(数据类型),64位float类型,因为梯度可能是正也可能是负
laplacian = cv2.Laplacian(image, cv2.CV_64F)
# 1, 0表示在x方向求一阶导数,最大可以求2阶导数
sobelx = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=3)
# 0, 1表示在y方向求一阶导数,最大可以求2阶导数
sobely = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=3)
titles = ['Original', 'Laplacian', 'SobelX', 'SobelY']
images = [image,laplacian,sobelx,sobely]
plt.figure(figsize=(10,5))
for i in range(4):
plt.subplot(2,2,i+1)
plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.axis('off')
plt.show()
Canny边缘检测
Canny 边缘检测是一种非常流行的边缘检测算法,是 John F.Canny 在1986 年提出的。它是一个有很多步构成的算法,我们接下来会逐步介绍。
1.噪声去除
由于边缘检测很容易受到噪声影响,所以第一步是使用 5x5 的高斯滤波器去除噪声,这个前面我们已经学过了。
2.计算图像梯度
对平滑后的图像使用 Sobel 算子计算水平方向和竖直方向的一阶导数(图像梯度)(Gx 和 Gy)。根据得到的这两幅梯度图(Gx 和 Gy)找到边界的梯度和方向,公式如下:
G=(G2x+G2y)⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯√G=(Gx2+Gy2)
θ=tan−1(GxGy)θ=tan−1(GxGy) 梯度的方向一般总是与边界垂直。梯度方向被归为四类:垂直,水平,和两个对角线。
3.非极大值抑制
在获得梯度的方向和大小之后,应该对整幅图像做一个扫描,去除那些非边界上的点。对每一个像素进行检查,看这个点的梯度是不是周围具有相同梯度方向的点中最大的。如下所示:
FAO
上图中的数字代表了像素点的梯度强度,箭头方向代表了梯度方向。以第二排第三个像素点为例,由于梯度方向向上,则将这一点的强度(7)与其上下两个像素点的强度(5和4)比较,由于这一点强度最大,则保留。
4.滞后阈值
现在要确定那些边界才是真正的边界。这时我们需要设置两个阈值:minVal 和 maxVal。当图像的灰度梯度高于 maxVal 时被认为是真的边界,那些低于 minVal 的边界会被抛弃。如果介于两者之间的话,就要看这个点是否与某个被确定为真正的边界点相连,如果是就认为它也是边界点,如果不是就抛弃。如下图:
FAO
A 高于阈值 maxVal 所以是真正的边界点, B 虽然低于 maxVal 但高于minVal 并且与 A 相连,所以也被认为是真正的边界点。而 C 就会被抛弃,因为他不仅低于 maxVal 而且不与真正的边界点相连。D也会被抛弃,因为低于minVal。所以选择合适的 maxVal和 minVal 对于能否得到好的结果非常重要。在这一步一些小的噪声点也会被除去,因为我们假设边界都是一些长的线段。
Canny使用
在 OpenCV 中只需要一个函数: cv2.Canny(),就可以完成以上几步。让我们看如何使用这个函数。这个函数的第一个参数是输入图像。第二和第三个分别是 minVal 和 maxVal。第四个参数设置用来计算图像梯度的 Sobel卷积核的大小,默认值为 3。最后一个参数是 L2gradient,它可以用来设定求梯度大小的方程。如果设为 True,就会使用我们上面提到过的方程: G=(G2x+G2y)⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯√G=(Gx2+Gy2) ,否则使用方程: G=|G2x|+|G2y|G=|Gx2|+|Gy2| 代替,默认值为 False。
def edge_detection(image,minVal=100,maxVal=200):
image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
edges = cv2.Canny(image,minVal,maxVal)
plt.imshow(edges,'gray')
plt.axis('off')
plt.show()
image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
image = cv2.GaussianBlur(image, (3,3), 0)
Value = [(10,150),(100,200),(180,230)]
plt.figure(figsize=(20,5))
for i,(minVal,maxVal) in enumerate(Value):
plt.subplot(1,3,i+1)
edges = cv2.Canny(image,minVal,maxVal)
edges = cv2.GaussianBlur(edges, (3,3), 0)
plt.imshow(edges,'gray')
plt.title(str((minVal,maxVal)))
plt.axis('off')
plt.show()
# 自动确定阈值的一种方法
def auto_canny(image, sigma=0.33):
v = np.median(image)
lower = int(max(0, (1.0-sigma) * v))
upper = int(min(255, (1.0+sigma) * v))
edged = cv2.Canny(image, lower, upper)
print(lower,upper)
return edged
edges = auto_canny(image)
edges = cv2.GaussianBlur(edges, (3,3), 0)
plt.imshow(edges,'gray')
plt.axis('off')
plt.show()
# 从摄像头获取图像数据
cap = cv2.VideoCapture(0)
while(True):
# ret 读取成功True或失败Falseq
# frame读取到的图像的内容
# 读取一帧数据
ret,frame = cap.read()
# 变为灰度图
gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
cv2.imshow('frame',gray)
# waitKey功能是不断刷新图像,单位ms,返回值是当前键盘按键值
# ord返回对应的ASCII数值
if cv2.waitKey(1) & 0xff == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
cap.read() 返回一个布尔值(True/False)。如果帧读取的是正确的,就是 True。所以最后你可以通过检查他的返回值来查看视频文件是否已经到了结尾。
有时 cap 可能不能成功的初始化摄像头设备。这种情况下上面的代码会报错。你可以使用 cap.isOpened(),来检查是否成功初始化了。如果返回值是True,那就没有问题。否则就要使用函数 cap.open()。
你可以使用函数 cap.get(propId) 来获得视频的一些参数信息。这里propId 可以是 0 到 18 之间的任何整数。每一个数代表视频的一个属性。
FAO
其中的一些值可以使用 cap.set(propId,value) 来修改, value 就是你想要设置成的新值。
例如,我可以使用 cap.get(3) 和 cap.get(4) 来查看每一帧的宽和高。默认情况下得到的值是 640X480。但是我们可以使用 ret=cap.set(3,320)和 ret=cap.set(4,240) 来把宽和高改成 320X240。
# 从文件读取视频内容
cap = cv2.VideoCapture('videos/cats.mp4')
# 视频每秒传输帧数
fps = cap.get(cv2.CAP_PROP_FPS)
# 视频图像的宽度
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
# 视频图像的长度
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
print(fps)
print(frame_width)
print(frame_height)
while(True):
# ret 读取成功True或失败False
# frame读取到的图像的内容
# 读取一帧数据
ret,frame = cap.read()
if ret!=True:
break
cv2.imshow('frame',frame)
# waitKey功能是不断刷新图像,单位ms,返回值是当前键盘按键值
# ord返回对应的ASCII数值
if cv2.waitKey(25) & 0xff == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
视频写入
在我们捕获视频,并对每一帧都进行加工之后我们想要保存这个视频。对于图片来时很简单只需要使用 cv2.imwrite()。但对于视频来说就要多做点工作。
这次我们要创建一个 VideoWriter 的对象。我们应该确定一个输出文件的名字。接下来指定 FourCC 编码(下面会介绍)。播放频率和帧的大小也都需要确定。最后一个是 isColor 标签。如果是 True,每一帧就是彩色图,否则就是灰度图。
FourCC 就是一个 4 字节码,用来确定视频的编码格式。可用的编码列表可以从fourcc.org查到。
• In Fedora: DIVX, XVID, MJPG, X264, WMV1, WMV2. (XVID is more preferable. MJPG results in high size video. X264 gives very small size video)
# 从文件读取视频内容
cap = cv2.VideoCapture('videos/cats.mp4')
# 视频每秒传输帧数
fps = cap.get(cv2.CAP_PROP_FPS)
# 视频图像的宽度
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
# 视频图像的长度
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
print(fps)
print(frame_width)
print(frame_height)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('videos/output.avi',fourcc,fps,(frame_width,frame_height))
while(True):
ret, frame = cap.read()
if ret==True:
# 水平翻转
frame = cv2.flip(frame,1)
out.write(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(25) & 0xff == ord('q'):
break
else:
break
out.release()
cap.release()
cv2.destroyAllWindows()
# 系统操作
import os
# 判断文件类型
import imghdr
from imutils import *
# 人脸检测并保存人脸
def facedetect(image, output):
# 获取文件名
name = os.path.basename(image)
# 读入图片
image = cv2.imread(image)
# 变成灰度图
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 级联分类器,检测人脸
detector = cv2.CascadeClassifier("haarcascade_frontalface_alt.xml")
rects = detector.detectMultiScale(image, scaleFactor=1.1, minNeighbors=3, minSize=(20, 20), flags=cv2.CASCADE_SCALE_IMAGE)
# 循环每个人脸
for (x,y,w,h) in rects:
# 截取人脸,并且都转化为200*200的固定大小
f = cv2.resize(image[y:y+h, x:x+w], (200,200))
# 写入指定路径
cv2.imwrite(os.path.join(output, name), f)
# 检测并截取人脸
def predict_face(path, output):
# 如果该文件夹不存在则创建文件夹
if not os.path.exists(output):
os.makedirs(output)
# 循环每个人物的文件夹下的图片
for files in os.listdir(path):
# 检测是不是文件夹
if os.path.isdir(os.path.join(path, files)):
# 定义截取到的人脸的输出路径
output2 = os.path.join(output, files)
# 如果该文件夹不存在则创建文件夹
if not os.path.exists(output2):
os.makedirs(output2)
# 人物文件夹的完整路径
files = os.path.join(path, files)
# 循环每个人的每张照片
for file in os.listdir(files):
# 照片完整路径
file = os.path.join(files, file)
# 检测人脸并保存
facedetect(file, output2)
# 生成label文件
def get_label(path):
fh = open("label.txt", 'w')
# 表示人脸label
label = 0
for root, dirs, files in os.walk(path):
# 循环每个文件夹
for subdir in dirs:
# 文件夹完整路径
subdir_path = os.path.join(root,subdir)
# 循环每个人物文件夹下面每张照片
for file in os.listdir(subdir_path):
# 照片完整路径
filepath = os.path.join(subdir_path, file)
# 判断文件类型是不是图片类型
imgType = imghdr.what(filepath)
if imgType == 'jpeg' or imgType == 'png':
# 保存图片路径
fh.write(filepath);
fh.write(";")
# 标签
fh.write(str(label))
fh.write("\n")
# 每个人的标签不一样,从0开始计数
label = label + 1
fh.close()
# 保存图片数据
images = []
# 保存标签
labels = []
# 打开文件
fh = open("label.txt")
# 循环每一行
for line in fh:
# 以;切分字符串
arr = line.split(";")
# 第0部分为图片路径,读取文件
img = cv2.imread(arr[0],0)
# 保存图片数据
images.append(img)
# 保存对应的标签数据
labels.append(int(arr[1]))
# 安装opencv扩展包
# pip install opencv-contrib-python
# 定义人脸识别模型
model = cv2.face.EigenFaceRecognizer_create()
# model = cv2.face.FisherFaceRecognizer_create()
# model = cv2.face.LBPHFaceRecognizer_create()
# 训练模型
model.train(np.array(images), np.array(labels))
# 保存模型
model.save("predict_face_XiaoMing_AB.xml")
# 定义人物名字
name= ['ab','xiaoming']
# 定义人脸识别模型
model = cv2.face.EigenFaceRecognizer_create()
# 载入训练好的模型
model.read('predict_face_XiaoMing_AB.xml')
# 读入测试图片来做测试
for file in os.listdir('test'):
file = os.path.join('test', file)
# 判断文件类型
imgType = imghdr.what(file)
if imgType == 'jpeg' or imgType == 'png':
# 读入图片
image = imread(file)
# 变为灰度图
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
# 级联分类器
detector = cv2.CascadeClassifier("haarcascade_frontalface_alt.xml")
rects = detector.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=3, minSize=(20, 20), flags=cv2.CASCADE_SCALE_IMAGE)
# 循环每个人脸
for (x,y,w,h) in rects:
# 画矩形框
cv2.rectangle(image, (x,y), (x+w,y+h), (0,255,0), 2)
# 人脸识别
face = cv2.resize(gray[y:y+h,x:x+w], (200,200))
# 预测人物
params = model.predict(face)
# 写上人物名字
cv2.putText(image,name[params[0]],(x,y-20),cv2.FONT_HERSHEY_SIMPLEX,1,(255,0,0),2)
show(image)
网友评论