图像基本操作
计算机眼中的图像
首先我们可以把图像看成一个二维视图,针对图像的处理,我们需要将2D图像转化为具体数据,因此可分为以下几种情况:
- 形成新的图像
- 决策目标
- 目标结果
- 提取相关信息
图像的处理流程分为三步:
- 读取图像
- 图像处理
- 显示结果
基础知识
在表示图像时,有多种颜色模型(RGB、HSB、CMYK等),最常见的是RGB(红绿蓝)模型,这是一种加法颜色模型,其中三原色混合在一起就可以用来表示广泛的颜色范围。
每个原色(R,G,B)通常表示一个通道,其中三个值取值范围为[0,255]内的整数值,每个取值共有256个可能离散值,因此RGB模型总共需要3*8=24比特数,又称为24位色深图像。
我们可以把RGB看作一个三维直角坐标系,R G B的值分别对应坐标系的xyz轴的值,因此任何一种颜色都可以在坐标系中直接表示出来,在原点时,即取值全为0表示黑色,当取值全为255时表示白色,在连接黑色和白色的对角线上,是亮度等量的三基色混合而成的灰色,该线称为灰色线。
分辨率指横纵方向的像素点数,单位为px。 800 × 1200 800\times1200 800×1200的图像是一个包含800列和1200行的网格,每个网格就是一个像素,因此包含了96万像素。但是图像中的像素并不表示物理尺寸,像素的大小取决于为该图像设置的每英寸像素数(Pixels Per Inch,PPI)。图像的计算PPI的基本公式如下:
- PPI=宽度(像素)/图像宽度(英寸)
- PPI=高度(像素)/图像高度(英寸)
一个2×3英寸的图像,图像分辨率为800×1200,则PPI是200
注意:出于历史原因,OpenCV的颜色模型为BGR,与RGB正好相反
图像描述
图像可以描述为一个二元函数
f
(
x
,
y
)
f(x,y)
f(x,y),其中x、y为二维图像的坐标,
f
(
x
,
y
)
f(x,y)
f(x,y)表示在点(x,y)处的亮度或者颜色值,当两者皆为有限离散量时,该图像称为数字图像,此时:
- x∈[0,h-1],其中h为图像的高度
- y∈[0,w-1],其中w为图像的宽度
- f ( x , y ) f(x,y) f(x,y)∈[0,L-1],这里L=256(RGB模型),同时有三种函数 f f f,即 f R f_R fR、 f G f_G fG、 f B f_B fB,分别对应R、G、B的三个分量
不同的图像类别通道数也不一样:
- RGB模型的彩色图共有三个通道R、G、B表示R、G、B的分量
- 灰度图只有一个通道表示亮度
- 黑白图有一个通道,0表示黑色,1表示白色
基本操作
读取图像
首先导入cv2库,即openCV工具库
import cv2 #opencv读取的格式是BGR
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
注:%matplotlib inline 为python内置的魔法命令,通常以%或者%%开头,可以在IPython的环境的操作中更加得心应手,这里是内嵌画图,省略plt.show(),自动生成对应图像显示在页面中,而不用弹出窗口
img=cv2.imread('cat.jpg',IMREAD_COLOR) #读取图像,第二个参数不填时默认为彩色图像
#图像的显示,也可以创建多个窗口
cv2.imshow('image',img)
# 等待时间,毫秒级,0表示任意键终止
cv2.waitKey(0) #n表示图片显示n毫秒后消失
cv2.destroyAllWindows() #销毁窗口
- IMREAD_COLOR: 彩色图像
- IMREAD_GRAYSCALE: 灰度图像
图像如下图:
img对象的类型
img.shape
输出: 当为彩图时:(414,500,3)
灰度图时:(414,500)
#保存,成功会返回true,失败返回false
cv2.imwrite('mycat.png',img)
像素个数(彩图时=414*500*3)
img.size
读取视频
cv2.VideoCapture可以捕获摄像头,用数字控制不同的设备,如果是视频文件,直接指定路径即可.
对于视频其实也可以看作是由一帧一帧的二维图像组成的,因此读取视频时,需要不断循环读取所有的帧
vc = cv2. VideoCapture('test.mp4')
# 检查是否打开正确
if vc.isOpened():
oepn, frame = vc.read() #open为true,frame为视频中的一帧
else:
open = False
while open:
ret, frame = vc.read()
if frame is None:
break
if ret == True:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #把三通道转化为灰度图
cv2.imshow('result', gray) #展示结果
if cv2.waitKey(100) & 0xFF == 27: #前者表示处理帧的速度,后者表示Esc键退出
break
vc.release()
cv2.destroyAllWindows()
截取部分图像数据
cat=img[0:50,0:200] # h,w,左闭右开
颜色通道提取
图片的拆分和合并
b,g,r=cv2.split(img) #OpenCV中是bgr顺序,这里是拆分
img=cv2.merge((b,g,r)) #三个通道重新组合成一张图片
更改像素值
# 只保留R (BGR,一共三个通道,取0-2)
cur_img = img.copy()
cur_img[:,:,0] = 0 #B取0;‘:’表示取所有,即整个B通道的像素点全取0
cur_img[:,:,1] = 0 #G取0
cv_show('R',cur_img)
边界填充
顾名思义,即在图片的四周填充相应区域,cv2.copyMakerBorder函数可在图像周围形成边框
top_size,bottom_size,left_size,right_size = (50,50,50,50) #上下左右
replicate = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_WRAP)
constant = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,cv2.BORDER_CONSTANT, value=0)
borderType参数类型:
- BORDER_REPLICATE:复制法,也就是复制最边缘像素。
- BORDER_REFLECT:反射法,对感兴趣的图像中的像素在两边进行复制例如: fedcba|abcdefgh|hgfedcb
- BORDER_REFLECT_101:反射法,也就是以最边缘像素为轴,对称,gfedcb|abcdefgh|gfedcba
- BORDER_WRAP:外包装法cdefgh|abcdefgh|abcdefg
- BORDER_CONSTANT:常量法,常数值填充,不同value值对应不同的颜色填充。
像素数值计算
img_cat=cv2.imread('cat.jpg')
img_dog=cv2.imread('dog.jpg')
img_cat2= img_cat +10 #所有像素点都加10
img_cat[:5,:,0] #取前五行,所有列,B通道
#相当于数值之和%256
(img_cat + img_cat2)[:5,:,0]
cv2.add(img_cat,img_cat2)[:5,:,0] #超过255,越界了,取255
图像融合
只有分辨率大小相同且类型相同的图片才能相加,否则会报错,可以用resize函数更改图像的像素点
img_dog = cv2.resize(img_dog, (500, 414)) #resize函数(w,h)直接更该
res = cv2.resize(img, (0, 0), fx=4, fy=4) #img表示原图像,(w,h)表示输出图像的大小,fx值表示w扩大倍数,fy值表示h扩大倍数,输出为(0,0)时fxy生效
图像融合:
res = cv2.addWeighted(img_cat, 0.4, img_dog, 0.6, 0) #添加权重值公式(x1,α,x2,β,b(偏置项))result=x1*α+x2*β+b
合并后的效果图:
这里的α和β没用范围,皆为双精度,最好相加为1。
总结
本篇文章主要讲述了读取图片和视频的一些操作