OpenCV 图像的基本处理
- 最近因项目需要加上自己的兴趣,需要用一些opencv相关的东西,虽然之前零零碎碎学习过一些,但是很久不用就忘了,打算写篇文章总结一下学习的过程以及一些常用的函数。类似的博文有很多,但还是觉得自己总结一编印象深一些。
1.1 图片读取和显示
读取:cv.imread(“图片路径”, “读取的方式”)
显示:cv.imshow(“窗口名称”, “图片数据”)
- 读取方式: 分别有如下三种:
cv.IMREAD_COLOR : 以彩图的方式加载,会忽略透明度(默认方式)
cv.IMREAD_GRAYSCALE: 以灰色图片方式加载
cv.IMREAD_UNCHANGED: 直接加载,透明度会得到保留
例:
import cv2 as cv
# 读取图片 参数1:图片路径, 参数2:读取的方式
img = cv.imread("img/lena.png", cv.IMREAD_COLOR)
# 显示窗口 参数1:窗口名称, 参数2:图片数据
cv.imshow("src", img)
# 让程序处于等待推出状态
cv.waitKey(0)
# 当程序推出时,释放所有窗口资源
cv.destroyAllWindows()
1.2 写入文件(保存)
import cv2 as cv
img = cv.imread("img/lena.png", cv.IMREAD_UNCHANGED)
# 将图片写入到磁盘中,参数1: 图片写入路径,参数2: 图片数据
cv.imwrite("img/lena_copy.png", img)
cv.waitKey(0)
cv.destroyAllWindows()
1.3 像素操作
import cv2 as cv
import numpy as np
# 构建一个空白的矩阵
img = np.zeros((30, 40, 3), np.uint8)
# 将第15行所有像素点全都改成红色
for i in range(40):
# 设置第15行颜色为红色
img[15, i] = (0, 0, 255)
# 显示图片
cv.imshow("src", img)
cv.waitKey(0)
cv.destroyAllWindows()
1.4 图片剪切
剪切:mat[起始行号:结束行号,开始列号:结束列号]
import cv2 as cv
# 读取原图
img = cv.imread("img/lena.jpg", cv.IMREAD_COLOR)
cv.imshow("source", img)
# 从图片(230,230) 截取一张 宽度130,高度70的图片
dstimg = img[180:250, 180:310]
# 显示图片
cv.imshow("result", dstimg)
cv.waitKey(0)
1.5 镜像处理:
获取宽高信息:
imgInfo = img.shape
imgInfo[0] : 表示高度
imgInfo[1] : 表示宽度
imgInfo[2] : 表示每个像素点由几个颜色值构成
实现步骤:
- 创建一个两倍于原图的空白矩阵
- 将图像的数据按照从前向后,从后向前进行绘制
import cv2 as cv
import numpy as np
# 创建两倍原图的大小的画布出来
img = cv.imread("../img/lena.jpg")
# 获取图像尺寸
print img.shape
height = img.shape[0]
width = img.shape[1]
print height, width
dst = np.zeros((height * 2, width, 3), np.uint8)
for row in range(height):
for col in range(width):
dst[row, col] = img[row, col]
dst[height*2 - row - 1, col] = img[row, col]
cv.imshow("img", img)
cv.imshow("dst", dst)
cv.waitKey(0)
1.6 图像缩放
关于图片的缩放,常用有两种:
- 等比例缩放
- 任意比例缩放
图片缩放的常见算法:
- 最近领域插值
- 双线性插值
- 像素关系重采样
- 立方插值
默认使用的是双线性插值法,可以利用opencv提供的 resize
方法来进行图片的缩放
import cv2 as cv
img = cv.imread("../img/lena.jpg")
cv.imshow("src", img)
height = img.shape[0]
width = img.shape[1]
dst = cv.resize(img, (height*2, width*2))
cv.imshow("dst", dst)
cv.waitKey()
1.7 图像位移
矩阵运算:cv.warpAffine(原始图像,变换矩阵,(高度,宽度))
import cv2 as cv
import numpy as np
img = cv.imread("../img/lena.jpg")
height, width = img.shape[0:2]
# 图像的位移
matrixShift = np.float32([[1, 0, 50], [0, 1, 100], ])
# 图像矩阵运算
dst = cv.warpAffine(img, matrixShift, (width, height))
cv.imshow("dst", dst)
cv.waitKey()
1.8 图像旋转
旋转变换:cv.getRotationMatrix2D((旋转中心),旋转角度,缩放系数)
import cv2 as cv
img = cv.imread("../img/lena.jpg")
height, width = img.shape[0:2]
# 1.旋转中心, 2.旋转角度, 3. 缩放系数
M = cv.getRotationMatrix2D((width/2, height/2), 45, 0.5);
# 图像矩阵运算
dst = cv.warpAffine(img, M, (width, height));
cv.imshow("dst", dst)
cv.waitKey()
1.9 仿射变换
import cv2 as cv
import numpy as np
img = cv.imread("../img/itheima.jpg")
height, width = img.shape[0:2]
# 定义变换的参考点: 左上角,左下角,右上角
matrixSrc = np.float32([[0, 0], [0, height-1], [width-1, 0]]);
# 将上述三个点映射到一个新的坐标系中
matrixDst = np.float32([[50, 100], [300, height-200], [width-300,100]]);
# 计算从Src到Dst的变换矩阵
M = cv.getAffineTransform(matrixSrc, matrixDst);
# 仿射变换
dst = cv.warpAffine(img, M, (width, height))
cv.imshow("src", img)
cv.imshow("dst", dst)
cv.waitKey()
1.10 图像融合
import cv2 as cv
import numpy as np
src = cv.imread("../img/itheima.jpg")
tony = cv.imread("../img/tony.jpg")
dst = cv.addWeighted(src, 0.5, tony, 0.5, 100)
cv.imshow("src", src)
cv.imshow("tony", tony)
cv.imshow("dst", dst)
cv.waitKey()
1.11 灰度处理
import cv2 as cv
# 方式一 : 直接以灰度图像的形式读取
img = cv.imread("img/itheima.jpg", cv.IMREAD_GRAYSCALE)
cv.imshow("dstImg", img)
cv.waitKey(0)
# 方式二: 以彩图的方式读取
img = cv.imread("img/itheima.jpg", cv.IMREAD_COLOR)
# 将原图的所有颜色转成灰色
dstImg = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
cv.imshow("dstImg", dstImg)
cv.waitKey(0)
原理演示
import cv2 as cv
import numpy as np
src = cv.imread("../img/lena.jpg")
height, width = src.shape[0:2]
# 创建一个画布 0-255 + 0-255
dst = np.zeros((height, width, 1), np.uint8)
for row in range(height):
for col in range(width):
b, g, r = src[row, col]
# gray = (int(b) + int(g) + int(r))/3
# 0.299∗color.r + 0.587∗color.g + 0.114∗color.b
gray = int(b) * 0.114 + int(g) * 0.587 + int(r) * 0.299
# 将计算出来的灰度值填充到画布中
dst[row, col] = gray
cv.imshow("dst", dst)
cv.waitKey()
1.12 颜色反转
- 灰图反转
import cv2 as cv
import numpy as np
src = cv.imread("../img/itheima.jpg")
height, width = src.shape[0:2]
grayImg = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
cv.imshow("gray1", grayImg)
# 100 ---> 255 - 100 = 155
for row in range(height):
for col in range(width):
value = grayImg[row, col]
grayImg[row, col] = 255 - value
cv.imshow("gray2", grayImg)
cv.imshow("src", src)
cv.waitKey()
- 彩图反转
import cv2 as cv
import numpy as np
src = cv.imread("../img/itheima.jpg")
height, width = src.shape[0:2]
# 创建画布
dst = np.zeros_like(src)
for row in range(height):
for col in range(width):
b, g, r = src[row, col]
dst[row, col] = (255-b, 255-g, 255-r)
cv.imshow("src", src)
cv.imshow("dst", dst)
cv.waitKey()
1.13 马赛克
import cv2 as cv
import numpy as np
src = cv.imread('../img/itheima.jpg')
height, width = src.shape[0:2]
# 将图像划分成若干个4*4的小方块,
# 每一个小方块里面的所有像素值修改为和第一个像素块的颜色一样
offset = 10
for row in range(160, 240):
for col in range(380, 670):
# 将图像划分成若干个4*4的小方块,
if row%offset == 0 and col%offset == 0:
# 获取当前位置的颜色快
color = src[row, col]
# 每一个小方块里面的所有像素值修改为和第一个像素块的颜色一样
for i in range(offset):
for j in range(offset):
src[row+i, col+j] = color
cv.imshow("src", src)
cv.waitKey()
1.14 毛玻璃
import cv2 as cv
import numpy as np
import random
src = cv.imread("../img/itheima.jpg")
height, width = src.shape[0:2]
offset = 10
# 创建一个和原图同样大小的画布
dst = np.zeros_like(src)
# 处理每一个像素
for row in range(height):
for col in range(width):
# 计算当前位置,周围的一个随机数
# index = random.randint(0,offset);
# 随机的行号
randomRow = row + random.randint(0, offset)
# 随机的列号
randomCol = col + random.randint(0, offset)
if randomRow > height - 1:
randomRow = height - 1
if randomCol > width - 1:
randomCol = width - 1
# 获取随机的周围颜色值
color = src[randomRow, randomCol]
# 填充到画布中
dst[row, col] = color
cv.imshow("dst", dst)
cv.imshow("src", src)
cv.waitKey()
1.15 浮雕效果
import cv2 as cv
import numpy as np
src = cv.imread("../img/itheima.jpg")
# 将彩图转成灰度图
grayImg = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
height, width = src.shape[0:2]
# 创建一个空白的矩阵 , 画布
dst = np.zeros_like(grayImg)
for row in range(height):
for col in range(width - 1):
# 计算相邻两个像素的差值 , 水平方向
gray0 = grayImg[row, col]
gray1 = grayImg[row, col+1]
# 计算相邻像素的梯度 uint8 0-255
value = int(gray0) - int(gray1) + 120
if value < 0:
value = -value
# 将计算出来的值填充一个新的画布中
dst[row, col] = value
cv.imshow("src", src)
cv.imshow("dst", dst)
cv.imshow("gray", grayImg)
cv.waitKey()
1.16 图形绘制
import cv2 as cv
import numpy as np
src = np.zeros((400, 600, 3), np.uint8)
pt1 = (200, 100)
pt2 = (300, 200)
color = (255, 255, 0)
# 绘制线段 参数2:起始点 参数3:结束点 参数4:颜色 参数5:线条宽度
cv.line(src, pt1, pt2, color, 2) # 图,zuoshang, youxia, yanse, xiankuan
# 绘制一个矩形 参数2:左上角 参数3:右下角 参数4:颜色 参数5:线条宽度,若为负数,则填充整个矩形
cv.rectangle(src, pt1, pt2, color, 1)
# 绘制圆形 参数2:圆心 参数3:半径 参数4:颜色 参数5:线条宽度,若为负数,则填充整个圆形
cv.circle(src, (400, 200), 50, color, -1)
# 绘制文字 参数2:文字内容 参数3:文字起始左下点
cv.putText(src, "hello", (200, 100), cv.FONT_HERSHEY_SIMPLEX, 2, (255, 0, 255), 2)
# 显示图片
cv.imshow("src", src)
cv.waitKey()
1.17 亮度增强
import cv2 as cv
import matplotlib.pyplot as plt
src = cv.imread("../img/itheima.jpg")
height, width = src.shape[0:2]
offset = 90
cv.imshow("src1", src)
for row in range(height):
for col in range(width):
b, g, r = src[row, col]
# 增加亮度
b = b + offset
g = g + offset
r = r + offset
if b > 255: b = 255
if g > 255: g = 255
if r > 255: r = 255
src[row,col] = (b,g,r)
cv.imshow("src2", src)
# 计算图像直方图
hist = cv.calcHist([src], [0], None, [256], [0, 255])
print hist
plt.plot(hist)
plt.show()
cv.waitKey()
1.18 直方图均衡化
直方图:cv.calcHist(图片,通道,掩膜,数量,值的范围)
直方图均衡化:cv.equalizeHist
import cv2 as cv
import matplotlib.pyplot as plt
src = cv.imread("../img/itheima.jpg")
cv.imshow("src", src)
# 将彩色图像拆成3层灰度图像: B通道 G通道 R通道
channels = cv.split(src)
channel_B = cv.equalizeHist(channels[0])
channel_G = cv.equalizeHist(channels[1])
channel_R = cv.equalizeHist(channels[2])
# 将三个通道的结果合并在一起
dst = cv.merge([channel_B, channel_G, channel_R])
cv.imshow("dst", dst)
cv.waitKey()
1.19 视频处理
视频:cv.VideoCapture(路径)
import cv2 as cv
import matplotlib.pyplot as plt
capture = cv.VideoCapture("../img/vtest.avi")
print capture.isOpened()
# 获取视频的信息
height = capture.get(cv.CAP_PROP_FRAME_HEIGHT)
width = capture.get(cv.CAP_PROP_FRAME_WIDTH)
# 获取视频的帧率: 1s 切换图片的数量
fps = capture.get(cv.CAP_PROP_FPS)
print("height={}, width={}, fps={}".format(height, width, fps))
# 读视频数据
ok, frame = capture.read()
while ok:
cv.imshow("frame", frame)
ok, frame = capture.read()
# 彩色图像直方图均衡化
channels = cv.split(frame)
channel_B = cv.equalizeHist(channels[0])
channel_G = cv.equalizeHist(channels[1])
channel_R = cv.equalizeHist(channels[2])
# 将三个通道的结果合并在一起
dst = cv.merge([channel_B, channel_G, channel_R])
cv.imshow("dst", dst)
cv.waitKey(int(1000/fps))
1.20 HSV颜色空间
将RGB图像转成HSV图像
hsv = cv.cvtColor(rgb, cv.COLOR_BGR2HSV)
1.21 阈值处理
所使用的阈值,结果图片 = cv.threshold(img,阈值,最大值,类型)
代码示例:
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
def onChange(value):
_, binary = cv.threshold(car, value, 255, cv.THRESH_BINARY_INV) # 第一个值空,_INV反转颜色
cv.imshow("binary", binary)
car = cv.imread("../img/car.jpg", cv.IMREAD_GRAYSCALE)
onChange(0)
# 增加滑动条
cv.createTrackbar("thresh", "binary", 0, 255, onChange) # 变量名字,窗口名字,min,max,回调函数
cv.imshow("car", car)
cv.waitKey(0)
1.22 人脸识别
核心API:
# 加载已经训练好的特征文件
face_classifier = cv.CascadeClassifier("/haarcascade_frontalface_default.xml")
# 根据特征文件去查找人脸
face_classifier.detectMultiScale(图像, 缩放系数, 至少检验次数)
实现步骤:
- 加载特征xml文件
- 加载图片
- 灰度处理
- 判决
- 绘制出检测出来的人脸
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
# 第1步:加载xml文件
face_classifier = cv.CascadeClassifier("../img/haarcascade_frontalface_default.xml")
eye_classifier = cv.CascadeClassifier("../img/haarcascade_eye.xml")
# 第2步:加载图片
lena = cv.imread("../img/lena.jpg")
# 第3步:将图片转成灰色图片
lena_gray = cv.cvtColor(lena, cv.COLOR_BGR2GRAY)
# 第4步:使用api进行人脸识别 参数2:缩放系数 参数3:至少要检测几次才算正确
faces = face_classifier.detectMultiScale(lena_gray, 1.3, 3)
print faces # 返回值:左上点的x,y,宽w,高h
# 第5步:在人脸上绘制矩形
for x, y, w, h in faces:
# 从灰色图片中找到人脸
grayFace = lena_gray[y:y+h, x:x+w]
colorFace = lena[y:y+h, x:x+w]
# 在当前人脸上找到眼睛的位置
eyes = eye_classifier.detectMultiScale(grayFace, 1.2, 5)
# 在找到人脸上画矩形
cv.rectangle(lena, (x, y), (x+w, y+h), (0, 0, 255), 2)
# 在眼睛上绘制矩形
for eye_x, eye_y, eye_w, eye_h in eyes:
cv.rectangle(colorFace, (eye_x, eye_y), (eye_x+eye_w, eye_y+eye_h), (0, 255, 255), 2)
cv.imshow("src", lena)
cv.waitKey()
识别结果如下: