轮廓检测
1. 边缘和轮廓检测辩析
- 边缘检测能够检测出边缘,但是边缘是不连续的。
- 将边缘连接成一个整体,构成轮廓
2.图像轮廓检测中注意的问题
-
对象是二值图像所以需要进行阈值分割
-
再Opencv中,背景必须是黑色的,对象必须是白色的
因为子自动从黑色中找白色的轮廓
3.轮廓检测
查找轮廓函数:
cv2.findContours(src,mode,method)
src:原图像
mode:轮廓的检索方式
method:轮廓逼近方法
- cv2.RETR_EXTERNAL :只检测外轮廓
- cv2.RETR_LIST:检测轮廓不建立等级关系
- cv2.RETE_CCOMP:检测所有论据,并将他们组织为两层:
顶层是各部分的外部边界,第二层是空洞边界 cv2.RETR_TREE
(最常用):检测所有轮廓,并重构嵌套轮廓的整个层次
method:轮廓逼近方法:
- CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他的方法输出多边形(顶点序列)
- CHAIIN_APPROX_SIMPLE:压缩水平的,垂直的和斜的部分,也就是函数只保留他们的终点部分。
返回值
- image:修改后的原始图像【即二值化图像】
- contours:轮廓
- hierarchy:图像的拓扑信息(轮廓层次)
轮廓绘制函数
cv2.findContous(src,contours,num,color,width)
- src:源图像
- contours:轮廓信息
- num:绘制多少个轮廓【-1为全部绘制】
- color:轮廓绘制的颜色
- width:轮廓的宽度
代码示例:
# -*- coding: UTF-8 -*-
# @Project :opencv
# @File :轮廓检测学习.py
# @Author :于金龙
# @IDE :PyCharm
# @Date :2024/4/19 13:40
import cv2
import numpy
# 读取彩色图片
image = cv2.imread(r"C:\Users\HONOR\Desktop\OIP-C.jpg")
# 将彩色图片转化为灰度图
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 将灰度图转为二值图
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 寻找图像的轮廓
# image, Contours, hie = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
Contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 对原始图像进行复制
draw_image = image.copy()
# 对图像进行绘制
new_image = cv2.drawContours(draw_image, Contours, -1, (0, 0, 255), 2)
# 图像显示
cv2.imshow("old_image", image)
cv2.imshow("new_image", new_image)
cv2.imwrite('new_image.jpg', new_image)
cv2.waitKey(0)
示例代码中的小问题和小细节:
小细节为什么不直接在读取图片的时候直接转为灰度图片:
因在如果在读取图片的时候直接转为灰度图的话,图片的会变为一个二维图片,也就灰度的,然后在进行绘制轮廓的时候,绘制的颜色也是灰色,不能够显现出红色。
报错:
Traceback (most recent call last):
File “D:\gitee代码托管\opencv\轮廓检测学习.py”, line 16, in
image, Contours, hie = cv2.findContours(binary, cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
ValueError: not enough values to unpack (expected 3, got 2)
原因:
由于opencv版本的原因:
2 -> cv2.findContours 两个返回值 (contours, hierarchy)
3 -> cv2.drawContours 三个返回值 (image,contours, hierarchy)
4 -> cv2.drawContours 两个返回值 (contours, hierarchy)
主要差距在于返回值时是不是返回源图像,因为我的版本时4.x.x的版本所以返回值为两个,但是我写了三个接收值,所以触发了报错。
这里建议查看一下函数的文档比较明朗还靠谱
为什么要对图像进行复制
这是因为drawContours函数的一个特性,会在原图进行进行修改,所以需要重新复制一个
避免函数对源数据进行修改