Aproximar polígonos é uma grande aproximação de contornos, mas às vezes queremos simplificá-la usando o casco convexo de um polígono.
Uma casca convexa é semelhante a um polígono de aproximação, exceto que é o polígono "convexo" mais externo de um objeto. Uma casca convexa refere-se a um polígono que contém completamente o contorno original e é composto apenas por pontos no contorno. Cada parte da casca convexa é convexa, ou seja, a linha reta que conecta quaisquer dois pontos na casca convexa está dentro da casca convexa. Em um casco convexo, o ângulo interno de quaisquer três pontos consecutivos é menor que 180°.
Por exemplo, na Figura 12-25, o polígono mais externo é o casco convexo do manipulador, e a parte entre a borda do manipulador e o casco convexo é chamada de defeito convexo (Defeito de Convexidade), que pode ser usado para lidar com reconhecimento de gestos e outras questões.
obter casco convexo
O OpenCV fornece 函数 cv2.convexHull()
um casco convexo para obter contornos. A sintaxe desta função é:
hull = cv2.convexHull(points[, sentido horário[, returnPoints]] )
A cobertura do valor de retorno na fórmula é o ponto de canto da cobertura convexa.
Os parâmetros da fórmula são os seguintes:
- Pontos: esboço.
- sentido horário: valor booleano. Quando o valor for True, os cantos da casca convexa serão dispostos no sentido horário; quando o valor for False, os cantos da casca convexa serão dispostos no sentido anti-horário.
- returnPoints: valor booleano. O valor padrão é True, a função retorna as coordenadas dos eixos x/y dos cantos da casca convexa; quando é False, a função retorna os índices dos cantos da casca convexa no contorno.
Exemplo: observe a utilização do parâmetro returnPoints na função cv2.convexHull()
código mostra como abaixo:
import cv2
o = cv2.imread('contours.bmp')
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
hull = cv2.convexHull(contours[0]) # 返回坐标值
print("returnPoints 为默认值 True 时返回值 hull 的值:\n",hull)
hull2 = cv2.convexHull(contours[0], returnPoints=False) # 返回索引值
print("returnPoints 为 False 时返回值 hull 的值:\n",hull2)
resultado da operação:
returnPoints 为默认值 True 时返回值 hull 的值:
[[[195 270]]
[[195 383]]
[[ 79 383]]
[[ 79 270]]]
returnPoints 为 False 时返回值 hull 的值:
[[3]
[2]
[1]
[0]]
Como pode ser visto nos resultados da execução do programa, o parâmetro opcional returnPoints da função cv2.convexHull():
- Quando o valor padrão é True, a função retorna as coordenadas dos eixos x/y dos pontos de canto do casco convexo. Neste exemplo, os valores das coordenadas de 4 contornos são retornados.
- Quando Falso, a função retorna os índices dos pontos dos cantos da casca convexa no contorno, neste caso são retornados 4 valores de índice do contorno.
Exemplo 2: Use a função cv2.convexHull() para obter a cobertura convexa de um contorno.
código mostra como abaixo:
import cv2
# --------------读取并绘制原始图像------------------
o = cv2.imread('hand.bmp')
cv2.imshow("original",o)
# --------------提取轮廓------------------
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
# --------------寻找凸包,得到凸包的角点------------------
hull = cv2.convexHull(contours[0])
# --------------绘制凸包------------------
cv2.polylines(o, [hull], True, (0, 255, 0), 2)
# --------------显示凸包------------------
cv2.imshow("result",o)
cv2.waitKey()
cv2.destroyAllWindows()
defeito convexo
A parte entre o casco convexo e o contorno é chamada de defeito convexo. cv2.convexityDefects()
Obtenha defeitos convexos usando a função em OpenCV . Seu formato de sintaxe é o seguinte:
convexityDefects = cv2.convexityDefects( contour, convexhull )
O valor de retorno convexityDefects na fórmula é o conjunto de pontos de defeitos convexos. É um array, e cada linha contém os valores [ponto inicial, ponto final, ponto no contorno mais distante da casca convexa, distância aproximada do ponto mais distante até a casca convexa].
需要注意的是,返回结果中[起点,终点,轮廓上距离凸包最远的点
, a distância aproximada do ponto mais distante ao casco convexo] Os três primeiros valores são os índices dos pontos do contorno, então você precisa encontrá-los nos pontos do contorno.
Os parâmetros da fórmula são os seguintes:
- contorno é o contorno.
- convexhull é o casco convexo.
Deve-se notar que ao calcular defeitos convexos com cv2.convexityDefects(), o casco convexo deve ser usado como parâmetro. Ao buscar o casco convexo, o valor do parâmetro returnPoints da função cv2.convexHull() utilizado deve ser False.
Para permitir que todos observem o ponto de defeito convexo definido de forma mais intuitiva, tentamos exibir o ponto de defeito convexo definido em uma imagem. O método de implementação é conectar o ponto inicial e o ponto final com uma linha e desenhar um círculo no ponto mais distante. Abaixo utilizamos um exemplo para demonstrar a operação acima.
Exemplo 2: Calcular defeitos convexos usando a função cv2.convexityDefects().
código mostra como abaixo:
import cv2
#----------------原图--------------------------
img = cv2.imread('hand.bmp')
cv2.imshow('original',img)
#----------------构造轮廓--------------------------
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 127, 255,0)
contours, hierarchy = cv2.findContours(binary,
cv2.RETR_TREE,
cv2.CHAIN_APPROX_SIMPLE)
#----------------凸包--------------------------
cnt = contours[0]
hull = cv2.convexHull(cnt,returnPoints = False)
defects = cv2.convexityDefects(cnt,hull)
print("defects=\n",defects)
#----------------构造凸缺陷--------------------------
for i in range(defects.shape[0]):
s,e,f,d = defects[i,0]
start = tuple(cnt[s][0])
end = tuple(cnt[e][0])
far = tuple(cnt[f][0])
cv2.line(img,start,end,[0,0,255],2)
cv2.circle(img,far,5,[255,0,0],-1)
#----------------显示结果,释放图像--------------------------
cv2.imshow('result',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
resultado da operação:
defects=
[[[ 0 102 51 21878]]
[[ 103 184 150 13876]]
[[ 185 233 220 4168]]
[[ 233 238 235 256]]
[[ 238 240 239 247]]
[[ 240 294 255 2715]]
[[ 294 302 295 281]]
[[ 302 304 303 217]]
[[ 305 311 306 114]]
[[ 311 385 342 13666]]
[[ 385 389 386 395]]
[[ 389 489 435 20327]]]
Determine se o contorno é convexo
No OpenCV, a função cv2.isContourConvex() pode ser usada para determinar se o contorno é convexo e seu formato de sintaxe é:
retval = cv2.isContourConvex(contorno)
Na fórmula:
- A recuperação do valor de retorno é um valor booleano. Quando True, o contorno é convexo; caso contrário, não é.
- O contorno do parâmetro é o contorno a ser julgado.
Exemplo: Use a função cv2.isContourConvex() para determinar se o contorno é convexo.
código mostra como abaixo:
import cv2
o = cv2.imread('hand.bmp')
cv2.imshow("original",o)
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,
cv2.RETR_LIST,
cv2.CHAIN_APPROX_SIMPLE)
#--------------凸包----------------------
image1=o.copy()
hull = cv2.convexHull(contours[0])
cv2.polylines(image1, [hull], True, (0, 255, 0), 2)
print("使用函数 cv2.convexHull()构造的多边形是否是凸形的:",
cv2.isContourConvex(hull))
cv2.imshow("result1",image1)
#------------逼近多边形--------------------
image2=o.copy()
epsilon = 0.01*cv2.arcLength(contours[0],True)
approx = cv2.approxPolyDP(contours[0],epsilon,True)
image2=cv2.drawContours(image2,[approx],0,(0,0,255),2)
print("使用函数 cv2.approxPolyDP()构造的多边形是否是凸形的:",
cv2.isContourConvex(approx))
cv2.imshow("result2",image2)
#------------释放窗口--------------------
cv2.waitKey()
cv2.destroyAllWindows()
resultado da operação:
使用函数 cv2.convexHull()构造的多边形是否是凸形的: True
使用函数 cv2.approxPolyDP()构造的多边形是否是凸形的: False
A partir dos resultados de execução acima, pode-se ver que:
- Depois de usar a função cv2.contourContourConvex() para construir o casco convexo, use a função cv2.isContourConvex() para julgar o casco convexo desenhado.O valor de retorno é True, indicando que o contorno é convexo.
- Após utilizar a função cv2.approxPolyDP() para construir o polígono aproximado, utilize a função cv2.isContourConvex() para julgar o polígono aproximado desenhado, e o valor de retorno é False, indicando que o contorno (polígono) não é convexo.
A imagem original do experimento: