openCV学习笔记(1)

一开始是直接看的官方文档,然后再看的是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()

 

 接下来做图像平滑处理,原理可以看这篇文档

http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.html

例如均值滤波的原理就是用一个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:以常量填充,就最后那个样子

原文地址:https://www.cnblogs.com/Truedragon/p/12904257.html