文章目录
- OpenCv基础之边缘检测与轮廓描绘
- Canny边缘检测
- 图像轮廓
- 绘制轮廓
OpenCv基础之边缘检测与轮廓描绘
边缘检测:主要是通过一些手段检测数字图像中明暗变化剧烈(即梯度变化比较大)像素点,偏向于图像中像素点的变化。
轮廓检测:指在包含目标和背景的数字图像中,忽略背景和目标内部的纹理以及噪声干扰的影响,采用一定的技术和方法来实现目标轮廓提取的过程。主要用来分析物体的形态,比如物体的周长和面积等。
Canny边缘检测
图像的边缘是指图像局部区域亮度变化显著的部分,该区域的灰度剖面可以看作是一个阶跃,即从一个灰度值在很小的缓冲区域内急剧变化到另一个灰度相差较大的灰度值。
# 1)使用高斯滤波器,以平滑图像,滤除噪声
# 2)计算图像中每个像素点的梯度强度和方向
# 3)应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应
# 4)应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘
# 5)通过抑制孤立的弱边缘最终完成边缘检测
canny_img=cv2.imread('img/girl.jpg')
# edge = cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient ]]])
# 参数 Image - 输入图片,必须为单通道的灰度图
# 参数 threshold1 和 threshold2 - 分别对应于阈值 minVal 和 maxVal
# 参数 apertureSize - 用于计算图片提取的 Sobel kernel 尺寸. 默认为 3.
# 参数 L2gradient - 指定计算梯度的等式. 当参数为 True 时,采用 2.2 中的梯度计算公式,其精度更高;否则采用的梯度计算公式为:
# 梯度|G|=|Gx|+|Gy|
v1=cv2.Canny(canny_img,80,150)
v2=cv2.Canny(canny_img,50,100)
# 展示边缘检测结果
res = np.hstack((v1,v2))
cv2.imshow('res',res)
cv2.waitKey(0)
注意,通过不同的阈值画出的图像边缘是不一样的,显然最小阈值低的,边缘更丰富。
图像轮廓
- cv2.cvtcolor()函数是一个颜色空间转换函数,可以实现RGB颜色向HSV,HSI等颜色空间转换。也可以转换为灰度图。
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图像
img=cv2.imread('img/backgrand.jpg')
# 读进去的是BGR格式的,但是在保存图片时,要保存为RGB格式的,可以用cv2.COLOR_BGR2RGB
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv2.imshow('gray ',gray )# 展示灰度图
cv2.waitKey(0)
# 图像阈值:将像素值大于127的全部设置为255
ret,thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
cv2.imshow('thresh',thresh )
cv2.waitKey(0)
- cv2.findContours(img,mode,method)
- img: 二值图像
mode: 轮廓检索模式:
①RETR_EXTERNAL 只检索最外面的轮廓
②RETR_LIST:检索所有的轮廓,并将其保存到一条链表当中
③RETR_CCOMP:检索所有的轮廓,并将他们组织为两层,顶层是各部分的外部边界,第二层是空洞的边界
④RETR_TREE:检索有所的轮廓,并重构嵌套轮廓的整个层次
method:轮廓逼近方法
①CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)
②CHAIN_APPROX_SIMPLE:压缩水平的,垂直的和斜的部分,也就是,函数只保留他们的终点部分。
注意:cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图),所以读取的图像要先转成灰度的,再转成二值图。
- contours,是一个向量,并且是一个双重向量,向量内每个元素保存了一组由连续的Point点构成的点的集合的向量,每一组Point点集就是一个轮廓。有多少轮廓,向量contours就有多少元素。
- hierarchy也是一个向量,向量内每个元素保存了一个包含4个int整型的数组.hierarchy[i][0] ~hierarchy[i][3],分别表示第i个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号.
如果当前轮廓没有对应的后一个轮廓、前一个轮廓、父轮廓或内嵌轮廓的话,则hierarchy[i][0]~hierarchy[i][3]的相应位被设置为默认值-1。
注意:可以通过cv2.findContours()函数的返回值contours,判断其轮廓线是否闭合,可以求其面积,周长等特点。
# 轮廓检测
binary,contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
- 函数cv2.drawContours()可以被用来绘制轮廓;它可以根据你提供的边界点绘制任何形状。
绘制轮廓
# 注意需要copy,要不原图会变
draw_img = img.copy()# draw_img = img是相同的
# 传入绘制图像,轮廓,轮廓索引(-1画所有轮廓),颜色模式(bgr),线条厚度
res = cv2.drawContours(draw_img,contours,-1,(0,0,255),2)# 目前红色
cv2.imshow('res',res)
cv2.waitKey(0)
这两个知识点比较容易混淆,所以笔者学习时也留意了一下,希望能够帮助到大家。同时,大家也可以通过matplotlib对图像进行输出,可以发现其输出图像颜色不同与OpenCV,这是由于两者三色通道顺序是不同的,需要进行转化。