python - 如何检测二进制图像中的某种形状(植物茎)?
问题描述
当我被困了几个小时试图弄清楚如何根据叶子的茎旋转图像时,我正在研究一个基于形状的叶子分类项目。
这是输入图像的示例。
我一直在尝试使用具有不同内核甚至 HoughLines 的 opencv 和 filter2D 应用形态学变换,这是我迄今为止得到的结果。
任何帮助将不胜感激,在此先感谢。
编辑
茎的位置很重要,因为我试图分类不同种类的叶子,所以我想要完成的是让叶子处于垂直位置,茎在底部。
我提供的图像是阈值图像,我将原始图像留在这里。
我提供了第二个样本,因为在这种特殊情况下,我无法将茎放在底部,所以它最终位于顶部。
样品返回 2 度。
解决方案
这是一个想法。将椭圆拟合到阈值叶形(假设它长于宽)。
输入:
import cv2
import numpy as np
# read image
img = cv2.imread('leaf.png')
# threshold on color
lower=(84,1,68)
upper=(84,1,68)
thresh = cv2.inRange(img, lower, upper)
# get contour
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
# fit ellipse to leaf contours
ellipse = cv2.fitEllipse(big_contour)
(xc,yc), (d1,d2), angle = ellipse
print(xc,yc,d1,d1,angle)
# draw ellipse on copy of input
result = img.copy()
cv2.ellipse(result, ellipse, (0,0,255), 1)
# save results
cv2.imwrite('leaf_threshold.png',thresh)
cv2.imwrite('leaf_ellipse.png',result)
# show results
cv2.imshow("thresh", thresh)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
阈值图像:
椭圆图像:
椭圆信息:
126.44944763183594 101.98369598388672 112.40930938720703 112.40930938720703 89.33087158203125
So angle = 89.33087158203125 deg (cw from -y axis, i.e. from the top) or
angle = 0.66912841796875 deg (ccw from the x axis, i.e. from right side)
添加:
这是一个更完整的解决方案。但它假设叶子长于宽,因此椭圆长轴沿步进方向对齐。
叶1:
叶 2:
import cv2
import numpy as np
# read image
#img = cv2.imread('leaf1.jpg')
img = cv2.imread('leaf2.jpg')
# threshold on color
lower=(0,0,0)
upper=(130,190,140)
thresh = cv2.inRange(img, lower, upper)
# get contour
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
# fit ellipse to leaf contours
ellipse = cv2.fitEllipse(big_contour)
(xc,yc), (d1,d2), angle = ellipse
print(xc,yc,d1,d1,angle)
# draw ellipse on copy of input
graphic = img.copy()
cv2.ellipse(graphic, ellipse, (0,0,255), 1)
# rotate image so step points downward
if angle >= 135 and angle <=180:
result = cv2.rotate(img, cv2.ROTATE_180)
elif angle >= 45 and angle <135:
result = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)
elif angle >= 0 and angle <45:
result = img.copy()
# save results
cv2.imwrite('leaf2_threshold.png',thresh)
cv2.imwrite('leaf2_ellipse.png',graphic)
cv2.imwrite('leaf2_result.png',result)
# show results
cv2.imshow("thresh", thresh)
cv2.imshow("graphic", graphic)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
叶 1 阈值:
叶 1 椭圆:
叶 1 旋转:
叶 2 阈值:
叶 2 椭圆:
叶 2 旋转:
推荐阅读
- cron - 构建一个 cron 表达式以在定义的分钟内运行并且只运行一次(不可重复)
- python-2.7 - 如何从“timedelta 对象”中仅提取 HH:MM:SS 格式的时间
- c - 完美数字:为什么嵌套的 if 不起作用?
- javascript - 更新事件后的传单 svg
- javascript - FullCalendar 未在 Boostrap 4 选项卡中加载
- postgresql - 哈希连接导致没有剩余空间错误
- python - 如何在 OSMnx 中去除边缘
- c# - 使用 c# 从 excel 工作表中连续获取基于先前单元格值的其他单元格值
- wordpress - asc 和 desc 在 WP_Query 中的自定义 tax_query 中不起作用
- javascript - 对于按类查找 jQuery 的函数