OpenCV概述与安装
视觉概述
人类的视觉能够很轻易地从图像中识别出内容。但是,计算机视觉不会像人类视觉那样能够对图像进行感知和识别,更不会自动控制焦距和光圈,而是把图像解析为按照栅格状排列的数字。
这些按照栅格状排列的数字包含大量的噪声,噪声在图像上常表现为引起较强视觉效果的孤立像素点或像素块,使得图像模糊不清。因此,噪声是计算机视觉面临的一个难题。要想让图片变得清晰,就需要对抗噪声。
计算机视觉使用统计的方法对抗噪声,例如,计算机视觉虽然很难通过某个像素或者这个像素的相邻像素判断这个像素是否在图像主体的边缘上,但是如果对图像某一区域内的像素做统计,那么上述判断就变得简单了,即在指定区域内,图像主体的边缘应该表现为一连串独立的像素,而且这一连串像素的方向应该是一致的。
OpenCV常用模块
模块 | 介绍 |
---|---|
Core | 包函OpenCV库的基础结构以及基本操作 |
Improc | 包函基本的图像转换,包括滤波、卷积 |
Highgui | 轻量级的UI工具包 |
Video | 读写视频流的方法 |
Calib3d | 校准单个、双目以及多个相机的算法实现 |
Feature2d | 检测、描述、匹配特征点算法 |
Objecttect | 检测待定目标的算法 |
ML | 包含大量机器学习算法 |
Flann | 多维空间的聚类和搜索 |
GPU | 包含在CUDA GPU上优化实现的方法 |
Photo | 计算机摄影学的一些方法 |
Stitching | 图像拼接流程的实现 |
dnn | 深度神经网络模块 |
安装
安装Python这里我使用的是Anaconda
-
创建虚拟环境
conda create --name 环境名称 python=3.8
-
进入环境
activate 环境名称
-
修改源
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/ -
查看源如下图既可
conda config --show channels
-
安装需要的依赖
pip install numpy pandas matplotlib opencv-python
-
查看是否安装成功
pip list
-
测试一下是否安装成功
准备一张图片 这里我命名为image.jpg
import cv2 image = cv2.imread("image.jpg") print(image)
输出类似如下:
OpenCV基础-图像数字化
读取图像:
# 获取彩色图像
image = cv2.imread("image.jpg")
方法 | 作用 |
---|---|
image.shape | (垂直像素,水平像素,通道数) |
image.size | 图像包含的像素个数 |
image.dtype | 数据类型 |
获取某一像素的RGB值:
print(image[231, 128])
# B通道
print(image[231, 128, 0])
# G通道
print(image[231, 128, 1])
# R通道
print(image[231, 128, 2])
输出:
[59 72 46]
59
72
46
即坐标[231, 128]上的像素的RGB值由[59 72 46]组成
拆分通道:
image = cv2.imread("image.jpg")
cv2.imshow("image", image)
b, g, r = cv2.split(image)
cv2.imshow("B", b) # 显示B通道图像
cv2.imshow("G", g) # 显示G通道图像
cv2.imshow("R", r) # 显示R通道图像
合并通道:
image = cv2.imread("image.jpg")
b, g, r = cv2.split(image)
rgb = cv2.merge([r, g, b]) # 按R→G→B顺序合并
cv2.imshow("RGB", rgb)
创建纯黑色的图像:
width = 800
height = 600
img = np.zeros((height, width), np.uint8)
cv2.imshow("img", img)
拼接图像:
image1 = cv2.imread("image1.jpg")
image2 = cv2.imread("image2.jpg")
# 水平拼接两个图像
img_h = np.hstack((image1, image2))
# 垂直拼接两个图像
img_v = np.vstack((image1, image2))
cv2.imshow("img_h", img_h)
cv2.imshow("img_v", img_v)
使用OpenCV绘制图形
绘制黄色的线:
# 绘制一个黑色的背景画布
canvas = np.zeros((300, 300, 3), np.uint8)
# 在画布上,绘制一条起点坐标为(150, 50)、终点坐标为(150, 250),黄色的,线条宽度为20的线段
canvas = cv2.line(canvas, (150, 50), (150, 250), (0, 255, 255), 20)
绘制矩形:
# 在画布上绘制一个左上角坐标为(65,65),右下角坐标为(180,150),青色的,线条宽度为20的矩形边框
canvas = cv2.rectangle(canvas, (65, 65), (200, 150), (255, 255, 0), 20)
绘制圆形:
# 在画布上,绘制一个圆心坐标为(150, 50),半径为40,黄色的实心圆形
canvas = cv2.circle(canvas, (150, 50), 40, (0, 255, 255), -1)
绘制多边形:
# 根据坐标[100, 50], [200, 50], [250, 250], [50, 250],绘制一个闭合的,红色的,线条宽度为5的等腰梯形边框
canvas = cv2.polylines(canvas, [np.array([[100, 50], [200, 50], [250, 250], [50, 250]], np.int32)], True, (0, 0, 255), 5)
绘制文字:
# 字体大小为2,线条颜色是绿色,线条宽度为5
cv2.putText(canvas, "Hello World", (20, 70), cv2.FONT_HERSHEY_TRIPLEX, 2, (0, 255, 0), 5)
OpenCV图像变换
图像缩放:
img = cv2.imread("image.png")
# 宽100像素、高100像素的大小进行缩放
dst = cv2.resize(img, (100, 100))
按比例缩放:
# 将宽缩小到原来的1/3、高缩小到原来的1/2
dst = cv2.resize(img, None, fx=1 / 3, fy=1 / 2)
# 将宽高扩大2倍
dst = cv2.resize(img, None, fx=2, fy=2)
图像翻转:
沿X轴翻转:
dst1 = cv2.flip(img, 0)
沿Y轴翻转:
dst2 = cv2.flip(img, 1)
同时沿X轴、Y轴翻转:
dst3 = cv2.flip(img, -1)
图像旋转:
# 图像像素行数
rows = len(img)
# 图像像素列数
cols = len(img[0])
# 图像的中心点
center = (rows / 2, cols / 2)
# 以图像为中心,逆时针旋转30度,缩放0.8倍
M = cv2.getRotationMatrix2D(center, 30, 0.8)
dst = cv2.warpAffine(img, M, (cols, rows))
OpenCv图形检测
绘制图像轮廓:
img = cv2.imread("image.png")
# 彩色图像转为变成单通道灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 灰度图像转为二值图像
t, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 检测图像中出现的所有轮廓,记录轮廓的每一个点
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
# 绘制所有轮廓,宽度为5,颜色为红色
cv2.drawContours(img, contours, -1, (0, 0, 255), 5)
为轮廓添加矩形框:
# 获取第一个轮廓的最小矩形边框,记录坐标和宽高
x, y, w, h = cv2.boundingRect(contours[0])
# 绘制红色矩形
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)
为轮廓添加圆形框:
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# 获取最小圆形边框的圆心点和半径
center, radius = cv2.minEnclosingCircle(contours[0])
# 圆心点横坐标转为近似整数
x = int(round(center[0]))
# 圆心点纵坐标转为近似整数
y = int(round(center[1]))
cv2.circle(img, (x, y), int(radius), (0, 0, 255), 2)
Canny边缘检测:
img = cv2.imread("image.png")
r1 = cv2.Canny(img, 10, 50)
直线检测:
img = cv2.imread("image.jpg")
# 复制原图
o = img.copy()
# 使用中值滤波进行降噪
o = cv2.medianBlur(o, 5)
gray = cv2.cvtColor(o, cv2.COLOR_BGR2GRAY)
binary = cv2.Canny(o, 50, 150) # 绘制边缘图像
# 检测直线,精度为1,全角度,阈值为15,线段最短100,最小间隔为18
lines = cv2.HoughLinesP(binary, 1, np.pi / 180, 15, minLineLength=100, maxLineGap=18)
for line in lines: # 遍历所有直线
x1, y1, x2, y2 = line[0] # 读取直线两个端点的坐标
cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2) # 在原始图像上绘制直线
圆环检测:
img = cv2.imread("image.jpg")
o = img.copy()
o = cv2.medianBlur(o, 5)
gray = cv2.cvtColor(o, cv2.COLOR_BGR2GRAY) # 从彩色图像变成单通道灰度图像
# 检测圆环,圆心最小间距为70,Canny最大阈值为100,投票数超过25。最小半径为10,最大半径为50
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 70, param1=100, param2=25, minRadius=10, maxRadius=50)
circles = np.uint(np.around(circles)) # 将数组元素四舍五入成整数
for c in circles[0]: # 遍历圆环结果
x, y, r = c # 圆心横坐标、纵坐标和圆半径
# 绘制圆环
cv2.circle(img, (x, y), r, (0, 0, 255), 3)
# 绘制圆心
cv2.circle(img, (x, y), 2, (0, 0, 255), 3)
OpenCV处理视频
开启摄像头:
import cv2
# 打开笔记本内置摄像头
capture = cv2.VideoCapture(0)
while (capture.isOpened()):
# 从摄像头中实时读取视频
retval, image = capture.read()
# 在窗口中显示读取到的视频
cv2.imshow("Video", image)
# 窗口的图像刷新时间为1毫秒
key = cv2.waitKey(1)
# 按下空格就终止
if key == 32:
break
capture.release()
cv2.destroyAllWindows()
彩色视频转换为灰度视频:
import cv2
capture = cv2.VideoCapture(0, cv2.CAP_DSHOW)
while (capture.isOpened()):
retval, image = capture.read()
# 把彩色视频转换为灰度视频
image_Gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
if retval == True:
cv2.imshow("Video", image)
cv2.imshow("Video_Gray", image_Gray)
key = cv2.waitKey(1)
if key == 32:
break
capture.release()
cv2.destroyAllWindows()
保存视频图像:
import cv2
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
while (cap.isOpened()):
ret, frame = cap.read()
cv2.imshow("Video", frame)
k = cv2.waitKey(1)
if k == 32:
cap.release()
cv2.destroyWindow("Video")
cv2.imwrite("路径", frame) # 保存按下空格键时摄像头视频中的图像
cv2.waitKey() # 刷新图像
break
cv2.destroyAllWindows() # 销毁显示图像的窗口
播放视频文件:
import cv2
video = cv2.VideoCapture("视频路径")
while (video.isOpened()):
retval, image = video.read()
# 设置“Video”窗口的宽为800,高为600
cv2.namedWindow("Video", 0)
cv2.resizeWindow("Video", 800, 600)
if retval == True:
# 在窗口中显示读取到的视频文件
cv2.imshow("Video", image)
else:
break
key = cv2.waitKey(1)
# 按下ESC退出
if key == 27:
break
video.release()
cv2.destroyAllWindows()
视频文件转换为灰度的:
import cv2
video = cv2.VideoCapture("视频路径")
while (video.isOpened()):
retval, img_Color = video.read()
cv2.namedWindow("Gray", 0)
cv2.resizeWindow("Gray", 800, 600)
if retval == True:
img_Gray = cv2.cvtColor(img_Color, cv2.COLOR_BGR2GRAY)
cv2.imshow("Gray", img_Gray)
else:
break
key = cv2.waitKey(1)
if key == 27:
break
video.release()
cv2.destroyAllWindows()