canny边缘提取算法

边缘:一个物体的边缘,可以是不封闭曲线。

轮廓:一个物体的轮廓,封闭曲线,一般属于边缘的子集,单像素构成线。但有时候对碰撞操作时,会有差别。且轮廓可以是几个特征点,不需要是一个一个像素组合而成的线

梯度:表示像素差异,不一定是一个像素

canny医学例子:

原图如下:

python 外轮廓提取 python人体轮廓提取_opencv


图像人脸的轮廓有一部分很浅,要提取出脸部轮廓,和原图一起作为先验,就要将轮廓更好的提取。所以采用对比度调整,然后在进行高斯滤波,然后进行canny提取,代码和效果如图:(其中增加了对比度的图片还可以进行闭操作,补洞之后在进行轮廓提取)

import cv2
img = cv2.imread("25.jpg", 0)
cv2.imshow('Canny2', img)
img = cv2.convertScaleAbs(img, alpha=6, beta=0)#进行对比度调整,获取到表示不明显地方的数据
cv2.imshow('Abs', img)
img = cv2.GaussianBlur(img, (5, 5), 1)
cv2.imshow("1",img)
canny = cv2.Canny(img, 100, 150)
cv2.imshow("2",canny)
canny = cv2.resize(canny, dsize=(500, 500))
cv2.imshow('Canny', canny)
cv2.waitKey(0)

python 外轮廓提取 python人体轮廓提取_灰度图_02


python 外轮廓提取 python人体轮廓提取_opencv_03


python 外轮廓提取 python人体轮廓提取_python 外轮廓提取_04

canny算法详解

步骤:

python 外轮廓提取 python人体轮廓提取_python 外轮廓提取_05


图像转灰度图(不需要在彩色图上进行),高斯滤波(锦上添花),计算图像梯度和幅值,即初步获取到图像轮廓,这时候的轮廓边不一定是单像素,非极大值抑制(变成单像素),双阈值链接处理,二值化图像输出。

梯度的幅值和角度:
幅值:幅值表示在该位置的边缘的亮度(即有值得地方,像素差距很大,就会表现出亮的特性)
角度:角度表示像素的颜色向哪一个方向变化的最快

非极大值抑制:

python 外轮廓提取 python人体轮廓提取_opencv_06


当前像素的梯度强度和沿着正负梯度的另外两个值进行比较,大于则保存,小于则替换双阈值边缘链接处理:

python 外轮廓提取 python人体轮廓提取_边缘检测_07


找出来的有一些线可能会断,或者找出来的线是否需要,用该阈值操作来进行操作。

它的原理就是设置了两个阈值,找出来的线高于最大阈值,则保留,低于阈值则直接排除。

这两个值的设置是canny的两个参数,这两个参数是经验参数,如果调的好,取出来的轮廓线会很连贯。

轮廓查找和绘制

import cv2

img = cv2.imread('14.jpg')
# cv2.imshow("src", img)
imggray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#转灰度图
ret, thresh = cv2.threshold(imggray, 127, 255, 0)#转二值图
contours, _tree= cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
'''
findContours算法内部包含了canny算法
cv2.RETR_TREE会生成一个轮廓的层次树,层次树是哪一个是主要的,哪一个是次要的
CHAIN_APPROX_SIMPLE需要最少点找出轮廓
CHAIN_APPROX_NONE点很多来找出轮廓
'''
# contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
print(len(contours[0]))
img_contour = cv2.drawContours(img, contours, -1, (0, 255, 0), 2)
'''
-1为画所有的轮廓
第二个参数为颜色
第三个为轮廓的宽度
将第三个参数改为-1,就或进行轮廓中的填充,在unet的实现中有很大帮助
'''
cv2.imshow("img_contour", img_contour)
cv2.waitKey(0)

python 外轮廓提取 python人体轮廓提取_灰度图_08


面积,周长,重心

import cv2
img = cv2.imread('15.jpg', 0)
ret, thresh = cv2.threshold(img, 127, 255, 0)
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
#重心的运算
M = cv2.moments(contours[0])  # 矩
cx, cy = int(M['m10'] / M['m00']), int(M['m01'] / M['m00'])
print("重心:", cx, cy)
#面积
area = cv2.contourArea(contours[0])
print("面积:", area)
#周长
perimeter = cv2.arcLength(contours[0], True)
print("周长:", perimete

轮廓近似

import cv2
img = cv2.imread('26.jpg')
imggray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imggray,127,255,0)
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
epsilon = 40 #精度
approx = cv2.approxPolyDP(contours[0],epsilon,True)
img_contour= cv2.drawContours(img, [approx], -1, (0, 0, 255), 3)
cv2.imshow("img_contour", img_contour)
cv2.waitKey(0)
'''
epsilon = 40 #精度表示近似点相对于真实点的偏移量不能大于40
'''

python 外轮廓提取 python人体轮廓提取_灰度图_09


凸包与凸性监测

在图形中取两个点,如果这两个点生成的直线和图像没有交点,则是凸包

import cv2

img = cv2.imread('15.jpg')

imggray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imggray,127,255,0)

contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

hull = cv2.convexHull(contours[0])
print(cv2.isContourConvex(contours[0]), cv2.isContourConvex(hull))
#False True
#说明轮廓曲线是非凸的,凸包曲线是凸的

img_contour= cv2.drawContours(img, [hull], -1, (0, 0, 255), 3)

cv2.imshow("img_contour", img_contour)
cv2.waitKey(0)

python 外轮廓提取 python人体轮廓提取_opencv_10


边界检测

找最小的边界矩形,外切圆,正方形

在这里插入代码片

python 外轮廓提取 python人体轮廓提取_python 外轮廓提取_11


判断物体相碰:找出外接矩形,然后看在坐标轴上的投影,看投影是否相交,以此来判断时候物体相碰轮廓的性质

python 外轮廓提取 python人体轮廓提取_python 外轮廓提取_12


用来判断轮廓是否偏向于正方形

python 外轮廓提取 python人体轮廓提取_边缘检测_13


python 外轮廓提取 python人体轮廓提取_灰度图_14


python 外轮廓提取 python人体轮廓提取_边缘检测_15


python 外轮廓提取 python人体轮廓提取_python_16


寻找对象的方向代码:

import cv2
import numpy as np
img = cv2.imread('16.jpg')
imggray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(imggray, 127, 255, 0)
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 椭圆拟合
ellipse = cv2.fitEllipse(contours[0])
cv2.ellipse(img, ellipse, (255, 0, 0), 2)

# 直线拟合
h, w, _ = img.shape
[vx, vy, x, y] = cv2.fitLine(contours[0], cv2.DIST_L2, 0, 0.01, 0.01)
lefty = int((-x * vy / vx) + y)
righty = int(((w - x) * vy / vx) + y)
cv2.line(img, (w - 1, righty), (0, lefty), (0, 0, 255), 2)

cv2.imshow("img_contour", img)
cv2.waitKey(0)

python 外轮廓提取 python人体轮廓提取_opencv_17


形状匹配

匹配度为0,完全匹配,匹配度为1,不匹配

import cv2
img1 = cv2.imread('16.jpg', 0)
img2 = cv2.imread('17.jpg', 0)
ret, thresh = cv2.threshold(img1, 127, 255, 0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnt1 = contours[0]
ret, thresh2 = cv2.threshold(img2, 127, 255, 0)
contours, hierarchy = cv2.findContours(thresh2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnt2 = contours[0]
ret = cv2.matchShapes(cnt1, cnt2, cv2.CONTOURS_MATCH_I2, 0.0)
print(ret)