这篇博文面向所有使用python版本的opencv的开发者,本人入门的时候硬读文档根本不知道如何下手。浪费了很多的时间,希望各位后辈们入行的时候能够轻松一些,把示例写的详细简单,代码基本上都是开盖即用,只要大家修改相应的参数即可。认真的看完本博文,并且把下面的代码跑一跑就能够把一些基础的opencv操作学明白了。后面还附一个获取视频流的代码,其实视频和图像本质是一样的,视频不过是快速展示的连续的图片。大家在学习过程中如果有问题可以私信或者留言。如果想要转载,请留言并且注明源链接。
图片展示
# 读入图像:
retval = cv2.imread(源图像[,显示控制参数])
# 显示图像:
result = cv2.imshow(窗口名,图像名)
# 基本上这两个命令就是opencv典中典,你想读取或者展示结果必须要这两个操作,
# 下面的代码中我有些没有写展示图像,大家想看结果不要使用print,print只能看到数组,
# 使用 cv2.imshow(窗口名,图像名) 才能看到图像形式的结果
retval = cv2.waitKey([, delay])
# delay:
# delay>0 等待delay毫秒
# delay<0 等待键盘单击
# delay=0 无限等待
cv2.destroyAllWindows() #删除所有窗口
# 保存图像:
retval=cv2.imwrite(目标文件,源图像)
图像基础
img = cv2.imread(源图像[,显示控制参数])
#读取像素:[88,142]为像素位置
p=img[88,142]
#BGR图像,返回值为B,G,R 的值。
blue=img[78,125,0]
print(blue)
green=img[78,125,1]
print(green)
red=img[78,125,2]
print(red)
#用numpy读取像素:
p=img.item(88,142)
print(p)
#修改像素:
img[88,99]=[255,255,255]
#用numpy修改像素:
#图像名.itemset(位置,新值)
img.itemset((88,99,0),255)
img.itemset((88,99,1),255)
img.itemset((88,99,2),255)
#获取图像属性:
#shape 可以获取图像的形状,返回包含行数,列数,通道数的元组。
#示例:
print(img1.shape)
#size 可以获取图像的像素数目 灰度【 返回:行数*列数】 彩色 【返回:行数*列数*通道数】
print(img1.shape)
#dtype 返回的是图像的数据类型。
print(img.dtype)
通道的拆分与合并:
img = cv2.imread(源图像[,显示控制参数])
#拆分:
b , g , r = cv2.split(img)
b=cv2.split(a)[0]
g=cv2.split(a)[1]
r=cv2.split(a)[2]
#合并:
m=cv2.merge([b,g,r])
图像运算
加法运算:
numpy加法运算:
运算方式:
img1 = cv2.imread(源图像[,显示控制参数])
img2 = cv2.imread(源图像[,显示控制参数])
result = img1 + img2
# numpy的加法运算为取模加法:当两张图片的某像素点相加结果超过255时,结果为对255取模的运算
# 例:
img1[x][y] = 254
img2[x][y] = 59
result[x][y] = img1[x][y] + img2[x][y]
# result[x][y] = 58
# 注:(254+59)% 255 = 58
opencv加法运算:
result = cv2.add(img1,img2)
#opencv的加法运算为饱和运算:当两张图片的某像素点相加结果超过255时,结果为255
#例:
img1[x][y] = 254
img2[x][y] = 59
result[x][y] = img1[x][y] + img2[x][y] = 255
注:参与计算的图像大小和类型必须一致
图像融合:
将两个同样大小的图像以不同的权重叠加在一起,和图像加法的区别就是多了权重,大家可以找两个图片试一试如果实在找不到同样大小的可以先看看下面的图像缩放,resize一下
#图像融合:img=img1*0.3+img2*0.7+18
#利用函数addWeighted:
#dst = cv.addWeighted(src1, alpha, src2, beta, gamma)
img1 = cv2.imread(文件名[,显示控制参数])
img2 = cv2.imread(文件名[,显示控制参数])
img = cv.addWeighted(img1,0.3,img2,0.7,18)
#img = img1*0.3+img2*0.7+18
图像转换:
a = cv2.imread(文件名[,显示控制参数])
#将a转换成灰度图像,这个函数可以将不同形式存储的图像转换成另外的形式,参数可以自己查一下文档
#常用的基本上就是这个
b=cv2.cvtColor(a, cv2.COLOR_BGR2GRAY)
#将a分解成为三个通道
b,g,r=cv2.split(a)
几何变换:
图像缩放:
dst=cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]])
a = cv2.imread(文件名[,显示控制参数])
# dsize参数缩放,如下所示为将a图像缩放到 122 x 122 的大小
b=cv2.resize(a,(122,122))
# fx,fy参数,如下所示为将图像a的横轴缩小1/2,纵轴缩小1/2,整体缩小到 1/4
b=cv2.resize(a,None,fx=0.5,fy=0.5)
图片翻转:
dst = cv2.flip( src, flipCode)
# 范例:
src = cv2.imread(源文件[,])
dst = cv2.flip( src, 1)
# flipCode=0 以 X 轴为对称轴翻转
# flipCode>0 以 Y 轴为对称轴翻转
# flipCode<0 在X轴、Y轴方向同时翻转
图像平滑处理
均值滤波:
# 函数blur 处理结果=cv2.blur(原始图像,核大小)
# 核大小:以(宽度,高度)形式表示的元组
src = cv2.imread(...) #不想敲了,其实这个读取是和上面参数都是一样的
result = cv2.blur(src,(2,2))
高斯滤波:
高斯滤波的主要作用就是消除图像的高斯噪声,这个我遇到的比较少,但是也可以作为一种平滑处理的方式让图像更平滑,整体方差更小
dst = cv2.GaussianBlur( src , ksize , sigmaX )
# src :原始图像, ksiez :核大小, sigmaX:X方向方差
# ksiez :核大小 (N,N) 必须是奇数
# sigmaX:X方向方差,控制权重
src = cv2.imread(...)
dst = cv2.GaussianBlur( src , (3,3), 0.5 )
中值滤波:
# medianBlur函数:
dst = cv2.medianBlur( src , ksize )
# src:源文件 ksize: 核大小
# ksize : 核大小,必须是比1大的奇数,如3,5,7等
# 兄弟们这和上面的都差不多,自己写一个demo看看吧,但是要注意
# 这里的ksize不是元组而是整数
形态学转换
图像腐蚀:
图像腐蚀一般和膨胀一起用去除噪声,基本的的原理就是让卷积核在图像上面扫描,将卷积核中的颜色最深的像素值赋值给中心点。通俗来讲就是深色的区域变大了,浅色的区域变少了
函数erode:
dst = cv2.erode ( src , kernel , iterations )
# dst 处理结果 ,src 源图像 ,kernel 卷积核 ,iterations 迭代次数
# 示例:
# 先读取一张图片,自己写一下
# 然后创建卷积核
kernel = np.ones((5,5),np.uint8)
dst = cv2.erode ( src , kernel , 5)
# 然后展示自己写一下
图像膨胀:
和腐蚀的操作相反,基本的的原理就是让卷积核在图像上面扫描,将卷积核中的颜色最前的像素值赋值给中心点。通俗来讲就是前色的区域变大了,深色的区域变少了
# demo就不写了
# 两个输入对象:二值图像,卷积核
# 函数dilate:
dst = cv2.dilate ( src , kernel , iterations )
# dst 处理结果 ,src 源图像 ,kernel 卷积核 ,iterations 迭代次数
# 使用 :kernel = np.ones((5,5),np.uint8)创建卷积核
梯度下降
sobel算子:
sobel算子的作用是计算图像的梯度,一般初学图像处理的情况下我们使用sobel算子来提取图像的边缘信息,大家可以试一下以下的代码,直观的体验一下。在某些特定的场景下需要使用sobel算子提取边缘信息,对理论感兴趣的同学可以百度一下,理论也并不复杂。
dst = cv2.Sobel( src , ddepth , dx , dy , [ksize] )
# dst:计算结果, src:原始图像,
# ddepth :处理结果图像深度, dx :x轴方向 ,dy :y轴方向 , ksize :核大小
# ddepth在通常情况下,可以将该参数的值设置为-1,让处理结果与原 始图像保持一致
# 实际使用中使用更好的数据类型将ddepth设置为cv2.CV_64F,
# 取绝对值后,再转换为np.uint8 (cv2.CV_8U)类型。
# 计算x方向梯度:【dx=1,dy=0】 计算y方向梯度:【dx=0,dy=1】
dx= cv2.Sobel( src , ddepth , 1 , 0 )
dy= cv2.Sobel( src , ddepth , 0 , 1 )
dst= dx + dy
# dst= dx * 系数1+ dy *系数2
# 这里也可以使用上面介绍过的addWeighted函数对结果进行加权处理
函数convertScaleAbs:
dst = cv2.convertScaleAbs( src [, alpha[, beta]] )
作用:将原始图像src转换为256色位图。
一段展示边缘信息提取的完整代码:
这段代码大家可以反复的尝试,因为sobel这里有很多坑,大家可以思考一下为什么需要cv2.convertScaleAbs函数,用选择较小的图片将各个步骤的结果print出来,观察数值的变化
import cv2
import numpy as np
# 这里cv2.IMREAD_COLOR为读取原色彩,
# 也可以使用cv2.IMREAD_GRAYSCALE,将图片读取为灰度图片,这样读取图片的效果更加直观
o = cv2.imread('D:\\asdfasdfa.png',cv2.IMREAD_COLOR)
# 提取边缘信息
sobelx = cv2.Sobel(o,cv2.CV_64F,1,0)
sobely = cv2.Sobel(o,cv2.CV_64F,0,1)
# 在这里是将记录图片信息的数组取绝对值并且转换成8位的uint8格式
# 大家也可以把这两行注释掉看看效果,或者修改一下参数
sobelx = cv2.convertScaleAbs(sobelx) # 转回uint8
sobely = cv2.convertScaleAbs(sobely)
# 图像融合
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
# 展示图像
cv2.imshow("original",o)
cv2.imshow("x",sobelx)
cv2.imshow("y",sobely)
cv2.imshow("xy",sobelxy)
cv2.waitKey()
cv2.destroyAllWindows()
获取视频流:
下面的代码可以使用opencv调取电脑的摄像头,大家可以通过修改下面的代码,再结合上面的代码改装出一些滤镜的效果,当然视频最好使用显卡跑,要不然会比较卡。
import numpy as np
import cv2
//视频捕捉编号为0的摄像头
cap = cv2.VideoCapture(0)
//设置视频解码器
fourcc = cv2.VideoWriter_fourcc(*'XVID')
//保存
out = cv2.VideoWriter('testwrite.avi',fourcc, 20.0, (1920,1080),True)
while(cap.isOpened()):
ret, frame = cap.read()
if ret==True:
cv2.imshow('frame',frame)
out.write(frame)
if cv2.waitKey(10) & 0xFF == ord('q'):
break
else:
break
//释放资源
cap.release()
out.release()
cv2.destroyAllWindows()
写在最后,这就是本期的所有内容了,本文中省略了很多的理论部分,大家上手来先试一下,以后会更新其他的图像处理的理论和实践部分,如果同学们觉得哪里需要一些理论的铺垫或者代码运行有问题可以随时私信我,或者留言评论。码字不易,点个赞再走吧(●'◡'●)!