1,HSV颜色空间
Hue:色调
Saturation:饱和度
Value:明亮度
2,opencv读取的是BGR,跟我们RGB有区别。需要做一个转换
# 读取图像将图像转换为Matplotlib可视化
# NOTE: 如果需要可视化图像,需要注意:OpenCV中是BGR图像,而Matplotlib中是RGB的图像。
img = cv.imread('t1.png', 1)
img2 = np.zeros_like(img, dtype=img.dtype)
img2[:, :, 0] = img[:, :, 2]
img2[:, :, 1] = img[:, :, 1]
img2[:, :, 2] = img[:, :, 0]
print(img2.shape)
plt.imshow(img2)
plt.show()
3,图像位运算
实际上x进行“非”操作,就是x->-x-1
4,图像的基本处理:
读取,cv.imread('xiaoren.png', 0)
保存,cv.imwrite('t1.png', img)
可视化cv.imshow('image', img)
切割,合并b,g,r = cv.split(img) img = cv.merge((r, g, b))
大小重置 dst = cv.resize(img, (new_width, new_height))
平移,旋转 cv.warpAffine(img,M,shape)通过构造有一个M矩阵来实现
图像模糊化
# 自定义一个kernel核
kernel = np.ones((3,3), np.float32) / 9
# 做一个卷积操作
# 第二个参数为:ddepth,一般为-1,表示不限制,默认值即可。
img2 = cv.filter2D(img, -1, kernel)
均值滤波 dst = cv.blur(img, ksize=(11,11))
高斯滤波 dst = cv.GaussianBlur(img, ksize=(9,9), sigmaX=2.0, sigmaY=2.0)
中值滤波 dst = cv.medianBlur(img, ksize=5)
双边滤波 dst = cv.bilateralFilter(img, d=9, sigmaColor=75, sigmaSpace=75)
添加背景
# 添加背景
# 计算公式:dst = alphe * src1 + beta * src2 + gamma
dst = cv.addWeighted(src1=img1, alpha=0.3, src2=img2, beta=1.0, gamma=0)
添加边框
replicate = cv.copyMakeBorder(img, top=10, bottom=10, left=10, right=10, borderType=cv.BORDER_REPLICATE)
# 边界反射
reflect = cv.copyMakeBorder(img,10,10,10,10,cv.BORDER_REFLECT)
# 边界反射,边界像素不保留
reflect101 = cv.copyMakeBorder(img,10,10,10,10,cv.BORDER_REFLECT_101)
# 边界延伸
wrap = cv.copyMakeBorder(img,10,10,10,10,cv.BORDER_WRAP)
# 添加常数
constant= cv.copyMakeBorder(img,10,10,10,10,cv.BORDER_CONSTANT, value=[128,128,128])
replicate
[1 1 1 1 2 3 3 3 3]
[1 1 1 1 2 3 3 3 3]
[1 1 1 1 2 3 3 3 3]
[1 1 1 1 2 3 3 3 3]
[4 4 4 4 5 6 6 6 6]
[7 7 7 7 8 9 9 9 9]
[7 7 7 7 8 9 9 9 9]
[7 7 7 7 8 9 9 9 9]
[7 7 7 7 8 9 9 9 9]]
reflect
[[9 8 7 7 8 9 9 8 7]
[6 5 4 4 5 6 6 5 4]
[3 2 1 1 2 3 3 2 1]
[3 2 1 1 2 3 3 2 1]
[6 5 4 4 5 6 6 5 4]
[9 8 7 7 8 9 9 8 7]
[9 8 7 7 8 9 9 8 7]
[6 5 4 4 5 6 6 5 4]
[3 2 1 1 2 3 3 2 1]]
reflect101
[[5 6 5 4 5 6 5 4 5]
[8 9 8 7 8 9 8 7 8]
[5 6 5 4 5 6 5 4 5]
[2 3 2 1 2 3 2 1 2]
[5 6 5 4 5 6 5 4 5]
[8 9 8 7 8 9 8 7 8]
[5 6 5 4 5 6 5 4 5]
[2 3 2 1 2 3 2 1 2]
[5 6 5 4 5 6 5 4 5]]
wrap
[[5 6 4 5 6 4 5]
[8 9 7 8 9 7 8]
[2 3 1 2 3 1 2]
[5 6 4 5 6 4 5]
[8 9 7 8 9 7 8]
[2 3 1 2 3 1 2]
[5 6 4 5 6 4 5]]
constant
[[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 1 2 3 0 0]
[0 0 4 5 6 0 0]
[0 0 7 8 9 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]]
5,基于opencv的基本绘画
cv.line画直线、cv.circle画圆、cv.rectangle画矩形、cv.ellipse画椭圆、cv.putText画文字等。常见参数
- img:给定绘画的对象
- color:给定像素点的颜色
- thickness:给定线条粗细程度,-1表示填充图像
- lineType:给定线条的类型
将logo放在图片右上角
import cv2 as cv
import matplotlib.pyplot as plt
# 图像的位运算(将logo放到图像的右上角)
# 加载图像
img1 = cv.imread("xiaoren.png")
img2 = cv.imread("opencv-logo.png")
# 获取一个新数据(右上角区域数据)
rows1, cols1, _ = img1.shape
rows, cols, channels = img2.shape
start_rows = 0
end_rows = rows
start_cols = cols1 - cols
end_cols = cols1
roi = img1[start_rows:end_rows, start_cols:end_cols]
# 将图像转换为灰度图像
img2gray = cv.cvtColor(img2,cv.COLOR_BGR2GRAY)
# 将灰度图像转换为黑白图像,做一个二值化操作
ret, mask = cv.threshold(img2gray, 10, 255, cv.THRESH_BINARY)
# 对图像做一个求反的操作,即255-mask
mask_inv = cv.bitwise_not(mask)
# 获取得到背景图(对应mask_inv为True的时候,进行and操作,其它位置直接设置为0)
# 在求解bitwise_and操作的时候,如果给定mask的时候,只对mask中对应为1的位置进行and操作,其它位置直接设置为0
img1_bg = cv.bitwise_and(roi, roi, mask=mask_inv)
# 获取得到前景图
img2_fg = cv.bitwise_and(img2,img2, mask=mask)
# 前景颜色和背景颜色合并
dst = cv.add(img1_bg,img2_fg)
# 复制粘贴
img1[start_rows:end_rows, start_cols:end_cols] = dst
# 可视化
cv.imshow('res',img1)
cv.waitKey(0)
cv.destroyAllWindows()
6,更改颜色空间
OpenCV中HSV颜色空间的取值范围为:H->[0,179], S->[0,255], V->[0,255]; 其它图像处理软件不一样
# 转换颜色空间
# 加载数据
img = cv.imread('opencv-logo.png')
# 转换为HSV格式
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
# 图像可视化
cv.imshow('image', hsv)
cv.waitKey(0)
cv.destroyAllWindows()
7,形态学转换
腐蚀:去除边缘像素点。减少白色厚度,一般应用于只有黑白像素的灰度情况。cv.erode
扩张/膨胀:增加白色厚度。cv.dilate
open:先做一次腐蚀,再做一次扩张。去除噪音数据 cv.morphologyEx(op=cv.MORPH_OPEN) or cv.erode->cv.dilate
close: 先扩张,在做腐蚀。去除前景中的黑色点 cv.morphologyEx(op=cv.MORPH_CLOSE) or cv.dilate->cv.erode
top hat :原始图像跟open图像之间取差集
black hat:原始图像跟close图像之间取差集
8,图像梯度
通过对图像梯度的操作,可以发现图像的边缘信息
在OpenCV中提供了三种类型的高通滤波器,常见处理方式:Sobel、Scharr以及Laplacian导数
Canny算法是一种比Sobel和Laplacian效果更好的一种边缘检测算法。
非极大值抑制:如果当前像素的梯度强度与另外两个像素相比最大,则该像素点保留为 边缘点,否则该像素点被抑制
双阈值检测:基于阈值来判断是否属于边;即如果像素边缘的梯度值高于 高阈值,则将其标记为强边缘像素,如果像素边缘的梯度值小于 高阈值并且大于低阈值,则将其标记为弱边缘像素,如果像素边 缘的梯度值小于低阈值,则会将其抑制
抑制孤立弱边缘:通过查看弱边缘像素及其周边的八个邻域像素, 主要其中有一个为强边缘像素,则该弱边缘点被保留为真实边缘。 其算法原理是:真实的弱边缘像素一定是连接强边缘像素点的。
9,直方图
OpenCV中的直方图的主要功能是可以查看图像的像素信息
# 加载图像
img = cv.imread('koala.png', 0)
# 两种方式基本结果基本类似
# 基于OpenCV的API计算直方图
hist1 = cv.calcHist([img], channels=[0], mask=None, histSize=[256], ranges=[0,256])
# 基于NumPy计算直方图
hist2, bins = np.histogram(img.ravel(), 256, [0, 256])
# 和np.histogram一样的计算方式,但是效率快10倍
hist3 = np.bincount(img.ravel(), minlength=256)
# 可视化
plt.subplot(131)
plt.imshow(img, 'gray')
plt.title('Original Image')
plt.subplot(132)
plt.plot(hist3)
plt.title('Hist')
plt.subplot(133)
# 可以直接使用matpliab中的hist API直接画直方图
plt.hist(img.ravel(), 256, [0, 256])
plt.title('Hist2')
plt.show()
直方图均衡化:如果某一个图像的像素仅限制于某个特定的范围,但是实际上一个比较好的图像像素点应该是在某一个范围内,所以需要将像素的直方图做一个拉伸的操作;比如:一个偏暗的图像,像素基本上都在较小的位置,如果将像素值增大,不就可以让图像变亮嘛!实际上,直方图均衡化操作是一个提高图像对比度的方式
人脸识别
# 加载定义好的人脸以及眼睛信息匹配信息
face_cascade = cv.CascadeClassifier('haarcascade_frontalface_default.xml')
eye_cascade = cv.CascadeClassifier('haarcascade_eye.xml')
# 加载图像
img = cv.imread('faces2.png')
# 转换为灰度图像
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 检测图像
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
# 画人脸区域
cv.rectangle(img, (x,y), (x+w, y+h), (255,0,0), 2)
# 获得人脸区域
roi_gray = gray[y:y+h, x:x+w]
roi_img = img[y:y+h, x:x+w]
# 检测眼睛
eyes = eye_cascade.detectMultiScale(roi_gray)
for (ex, ey, ew, eh) in eyes:
# 画眼睛
cv.rectangle(roi_img, (ex,ey), (ex+ew, ey+eh), (0,0,255), 2)
# 可视化
cv.imshow('img', img)
cv.waitKey(0)
cv.destroyAllWindows()