带有霍夫变换的OpenCV,100%
我最初的想法是检测山羊腿的垂直线,并确定山羊相对于身体和地平线的垂直位置。
事实证明,在所有图像中,地面都非常嘈杂,从而产生了大量的Canny边缘检测输出以及来自Hough变换的相应检测线。然后,我的策略是确定水平线是位于图像的上半部还是下半部,这足以解决问题。
# Most of this code is from OpenCV examples
import cv2
import numpy as np
def is_upgoat(path):
img = cv2.imread(path)
height, width, channels = img.shape
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 100, 200, apertureSize=3)
lines = cv2.HoughLines(edges, 1, np.pi/180, 200, None, 0, 0, np.pi/2-0.5, np.pi/2+0.5)
rho_small = 0
for line in lines:
rho, theta = line[0]
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 5000*(-b))
y1 = int(y0 + 5000*(a))
x2 = int(x0 - 5000*(-b))
y2 = int(y0 - 5000*(a))
if rho/height < 1/2: rho_small += 1
cv2.line(img,(x1,y1),(x2,y2),(0,0,255),1, cv2.LINE_AA)
output_dir = "output/"
img_name = path[:-4]
cv2.imwrite(output_dir + img_name + "img.jpg", img)
cv2.imwrite(output_dir + img_name + "edges.jpg", edges)
return rho_small / len(lines) < 1/2
for i in range(1, 10):
downgoat_path = "downgoat" + str(i) + ".jpg"
print(downgoat_path, is_upgoat(downgoat_path))
for i in range(1, 10):
upgoat_path = "upgoat" + str(i) + ".jpg"
print(upgoat_path, is_upgoat(upgoat_path))
这是不输出图像的全部功能:
def is_upgoat(path):
img = cv2.imread(path)
height, width, channels = img.shape
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 100, 200, apertureSize=3)
lines = cv2.HoughLines(edges, 1, np.pi/180, 200, None, 0, 0, np.pi/2-0.5, np.pi/2+0.5)
rho_small = 0
for line in lines:
rho, theta = line[0]
if rho/height < 1/2: rho_small += 1
return rho_small / len(lines) < 1/2
Downgoat1边缘:
Downgoat1行:
Upgoat2边缘和线条:
该方法甚至在噪声特别大的图像上也能很好地工作。这是downgoat3的边缘和线条:
附录
事实证明,在霍夫变换之前,中值模糊和自适应高斯阈值比Canny边缘检测要好得多,这主要是因为中值模糊在嘈杂的区域比较好。但是,我最初方法的问题立即显而易见:检测到突出的背景线以及某些图片中的山羊脸。
def is_upgoat2(path):
img = cv2.imread(path)
#height, width, channels = img.shape
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.medianBlur(gray, 19)
thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY_INV, 11, 2)
lines = cv2.HoughLinesP(thresh, 1, np.pi / 180, threshold=100,
minLineLength=50, maxLineGap=10)
vert_y = []
horiz_y = []
for line in lines:
x1, y1, x2, y2 = line[0]
# Vertical lines
if x1 == x2 or abs((y2-y1)/(x2-x1)) > 3:
vert_y.append((y1+y2)/2)
cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
# Horizontal lines
if x1 != x2 and abs((y2-y1)/(x2-x1)) < 1/3:
horiz_y.append((y1+y2)/2)
cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
print(np.median(vert_y), np.median(horiz_y))
这是失策8:
轮廓(代码未显示)可以很好地检测山羊(脊椎)的上边缘,但无法获得整个形状。
进一步的研究: OpenCV具有基于Haar特征的对象检测,通常用于汽车和面部等事物,但鉴于其独特的形状,它也可能适用于山羊。
2D特征识别看起来很有前途(由于缩放和旋转,模板匹配无法使用),但是我懒得弄清楚C ++的OpenCV。