安装opencv
- 最新版本的anaconda
anaconda网址 - 由于需要python3.6,于是在anaconda里创建一个3.6的环境
conda create -n python36 python=3.6
conda activate python36 //激活环境
此时anaconda navigator里会显示两个环境
- 安装opencv
pip install opencv-python==3.4.1.15
pip install opencv-contrib-python==3.4.1.15
图像基本操作
img1=cv2.imread('files/cat.jpg')
读取图片,将图片转化为一个三维的矩阵。默认加载彩色,如果第二个参数为0则加载灰度图。
可以打印看img1的一些参数print(img1.shape) print(img1.size)
cv2.imshow('hi', img1)
显示图片,只显示一下,使用cv2.waitKey(0)
来等待关闭- 逐帧读取视频
vc=cv2.VideoCapture('files/test.mp4')
if vc.isOpened():
open,frame=vc.read()//open为读取的情况,布尔值。frame为读取该帧的图像信息。
else:
open=False
while open:
now,frame=vc.read()
if(frame is None):
break
if(now==True):
grey=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
cv2.imshow('window',grey)
if cv2.waitKey(10) & 0xFF==27:
break
vc.release()
- 截取部分图像数据
img1 = cv2.imread('files/cat.jpg')
print(img1.shape)
cv2.imshow('h', img1)
img1 = img1[0:200, 0:100]
cv2.imshow('hi', img1)
print(img1.shape)
cv2.waitKey()
#输出
# (414, 500, 3)
# (200, 100, 3)
- 颜色通道提取与合并
img = cv2.imread('files/cat.jpg')
b, g, r = cv2.split(img)
print(b.shape)
print(g.shape)
a=cv2.merge((b,g,r))//参数是一个元组
print(a.shape)
#输出
# (414, 500)
# (414, 500)
# (414, 500, 3)
只保留R
img = cv2.imread('files/cat.jpg')
cv2.imshow('1', img)
img[:, :, 0] = 0;
img[:, :, 1] = 0
cv2.imshow('2', img)
cv2.waitKey(0)
- 边界填充
img = cv2.imread('files/cat.jpg')
top, bottom, left, right = 50, 50, 50, 50
cv2.imshow('h',img)
replicate = cv2.copyMakeBorder(img, top, bottom, left, right, borderType=cv2.BORDER_REFLECT)
cv2.imshow('hi',replicate)
cv2.waitKey(0)
- 数值计算
img = cv2.imread('files/cat.jpg')
img1 = img + 10//超出256则取模
//也可以两个图片相加,比如img1+img
//cv2.add(img1,img)若溢出则取255
print(img[:5, :, 0])
print(img1[:5, :, 0])
plt.show()
- 图像融合
融合的两张图的大小需要相等,先进行resize操作
img1 = cv2.resize(img1, (100, 429))//横向,纵向
img2 = cv2.resize(img1, (0, 0), fx=2, fy=2)//倍数
img1 = cv2.imread('files/cat.jpg')
cv2.imshow('hi', img1)
img1 = cv2.resize(img1, (100, 429))
img2 = cv2.resize(img1, (0, 0), fx=2, fy=2)
cv2.imshow('h', img1)
cv2.imshow('hh',img2)
cv2.waitKey(0)
img1 = cv2.imread('files/cat.jpg')
img2 = cv2.imread('files/dog.jpg')
img1 = cv2.resize(img1, (499, 429))
#αX1+βX2+b α为X1占的权重,β为X2占的权重,b为提亮
res=cv2.addWeighted(img1,0.4,img2,0.6,0)
cv2.imshow('1',img1)
cv2.imshow('2',img2)
cv2.imshow('3',res)
cv2.waitKey(0)
图像阈值
ret, dst = cv2.threshold(src, thresh, maxval, type)
- src:输入图,只能输入单通道图像,通常来说为灰度图
- dst:输出图
- thresh:阈值
- maxval:当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值
- type:二值化操作的类型,包含以下5种类型: cv2.THRESH_BINARY; cv2.THRESH_BINARY_INV; cv2.THRESH_TRUNC; cv2.THRESH_TOZERO;cv2.THRESH_TOZERO_INV
- cv2.THRESH_BINARY 超过阈值部分取maxval(最大值),否则取0
- cv2.THRESH_BINARY_INV THRESH_BINARY的反转
- cv2.THRESH_TRUNC 大于阈值部分设为阈值,否则不变
- cv2.THRESH_TOZERO 大于阈值部分不改变,否则设为0
- cv2.THRESH_TOZERO_INV THRESH_TOZERO的反转
平滑处理
- 均值滤波
值为以其为中心所在矩阵里的值的平均值
img=cv2.imread('files/lena.jpg')
cv2.imshow('h',img)
blur=cv2.blur(img,(3,3))//3*3的矩阵
cv2.imshow('b',blur)
cv2.waitKey(0)
- 方框滤波
#当最后一个参数为True时等价于均值滤波
#否则在所在矩阵中相加计算时若溢出则不会取模,而是取255
box=cv2.boxFilter(img,-1,(3,3),normalize=False)//
cv2.imshow('box',box)
- 高斯滤波
距离更近的数值所占权重比较大
aussian = cv2.GaussianBlur(img, (3, 3), 1)
cv2.imshow('aussian', aussian)
- 中值滤波
#取周围5*5的矩阵中的数值的中位数
median = cv2.medianBlur(img, 5) # 中值滤波
cv2.imshow('median', median)
一起展示的方法
```python
res = np.hstack((img,blur,aussian,median))
cv2.imshow('img,blur,aussian,median', res)
cv2.waitKey(0)
图像形态学处理
- 腐蚀操作
img = cv2.imread('files/1.png')
kernel = np.ones((5, 5), np.uint8)
erosion = cv2.erode(img, kernel, iterations=1)//迭代次数
res = np.hstack((img, erosion))
cv2.imshow('res', res)
cv2.waitKey(0)
- 膨胀
膨胀和腐蚀大概像是互逆的操作
img = cv2.imread('files/1.png')
kernel = np.ones((5, 5), np.uint8)
dige_dilate = cv2.dilate(img,kernel,iterations = 2)
cv2.imshow('dilate', dige_dilate)
- 开运算与闭运算
- 开运算:先腐蚀后膨胀
img = cv2.imread('files/1.png')
kernel = np.ones((5, 5), np.uint8)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
cv2.imshow('opening', opening)
res = np.hstack((img, opening))
cv2.imshow('res', res)
cv2.waitKey(0)
cv2.destroyAllWindows()
- 闭运算
先膨胀 后腐蚀 毛刺无法消除
img = cv2.imread('files/1.png')
kernel = np.ones((10, 10), np.uint8)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
# cv2.imshow('closing', closing)
res = np.hstack((img, closing))
cv2.imshow('1', res)
- 梯度运算
梯度运算=膨胀-腐蚀
pie = cv2.imread('files/pie.png')
cv2.imshow('1', pie)
kernel = np.ones((7, 7), np.uint8)
erosion = cv2.erode(pie, kernel, iterations=5)
dilate = cv2.dilate(pie, kernel, iterations=5)
gradient = cv2.morphologyEx(pie, cv2.MORPH_GRADIENT, kernel)
res = np.hstack((erosion, dilate, gradient))
cv2.imshow('res', res)
- 礼帽与黑帽
- 礼帽=原始-开运算
img = cv2.imread('files/1.png')
cv2.imshow('1',img)
kernel = np.ones((5, 5), np.uint8)
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
cv2.imshow('tophat', tophat)
- 黑帽=闭运算-原始
闭运算为先膨胀后腐蚀,此操作后图中的刺依旧存在,减去原图之后只剩下一个图像的大致轮廓
img = cv2.imread('files/1.png')
kernel = np.ones((5, 5), np.uint8)
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
cv2.waitKey(0)
res = np.hstack((img, blackhat))
cv2.imshow('1', res)
图像梯度处理
- 图像梯度-Sobel算子
dst = cv2.Sobel(src, ddepth, dx, dy, ksize)
- ddepth:图像的深度
- dx和dy分别表示水平和竖直方向,dx为1时则为水平方向
- ksize是Sobel算子的大小
水平方向是从左到右,白-黑>0正常显示,黑-白为负数,应取绝对值。
垂直方向是从下到上
img = cv2.imread('files/lena.jpg', cv2.IMREAD_GRAYSCAL
#水平方向和垂直方向一起算不如分别算完之后相加效果好
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)
sobely = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0)
res = np.hstack((img, sobelxy))
cv2.imshow('1', res)
- Scharr算子
类似于Sobel,但权重更大,效果更明显
img = cv2.imread('files/lena.jpg', cv2.IMREAD_GRAYSCALE)
scharrx = cv2.Scharr(img, cv2.CV_64F, 1, 0)
scharry = cv2.Scharr(img, cv2.CV_64F, 0, 1)
scharrx = cv2.convertScaleAbs(scharrx)
scharry = cv2.convertScaleAbs(scharry)
scharrxy = cv2.addWeighted(scharrx, 0.5, scharry, 0.5, 0)
res=np.hstack((img,scharrxy))
- laplacian算子
对于变化更加敏感,但是对于噪点也更加敏感
img = cv2.imread('files/lena.jpg', cv2.IMREAD_GRAYSCALE)
laplacian = cv2.Laplacian(img, cv2.CV_64F)
laplacian = cv2.convertScaleAbs(laplacian)
res = np.hstack((img, laplacian))
cv2.imshow('res',res)
Canny边缘检测
img = cv2.imread("files/car.png", cv2.IMREAD_GRAYSCALE)
v1 = cv2.Canny(img, 80, 150)//minval和maxval值小的话得到的细节更多,
v2 = cv2.Canny(img, 50, 100)//但也可能是无用的噪点
res = np.hstack((v1, v2))
cv2.imshow('res', res)
图像金字塔
- 拉普拉斯金字塔
down=cv2.pyrDown(img)
down=cv2.pyrUp(down)
cv2.imshow('1',img-down)
图像轮廓
cv2.findContours(img,mode,method)
mode:轮廓检索模式
- RETR_EXTERNAL :只检索最外面的轮廓;
- RETR_LIST:检索所有的轮廓,并将其保存到一条链表当中;
- RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;
- RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次;
method
轮廓逼近方法 - CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。
- CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。
img = cv2.imread('files/car.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
#contours代表获取到的图像的轮廓信息,为list类型
res = cv2.drawContours(img, contours, -1, (0, 0, 255), 2)
#第三个参数为-1时表示所有轮廓,否则代表轮廓的下标
#第四个参数为BGR
#第五个参数代表轮廓的粗细
cv2.imshow('4', res)
轮廓特征
cnt = contours[0]//得到编号为0的轮廓
print(cv2.contourArea(cnt))//面积
print(cv2.arcLength(cnt, True))//周长,True表示是闭合的
轮廓近似
#普朗克算法
binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
draw_img = img.copy()
cnt = contours[0]
epsilon = 0.04 * cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)
draw_img = img.copy()
res = cv2.drawContours(draw_img, [approx], -1, (0, 0, 255), 2)
边界矩形
img = cv2.imread('files/demo1.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[0]
x, y, w, h = cv2.boundingRect(cnt)
#x,y是矩阵左上点的坐标,w,h是矩阵的宽和高
img = cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
#(x,y)是矩阵的左上点坐标
#(x+w,y+h)是矩阵的右下点坐标
外接圆
x, y, w, h = cv2.boundingRect(cnt)
img = cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
模板匹配
假如原图形是AxB大小,而模板是axb大小,则输出结果的矩阵是(A-a+1)x(B-b+1)
res = cv2.matchTemplate(img, face, cv2.TM_SQDIFF)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
print(res.shape)
img = cv2.rectangle(img, min_loc, (min_loc[0] + w, min_loc[1] + h), 255, 2)
- TM_SQDIFF:计算平方不同,计算出来的值越小,越相关
- TM_CCORR:计算相关性,计算出来的值越大,越相关
- TM_CCOEFF:计算相关系数,计算出来的值越大,越相关
- TM_SQDIFF_NORMED:计算归一化平方不同,计算出来的值越接近0,越相关
- TM_CCORR_NORMED:计算归一化相关性,计算出来的值越接近1,越相关
- TM_CCOEFF_NORMED:计算归一化相关系数,计算出来的值越接近1,越相关
匹配多个对象
face = cv2.imread('files/mario_coin.jpg')
img = cv2.imread('files/mario.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow('img1',img)
h, w = face.shape[:2]
res = cv2.matchTemplate(img, face, cv2.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where(res > threshold)
for pt in zip(*loc[::-1]):
bottom_right = (pt[0] + w, pt[1] + h)
cv2.rectangle(img, pt, bottom_right, (0, 0, 255), 2)
cv2.imshow('img',img)
直方图
cat = cv2.imread('files/cat.jpg', 0)
hist = cv2.calcHist([cat], [0], None, [256], [0, 256])
plt.hist(cat.ravel(), 256)
#cat.ravel() 是多维矩阵变一维数组
cv2.calcHist(images,channels,mask,histSize,ranges)
- images: 原图像图像格式为 uint8 或 float32。当传入函数时应 用中括号 [] 括来例如[img]
- channels: 同样用中括号括来它会告函数我们统幅图 像的直方图。如果入图像是灰度图它的值就是 [0]如果是彩色图像 的传入的参数可以是 [0] [[1]] [[2]] 它们分别对应着 BGR。
- mask: 掩模图像。统整幅图像的直方图就把它为 None。但是如 果你想统图像某一分的直方图的你就制作一个掩模图像并 使用它。
- histSize:BIN 的数目。也应用中括号括来
- ranges: 像素值范围常为 [0256]