图像基本操作
在获取图像后 首先需要知道一些处理图像的基本操作 如图像颜色的分离,像素的改变,图像的拉伸和旋转,以及在图像上添加一些基础文字和图形
颜色空间
在数字图像中,通过红绿蓝3三种颜色混合可以展现各种颜色,这种颜色被称为RGB颜色空间,RGB是常见的颜色空间,常用于表示和显示图像,为了表示3种
颜色的混合,图像使用多通道的形式分别存储某颜色的分量,红色,绿色,蓝色。除了RGB颜色空间外,图像还有YUV,HSV,GRAY等。
颜色空间和转换:
RGB颜色空间,对应通道1蓝色,通道2绿色,通道3红色。
在RGB颜色空间种,3个通道对颜色的描述范围是相同的,因此RGB颜色空间可以表示为一个立方体。
在RGB颜色空间中,所有的颜色都是由这几个颜色混合得到。若都为0则表示为黑色
若都为最大值 则为白色,对于uint8的图像,通道将其量化为256个等级。
在三个颜色空间基础上,增加第四个通道,则得到RGBA颜色空间,第四个通道表示透明度
HSV颜色空间,由色调,饱和度,亮度三个术语的首字母组成
色调是色彩的基本属性,就是平时所说的颜色,色相可以表示为一个0-360°的圆心角
饱和度是指颜色的纯度,饱和度越高,色彩越纯,越艳丽
亮度是颜色的明亮程度
由于其取值范围不同,所以,HSV用圆锥表示。
RGB颜色空间中存在的三个颜色分量和最终颜色联系不直观,而HSV更加符合人类感知颜色的方式。
GARY颜色空间是一个关于灰度图像的颜色空间,其仅有一个通道灰度由0到最大,分别代表了由黑到白
转换:
OpenCV 4提供了cv.cvtColor() 函数来进行不同颜色空间间的转换
dst = cv.cvtColor(src,code,[,dst[,dstCn]])
src: 带转换的原始图像
code: 颜色空间转换的标志
dst: 颜色空间转换后的目标图像
由于不同的数据类型的范围不同:
所以在类型转换前应该观察是否要进行提前归一化
如 uint8(0-255) --》 float(0-1)
要提前先对uint8 /255
cv.COLOR_BGR2BGRA 添加alpha通道
cv.COLOR_BGR2RGB BGR转为RGB
cv.COLOR_BGR2GRAY BGR转为GRAY
cv.COLOR_BGR2HSV BGR转为HSV
import cv2 as cv
import numpy as np
img = cv.imread('preview.jpg')
if img is None:
print('没读进')
exit()
cv.imshow('1', img)
print(img.shape)
img2 = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
cv.imshow('2', img2)
print(img2.shape)
img3 = cv.cvtColor(img, cv.COLOR_BGR2HSV)
cv.imshow('3', img3)
print(img3.shape)
img4 = cv.cvtColor(img, cv.COLOR_BGR2RGB)
cv.imshow('4',img4)
print(img4.shape)
cv.waitKey(0)
cv.destroyAllWindows()
通道分离和合并:
在颜色空间中,不同的分量存放在不同的通道中,若我们仅仅需要其中的一个分离,则可以将该通道从三通道数据中分离出来再处理。
这种方式可以减少数据占用的内存,加快程序的运行速度。同时,我们将处理完的通道再合并在一起重新生成RGB图像
所以,若要利用numpy切出一个通道,则要
img[:,:,0],可以对照图来进行比对 ,先行,再列,最后通道
在分离通道方面,根据实验,使用numpy比直接使用opencv的速度要快100多倍
这里将介绍opencv自带函数的分离和合并
分离函数:
mv = cv.split(m,[, mv])
mv: 分离后的单通道图像
m: 待分离的多通道图像
mv是一个列表,可以使用解压赋值进行获得
b,g,r
合并函数:
dst = cv.merge(mv,[, dst])
dst = cv.merge([b,g,r])
mv: 需要合并的图像
dst: 合并后输出的图像
接下来的内容将面向着每个通道内像素来进行
图像像素操作:
1.图像像素统计:
minval,maxval,minloc,maxloc = cv.minMaxLoc(src,[,mask]) # 寻找图像像素最大最小值
minval: 最小值
maxval: 最大值
minloc: 最小值坐标
maxloc: 最大值坐标
src: 图片,必须为单通道图片
mask:掩膜, 用于指定寻找范围 默认为None
若存在多个最大位置,则会得到由左到右扫描的第一个
图像的均值表示图像整体的亮暗程度,图像均值越大,图像整体越亮
标准差表示了图像的明暗变换程度,标准差越大,变化越明显
retval = cv.mean(src)
该函数用来求每个通道的均值,将计算结果放在一个长度为4的元组并返回
每个值代表对应通道的均值,若没有该通道,则返回0
mean,stddev = cv.meanStdDev(src)
mean : 返回每个通道的均值
stddev : 返回每个通道的标准差
该函数用于同时求每个通道的均值和标准差
2.两图像间的像素操作
求取两幅图像中较大的或者较小的灰度值
dst = cv.max(src1,src2)
dst = cv.min(src1,src2)
src1 和 src2 维度大小通道必须相同
dst: 保留对应位置较大或者较小的灰度值后的图像,尺寸,通道数和原图像一致
图像二值化 (重要)
当图像为非黑及白仅仅两种灰度值的情况下,此图像称为二值图像
二值图像的色彩种类很少,可以进行高度压缩
将非二值化图像经过计算变为二值图像的过程叫做图像的二值化或者阈值化
给出了两个函数进行二值化:
retval,dst = cv.threshold(src,thresh,maxval,type,[,dst])
src: 待二值化图像
thresh: 二值化阀值
maxval: 二值化过程中的1最大值
type: 选择二值化方法的标志
dst: 二值化后的图像
retval: 返回阈值
该方法是二值化方法的集成,所有方法都实现了一个功能
就是通过给定阀门并计算灰度值和这个阀门的关系
该方法中的阀值有些不是二值的,而是一个取值范围
type:
THRESH_BINARY: 若灰度值大于阀值,则取最大值,其他取0
THRESH_BINARY_INV: 若灰度值大于阀值,则取0,其他取最大值
将灰度值改为maxval参数
THRESH_TRUNC: 若灰度值大于阀值,则取阀门,其他取0
THRESH_TOZERO: 若灰度值大于阀值,不变,对其他值,取0
THRESH_BINARY_INV: 若灰度值大于阀值,则取0,其他取最大值
THRESH_OTSU: 使用大律法自动寻求全局阈值
THRESH_TRIANGLE: 使用三角形法自动寻求全局阈值
import cv2 as cv
import numpy as np
import sys
if __name__ == '__main__':
img = cv.imread('preview.jpg')
if img is None:
print('读取失败')
sys.exit()
b_img = img[:,:,0]
retval, dst_b_img = cv.threshold(b_img, 100, 255, cv.THRESH_BINARY)
print(b_img)
print(dst_b_img)
print(retval)
cv.imshow('dst', dst_b_img)
cv.waitKey(0)
cv.destroyAllWindows()
dst = cv.adaptiveThreshold(src,maxval,adaptiveMethod,thresholdType,blockSize,C,[, dst])
src: 待二值化图片
maxval: 二值化后的最大值
adaptiveMethod: 自适应确定阈值方法, cv.ADAPTIVE_THRESH_MEAN_C 均值法 cv.ADAPTIVE_THRESH_GAUSSIAN_C 高斯法
thresholdType: 选择图像二值化方法 只能是THRESH_BINARY 和 THRESH_BINARY_INV
blockSize: 自适应确定阈值的像素领域大小 一般为3 5 7
C:从平均值或者加权平均值减去的常数
dst 二值化的图像
cv.adaptiveThreshold() 可以将灰度图转为二值化图像 并且自适应计算领域内阈值
为多阈值
之前介绍的阈值比较方法中只有一个阈值,若需要多阈值比较,就要进行查表(LUT)。
简单来说,LUT就是一个灰度映射表,以灰度为索引,以灰度映射后内容为表内内容
dst = cv.LUT(src,lut,[,dst])
src: 输入图像
lut: 256个灰度值的查找表 一个1 * 256 的矩阵
dst: 输出图像
图像连接和变换
在日常生活中,常常要提交规定尺寸的照片,并且一些算法也需要输入规定尺寸的图片。接下来将介绍图像的形状变换
1.图像连接
图像连接指将连个宽度或者高度相同的图像拼接在一起
dst = cv.vconcat(src,[, dst])
src: 需要连接的图像
dst: 连接后的图像
该函数为垂直方向进行连接
dst = cv.vconcat((A,B))
dst = cv.hconcat(src,[, dst])
该函数为水平方向进行连接
cv.namedWindow('dst1',cv.WINDOW_FREERATIO)
cv.namedWindow('dst2',cv.WINDOW_FREERATIO)
if __name__ == '__main__':
img = cv.imread('preview.jpg')
if img is None:
print('读取失败')
sys.exit()
b_img = img[:, :, 0]
g_img = img[:, :, 1]
dst1 = cv.vconcat((b_img, g_img))
dst2 = cv.hconcat((b_img, g_img))
cv.imshow('dst1', dst1)
cv.imshow('dst2', dst2)
cv.waitKey(0)
cv.destroyAllWindows()
2.图像尺寸变换
dst = cv.resize(src,dsize,fx,fy,type)
dsize: 输入图像
type: 表示图像插值方式
fx: 将图像按x轴放大或缩小
fy: 将图像按y轴放大或缩小
cv.INTER_CUBIC 放大图像效果较好
cv.INTER_AREA 缩小图像效果较好
dst = cv.resize(b_img, (500, 500), cv.INTER_AREA)
3.图像进行翻转变换
dst = cv.flip(src,filpCode,[,dst])
flipCode: 翻转方式的标志,若大于0 为绕y翻转, 等于0 绕x轴翻转 小于0 绕两轴翻转
4.图像仿射变换(图像的旋转,平移,缩放操作的统称)
pass
5.图像透视变换
透视变换是按照物体成像投影规律进行变换,及将物体重新投影在新的成像平面上
通常用于机器人视觉导航,可以实现相机因角度产生的畸变的矫正
变换前和变换后的关系可以通过一个变换矩阵来表示
根据四个点求取变换矩阵
retval = cv.getPerspectiveTransform(src,dst,[,solveMethod])
src 原图像中的4个像素的坐标
dst 目标图像中的4个像素坐标
solveMethon 变换的方法标志 默认情况下会选择高斯消元法
src np.array([[x,y],[x,y],[x,y],[x,y]])
根据变换矩阵进行透视变化
dst = cv.warpPerspective(src,M,dsize,[])
M: 变换矩阵
dsize: 输出图像的尺寸
应用: 将不是垂直拍摄的二维码的角点转为垂直拍摄的二维码
6.极坐标变换
将图像由直角坐标变为极坐标中,可以将圆形图像变为矩形图像。
圆形图案边缘上的文字经过极坐标变换后,可以垂直的排列在新图像的边缘,便于文字的识别和检测
dst = cv.warpPolar(src,dsize,center,maxRadius,flags)
src: 原图像
dsize: 目标图像大小
center: 极坐标变换时 极坐标在原图像中的原点
maxRadius: 变换时边界圆半径
flags: 插值方法和极坐标映射方法 cv.WARP_POLAR_LINEAR 极坐标变换 cv.WARP_INVERSE_MAP 逆变换
img_res = cv.warpPolar(img,(300,600),center,center(0),cv.INTER_LINEAR + cv.WARP_POLAR_LINEAR)