├── README.md ├── bookpage.jpg ├── opencv_logo.jpg ├── plane.jpg ├── poker.jpg ├── test00_hello.py ├── test02_color.py ├── test03_crop.py ├── test04_draw.py ├── test05_blur.py ├── test06_corner.py ├── test07_match.py ├── test08_gradient.py ├── test09_threshold.py ├── test10_morphology.py └── test11_camera.py /README.md: -------------------------------------------------------------------------------- 1 | # OpenCV Python 图像处理 30分钟 入门课程 源代码 2 | 3 | 欢迎来到《OpenCV Python 图像处理 30分钟 入门课程》的源代码仓库。本课程由孔工码字提供,旨在帮助初学者快速入门OpenCV图像处理。课程内容涵盖了图像处理的基本概念和实践技巧,适合对计算机视觉和图像处理感兴趣的开发者。 4 | 5 | ## 课程信息 6 | 7 | - **课程名称**: OpenCV Python 图像处理 30分钟 入门课程 8 | - **B站地址**: [BV1BT4y1Z7WS](https://www.bilibili.com/video/BV1BT4y1Z7WS/?spm_id_from=333.337.search-card.all.click&vd_source=f33026057a06810119d860bd432f2abb) 9 | 10 | ## 课程内容 11 | 12 | 课程内容包括但不限于以下主题:(比较干,记得喝水) 13 | 14 | 1. **第一个hello程序**: 学习如何运行OpenCV的基本示例。 15 | 2. **图像的彩色通道BGR**: 了解OpenCV中图像颜色通道的表示方式。 16 | 3. **图像的裁剪**: 学习如何对图像进行裁剪操作。 17 | 4. **绘制直线、矩形、圆形**: 实践在图像上绘制基本图形。 18 | 5. **均值滤波处理图像噪点**: 使用均值滤波器去除图像噪声。 19 | 6. **图像特征点的提取**: 学习如何提取图像中的特征点。 20 | 7. **模板匹配扑克牌上的菱形**: 实现模板匹配技术。 21 | 8. **图像的梯度算法与边缘检测**: 探索图像梯度和边缘检测算法。 22 | 9. **图像的二值化**: 学习如何将图像转换为二值图像。 23 | 10. **图像形态学之腐蚀和膨胀**: 实践图像形态学操作。 24 | 11. **调用电脑摄像头**: 学习如何使用OpenCV捕获实时视频流。 25 | 26 | ## 如何使用源代码 27 | 28 | 1. 克隆或下载本仓库到本地。 29 | 2. 确保你已经安装了Python和OpenCV库。(具体python基础知识的学习和开发环境的配置请移步[B站UP主孔工码字](https://space.bilibili.com/302545359?spm_id_from=333.337.search-card.all.click)) 30 | 3. 运行相应的Python脚本,查看图像处理效果。 31 | 32 | ## 贡献 33 | 34 | 如果你在课程学习过程中有任何疑问或建议,欢迎在GitHub Issues中提出。如果你希望贡献代码或改进,也欢迎fork一份随时PR。 35 | 36 | ------ 37 | 38 | 感谢你对本课程的兴趣,希望这些源代码能够帮助你更好地理解和应用OpenCV进行图像处理。祝你学习愉快! -------------------------------------------------------------------------------- /bookpage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongfanhe/opencv_tutorial/18f9d76e7ac935a8ab7b925519f81d15cf964910/bookpage.jpg -------------------------------------------------------------------------------- /opencv_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongfanhe/opencv_tutorial/18f9d76e7ac935a8ab7b925519f81d15cf964910/opencv_logo.jpg -------------------------------------------------------------------------------- /plane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongfanhe/opencv_tutorial/18f9d76e7ac935a8ab7b925519f81d15cf964910/plane.jpg -------------------------------------------------------------------------------- /poker.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongfanhe/opencv_tutorial/18f9d76e7ac935a8ab7b925519f81d15cf964910/poker.jpg -------------------------------------------------------------------------------- /test00_hello.py: -------------------------------------------------------------------------------- 1 | # 基本IO 2 | import cv2 3 | # 读取版本号 4 | print(cv2.getVersionString()) 5 | # 读取图片 6 | image = cv2.imread("opencv_logo.jpg") 7 | # 打印图片的形状(高度,宽度,通道数) 8 | print(image.shape) 9 | 10 | cv2.imshow("image", image) 11 | cv2.waitKey() # 让窗口暂停 12 | 13 | -------------------------------------------------------------------------------- /test02_color.py: -------------------------------------------------------------------------------- 1 | # 图像的颜色 2 | import cv2 3 | 4 | image = cv2.imread("opencv_logo.jpg") 5 | # 颜色通道顺序:BGR 6 | 7 | 8 | cv2.imshow("blue", image[:, :, 0]) 9 | cv2.imshow("green", image[:, :, 1]) 10 | cv2.imshow("red", image[:, :, 2]) 11 | 12 | 13 | # 彩色图片灰度化 14 | gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 15 | cv2.imshow("gray", gray) 16 | 17 | cv2.waitKey() 18 | 19 | -------------------------------------------------------------------------------- /test03_crop.py: -------------------------------------------------------------------------------- 1 | # 图像裁剪操作 2 | import cv2 3 | 4 | image = cv2.imread("opencv_logo.jpg") 5 | 6 | crop = image[10:170, 40:200] 7 | 8 | cv2.imshow("crop", crop) 9 | cv2.waitKey() 10 | -------------------------------------------------------------------------------- /test04_draw.py: -------------------------------------------------------------------------------- 1 | # 实现绘图功能 2 | import cv2 3 | import numpy as np 4 | 5 | # 创建黑色画布 6 | image = np.zeros([300, 300, 3], dtype=np.uint8) 7 | 8 | # 绘制线段(对象, 起点, 终点, 颜色, 粗细) 9 | cv2.line(image, (100, 200), (250, 250), (255, 0, 0), 2) 10 | # 绘制矩形(~,起点, 对角点, 颜色, 粗细) 11 | cv2.rectangle(image, (30, 100), (60, 150), (0, 255, 0), 2) 12 | # 绘制圆形(~,圆心, 半径, 颜色, 粗细) 13 | cv2.circle(image, (150, 100), 20, (0, 0, 255), 3) 14 | # 绘制字符串(~, 内容, 坐标, 字体格式序号, 缩放系数, 颜色, 粗细, 线条类型序号) 15 | cv2.putText(image, "hello", (100, 50), 0, 1, (255, 255, 255), 2, 1) 16 | 17 | cv2.imshow("image", image) 18 | cv2.waitKey() 19 | -------------------------------------------------------------------------------- /test05_blur.py: -------------------------------------------------------------------------------- 1 | # 图形的滤波 2 | import cv2 3 | 4 | image = cv2.imread("plane.jpg") 5 | # 使用高斯滤波器 6 | gauss = cv2.GaussianBlur(image, (5, 5), 0) 7 | # 使用均值滤波器 8 | median = cv2.medianBlur(image, 5) 9 | 10 | cv2.imshow("image", image) 11 | cv2.imshow("gauss", gauss) 12 | cv2.imshow("median", median) 13 | 14 | cv2.waitKey() 15 | 16 | ''' 17 | 高斯滤波(Gaussian Blur)和均值滤波(Mean Blur)都是图像处理中常用的平滑技术,它们用于减少图像噪声、模糊图像边缘或细节,以及进行图像预处理。 18 | 选择使用哪种滤波方法取决于具体的应用场景和需求。 19 | 20 | 均值滤波: 21 | 简单易实现,对所有像素的邻域内的像素值求平均。 22 | 对于去除随机噪声(如椒盐噪声)效果较好。 23 | 对图像的边缘和细节的模糊程度较高,可能导致图像质量下降。 24 | 25 | 高斯滤波: 26 | 使用高斯分布作为权重,对邻域内的像素进行加权平均。 27 | 对图像的边缘和细节的模糊程度较低,通常能更好地保留图像的结构信息。 28 | 实现相对复杂,需要计算高斯核的权重。 29 | 30 | 在实际应用中,高斯滤波通常更受欢迎,因为它在平滑图像的同时能更好地保留图像的边缘和细节。 31 | 然而,如果处理速度是一个关键因素,均值滤波由于其简单性可能会更快。此外,对于某些特定的噪声类型,均值滤波可能更有效。 32 | 33 | 在决定使用哪种滤波方法时,可以考虑以下因素: 34 | 图像内容:如果图像中包含重要的边缘信息,高斯滤波可能更合适。 35 | 噪声类型:如果主要是随机噪声,均值滤波可能更有效。 36 | 实现复杂度:如果需要快速实现,均值滤波可能更简单。 37 | 性能要求:如果对图像质量有较高要求,高斯滤波通常能提供更好的结果。 38 | 39 | 在某些情况下,也可以结合使用这两种滤波方法,或者尝试其他类型的滤波器,如双边滤波(Bilateral Filter),它在平滑图像的同时能更好地保留边缘。 40 | ''' 41 | 42 | -------------------------------------------------------------------------------- /test06_corner.py: -------------------------------------------------------------------------------- 1 | # 图片特征的提取 2 | import cv2 3 | 4 | image = cv2.imread("opencv_logo.jpg") 5 | gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 图片先灰度化 6 | 7 | # 获取特征点 (对象, 最多的点数, 质量优度水平, 特征点之间的最小距离) 8 | corners = cv2.goodFeaturesToTrack(gray, 500, 0.1, 10) 9 | # 标记出每个点 10 | for corner in corners: 11 | x, y = corner.ravel() 12 | cv2.circle(image, (int(x), int(y)), 3, (255, 0, 255), -1) 13 | 14 | cv2.imshow("corners", image) 15 | cv2.waitKey() 16 | # 可以发现,特征点主要都在图片的转角处 17 | 18 | 19 | -------------------------------------------------------------------------------- /test07_match.py: -------------------------------------------------------------------------------- 1 | # 图片的模板匹配(以匹配扑克牌上的菱形为例) 2 | import cv2 3 | import numpy as np 4 | 5 | image = cv2.imread("poker.jpg") 6 | gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 7 | 8 | # 选取匹配模板 9 | template = gray[75:105, 235:265] 10 | 11 | # 使用标准相关匹配算法——将待检测对象和模板都标准化再来计算匹配度 12 | match = cv2.matchTemplate(gray, template, cv2.TM_CCOEFF_NORMED) 13 | locations = np.where(match >= 0.9) # 找出匹配系数大于0.9的匹配点 14 | 15 | w, h = template.shape[0:2] 16 | for p in zip(*locations[::-1]): # 循环遍历每一个匹配点并画出矩形框标记 17 | x1, y1 = p[0], p[1] 18 | x2, y2 = x1 + w, y1 + h 19 | cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2) 20 | 21 | cv2.imshow("image", image) 22 | cv2.waitKey() 23 | 24 | 25 | -------------------------------------------------------------------------------- /test08_gradient.py: -------------------------------------------------------------------------------- 1 | # 图像的梯度(明暗变化) 2 | import cv2 3 | 4 | gray = cv2.imread("opencv_logo.jpg", cv2.IMREAD_GRAYSCALE) # 直接读取为灰度图 5 | 6 | # 使用拉普拉斯算子(检测边缘——梯度剧烈变化处) 7 | laplacian = cv2.Laplacian(gray, cv2.CV_64F) 8 | # canny边缘检测(定义边缘为梯度区间) 9 | # 梯度大于200 -> 变化足够强烈,确定是边缘 10 | # 梯度小于100 -> 变化较为平缓,确定非边缘 11 | # 梯度介于二者之间 -> 待定,看其是否与已知的边缘像素相邻 12 | canny = cv2.Canny(gray, 100, 200) 13 | 14 | cv2.imshow("gray", gray) 15 | cv2.imshow("laplacian", laplacian) 16 | cv2.imshow("canny", canny) 17 | 18 | cv2.waitKey() 19 | 20 | -------------------------------------------------------------------------------- /test09_threshold.py: -------------------------------------------------------------------------------- 1 | # 图片的阈值算法(二值化,将连续的灰度范围切割为白+黑) 2 | import cv2 3 | 4 | # 图片灰度二值化 5 | gray = cv2.imread("bookpage.jpg", cv2.IMREAD_GRAYSCALE) 6 | ret, binary = cv2.threshold(gray, 10, 255, cv2.THRESH_BINARY) 7 | # 图片自适应二值化(划分区块二值化,效果更好) 8 | binary_adaptive = cv2.adaptiveThreshold( 9 | gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 115, 1) 10 | # 大津算法(基于图片灰度聚类分析,自定义阈值) 11 | ret1, binary_otsu = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) 12 | 13 | cv2.imshow("gray", gray) 14 | cv2.imshow("binary", binary) 15 | cv2.imshow("adaptive", binary_adaptive) 16 | cv2.imshow("otsu", binary_otsu) 17 | cv2.waitKey() 18 | 19 | # ret/ret1是一个浮点数,表示图像中像素值的阈值 20 | print(ret) 21 | print(ret1) 22 | -------------------------------------------------------------------------------- /test10_morphology.py: -------------------------------------------------------------------------------- 1 | # 图像的形态学算法(腐蚀和膨胀) 2 | import cv2 3 | import numpy as np 4 | 5 | # 在腐蚀和膨胀之前需要先将图片二值化 6 | gray = cv2.imread("opencv_logo.jpg", cv2.IMREAD_GRAYSCALE) 7 | 8 | _, binary = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV) # 使用反向阈值——背景白色,图案黑色 9 | kernel = np.ones((5, 5), np.uint8) # 操作需要用到的kernel 10 | 11 | # 腐蚀和膨胀操作 12 | erosion = cv2.erode(binary, kernel) 13 | dilation = cv2.dilate(binary, kernel) 14 | 15 | cv2.imshow("binary", binary) 16 | cv2.imshow("erosion", erosion) 17 | cv2.imshow("dilation", dilation) 18 | 19 | 20 | cv2.waitKey() 21 | -------------------------------------------------------------------------------- /test11_camera.py: -------------------------------------------------------------------------------- 1 | # opencv调用电脑中的摄像头 2 | import cv2 3 | 4 | # 获取摄像头设备的指针(设备管理器 -> 照相机) 5 | capture = cv2.VideoCapture(0) 6 | ret = True 7 | 8 | # 摄像头的读取是连续不断的,需要循环读取 9 | while ret: 10 | ret, frame = capture.read() 11 | ''' 12 | ret:这是一个布尔值,表示读取操作是否成功。 13 | 如果 ret 为 True,表示成功读取了一帧图像;如果为 False,则表示读取失败,可能是因为视频流结束或者其他错误。 14 | 在处理视频流时,这个返回值通常用于控制循环,直到视频流结束。 15 | 16 | frame:这是一个NumPy数组,代表了从视频捕获对象读取的当前帧。 17 | 这个数组通常是一个三维的,其形状为 (高度, 宽度, 通道数),其中通道数可以是1(灰度图像)或3(彩色图像,分别对应红、绿、蓝通道)。 18 | ''' 19 | cv2.imshow("camera", frame) 20 | key = cv2.waitKey(1) # 等待键盘输入1ms 21 | if key != -1: # 按任意键跳出循环 22 | break 23 | 24 | capture.release() # 释放指针 25 | --------------------------------------------------------------------------------