5500字,从零开始入门OpenCV的超基础操作~
一.图像起源
图像是人类视觉的基础,是自然景物的客观反映,是人类认识世界和人类本身的重要源泉。“图”是物体反射或者透射光的分布,“像”是人的视觉系统所接受的图在人脑中所形成的印象或者认知。
二.数字图像和模拟图像
说来也巧,学过计网的同学一定记着数字信号和模拟信号这两个概念,显然图像作为一种数据也有着异曲同工之妙,数字图像和模拟图像分别是图像的两种表现形式。
图像起源于第一张可以永久保存的照片,这张照片属于模拟图像。模拟图像又被称为连续图像,它通过某种物理量的强弱变化来记录图像的亮度信息,所以是连续变换的。模拟信号的特点是容易受到干扰,如今已经基本全面被数字图像替代~
三.数字图像的表示
计算机次用0/1编码的系统,数字图像也是利用0/1来记录信息,我们平常接触的图像都是8位数的图像,即灰度范围是0~255,其中0代表最黑,255最白~
人眼则更敏感一些,对灰度的感受为16~32位。
四.图像分类
1.二值图
一幅二值图的二维矩阵仅由0/1两个值构成,0代表黑色而1代表白色。由于每一像素取值仅有0/1两种可能,所以计算机中二值图像的数据类型通常为1个二进制位。二值图像通常用于文字、线条图和扫描识别OCR和掩膜图像的存储。
2.灰度图
每个像素只有一个采样颜色的图像,这类图像通常显示未最暗黑色到最亮白色的灰度,尽管理论上这个采样可为任何颜色的不同深浅,甚至可以是不同亮度上的不同颜色。灰度图像与黑白图像不同,在计算机图像领域中黑白图像只有黑色和白色两种颜色,但是灰度图像在黑色和白色之间还有许多级的颜色深度。灰度图像经常是在单个电磁波频谱如可见光内测量每个像素的亮度得到的,用于显示的灰度图像通常采用每个像素8位的非线性尺度来保存,这样可以有256级灰度——如果用16位则有65536级~
3.彩色图
每个像素通常是由RGB三个分量来表示的,分量介于0~255之间。RGB图像与索引图像一样都可以用来表示彩色图像。与索引图像一样,它分别用红绿蓝三原色的组合来表示每个像素的颜色,但与像素图不同的是,RGB图像每个像素的颜色值直接存放在图像矩阵中。由于每一个像素的颜色需要由RGB三个分量来表示,M、N分别表示图像的行列数,三个M*N的二维矩阵分别表示各个像素的R、G、B三个颜色的分量。RGB图像的数据类型一般为8位无符号整形,通常用于表示和存放真彩色图像。
- 每一个非常小的小格,就是一个像素点~像素点构成一个图像
- (0-255浮动,表示一个点的亮度~大白小黑~)
- 每个点都对应3个颜色矩阵(RGB即为颜色通道)灰度图就只有一个颜色通道
- 三色图就有3个颜色通道~
五.OpenCV简介
OpenCV是一个计算机视觉处理的开源软件库,支持计算机视觉和机器学习相关的开源算法。OpenCV-Python是一个Python绑定库,旨在解决计算机视觉问题。
Python的下载就不说了,博主使用的版本是3.12。
首先安装numpy和matplotlib(别忘了以管理员身份运行):
pip install numpy
pip install matplotlib
然后用pip list命令查看一下安装好与否:
安装OpenCV-python:
pip install opencv-python
然后执行:pip install --upgrade pip
升级OpenCV到最新版本~
还有一个名叫opencv-contrib-python 的包,需要下载为和前者一样的版本:
六.OpenCV常用操作
1.读取图像
import cv2
img = cv2.imread("D:\\Code.jpg")
cv2.imshow('img',img) #显示图像,也可以创建多个窗口
cv2.waitKey(0) #等待时间,这里设置为0,表示任意键终止
cv2.destroyAllWindows() #销毁窗口
为了方便实用建议封装为函数:
import cv2
def cv_show(img,name):
cv2.imshow('img',img) #显示图像,也可以创建多个窗口
cv2.waitKey(0) #等待时间,这里设置为0,表示任意键终止
cv2.destroyAllWindows() #销毁窗口
img = cv2.imread("D:\\Code.jpg")
cv_show(img,"img")
还是老生常谈的转义符问题:一定要用双反斜杠!此外路径最好不要出现中文~
2.获取图像尺寸
print(img.shape)
前两者分别为高度和宽度,后者证明是RGB图。当然需要注意的是,这里的三色图顺序其实是BGR~
也可以直接指定图像的长宽高修改大小:
import cv2
def cv_show(img,name):
cv2.imshow('img',img) #显示图像,也可以创建多个窗口
cv2.waitKey(0) #等待时间,这里设置为0,表示任意键终止
cv2.destroyAllWindows() #销毁窗口
img = cv2.imread("D:\\Code.jpg")
img=cv2.resize(img,(300,300))
cv_show(img,"img")
也可以按照如下写法,直接按照比例对图像进行放缩:
img = cv2.imread("D:\\Code.jpg")
img=cv2.resize(img,(0,0),fx=0.5,fy=0.5)
cv_show(img,"img")
3.灰度图
import cv2
def cv_show(img,name):
cv2.imshow('img',img) #显示图像,也可以创建多个窗口
cv2.waitKey(0) #等待时间,这里设置为0,表示任意键终止
cv2.destroyAllWindows() #销毁窗口
img = cv2.imread("D:\\Code.jpg",cv2.IMREAD_GRAYSCALE)
cv_show(img,"img")
添加参数后可以读取为灰度图:
import cv2
img = cv2.imread("D:\\Code.jpg")
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
也可以读取后再转换,效果一样~
4.图像的一些属性
import cv2
def cv_show(img,name):
cv2.imshow('img',img) #显示图像,也可以创建多个窗口
cv2.waitKey(0) #等待时间,这里设置为0,表示任意键终止
cv2.destroyAllWindows() #销毁窗口
img = cv2.imread("D:\\Code.jpg",cv2.IMREAD_GRAYSCALE)
print(type(img)) #格式
print(img.size) #像素点个数
print(img.dtype) #类型
5.截取部分图像
其实就是对像素点矩阵做个切片操作:
import cv2
def cv_show(img,name):
cv2.imshow('img',img) #显示图像,也可以创建多个窗口
cv2.waitKey(0) #等待时间,这里设置为0,表示任意键终止
cv2.destroyAllWindows() #销毁窗口
img = cv2.imread("D:\\Code.jpg")
code=img[0:200,0:200]
cv_show(code,"code")
6.颜色通道获取
将RGB三色分别提取出来,但是还是要注意RGB的顺序哦:
import cv2
def cv_show(img,name):
cv2.imshow('img',img) #显示图像,也可以创建多个窗口
cv2.waitKey(0) #等待时间,这里设置为0,表示任意键终止
cv2.destroyAllWindows() #销毁窗口
img = cv2.imread("D:\\Code.jpg")
B,G,R=cv2.split(img)
通过merge函数你还可以将三色再组装回去:
import cv2
def cv_show(img,name):
cv2.imshow('img',img) #显示图像,也可以创建多个窗口
cv2.waitKey(0) #等待时间,这里设置为0,表示任意键终止
cv2.destroyAllWindows() #销毁窗口
img = cv2.imread("D:\\Code.jpg")
B,G,R=cv2.split(img)
newImg=cv2.merge((B,G,R))
cv_show(newImg,"newImg")
亦可单独显示RGB的一种颜色——其他全设置为0即可:
import cv2
def cv_show(img,name):
cv2.imshow('img',img) #显示图像,也可以创建多个窗口
cv2.waitKey(0) #等待时间,这里设置为0,表示任意键终止
cv2.destroyAllWindows() #销毁窗口
img = cv2.imread("D:\\Code.jpg")
B,G,R=cv2.split(img)
img1=img.copy()
img1[:,:,0]=0
img1[:,:,1]=0
cv_show(img1,"img1")
注意:不能直接用分离出来的R、G、B绘图,因为这三者是直接少了2个通道,而正确做法是将另外两个通道全部赋值为0~
7.边界填充
选择图像的上下左右3个边,可以自定义像素宽度——有点像CSS属性,然后调用borderType属性选择填充方法:
import cv2
def cv_show(img,name):
cv2.imshow('img',img) #显示图像,也可以创建多个窗口
cv2.waitKey(0) #等待时间,这里设置为0,表示任意键终止
cv2.destroyAllWindows() #销毁窗口
img = cv2.imread("D:\\Code.jpg")
top,bottom,left,right=(50,50,50,50)
replicate=cv2.copyMakeBorder(img,top,bottom,left,right,borderType=cv2.BORDER_CONSTANT,value=[255,255,255])
cv_show(replicate,"replicate")
这里我们选择BORDER_CONSTANT也即常数填充法——用一个颜色填充,赋值为255,255,255意为用白色填充~
borderType还有如下属性,各位可以自行尝试:
- BORDER_REPLICATE:复制最边缘的像素
- BORDER_REFLECT:反射法,也即在按照图像的边缘反向扩充
- BORDER_REFLECT_101:以边缘点为对称轴翻新扩充
- BORDER_WARP:外包装法 ,按照像素点取值的顺序依次向两边填充~
8.像素数值计算
- 图像的像素点类型为ndarray数组,允许和常数运算,也可以和另一张图像的像素点运算,但必须维度一致~
- 当数组中的像素值大于255,会进行取模操作,保证在0~255的范围内~
9.图像叠加
通过addweight函数可以将数张图片以像素点的方式叠加在一起,这里随便找的图可能四不像:
import cv2
def cv_show(img,name):
cv2.imshow('img',img) #显示图像,也可以创建多个窗口
cv2.waitKey(0) #等待时间,这里设置为0,表示任意键终止
cv2.destroyAllWindows() #销毁窗口
img1 = cv2.imread("D:\\Code.jpg")
img2 = cv2.imread("D:\\Bayern.jpg")
img1=cv2.resize(img1,(300,300))
img2=cv2.resize(img2,(300,300))
img3=cv2.addWeighted(img1,0.5,img2,0.5,0)
cv_show(img3,"img3")
10.图像阈值
阈值也即一个既定的范围,图像中的像素点值理论上在0-255之间,因此我们需要对超过某个值的部分做出相应的调整~
import cv2
def cv_show(img,name):
cv2.imshow('img',img) #显示图像,也可以创建多个窗口
cv2.waitKey(0) #等待时间,这里设置为0,表示任意键终止
cv2.destroyAllWindows() #销毁窗口
img = cv2.imread("D:\\Code.jpg")
img = cv2.resize(img,(0,0),fx=0.5,fy=0.5)
ret,thresh = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
#ret为阈值,thresh为处理后的图像
#4个参数分别为:传入图像、阈值、最大值、阈值处理类型
cv_show(thresh,"thresh")
这里虽然使用了二值类型,但由于输入的图不是灰度图(也即并非单通道图),因此并不会变成真正意义上的二值图!
Type选值如下:
- cv2.THRESH_BINARY:超过阈值的部分取maxval,否则取0
- cv2.THRESH_BINARY_INV:前者的翻转,超过的赋值为0,负责为maxval
- cv2.THRESH_TRUNC:大于阈值则变为阈值,其他不变
- cv2.THRESH_TOZERO:大于阈值不变,否则为0
- cv2.THRESH_TOZERO_INV:前者翻转,小于阈值不变,否则变为最大值maxval
由于篇幅太长,下期继续~