You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python准确计数航拍图像中的树木及获取轮廓数量

解决航拍图像树木计数问题的分步方案

嘿,作为图像处理新手,你已经迈出了很棒的第一步!咱们一步步拆解你的问题,先搞定计数错误的根源,再解决轮廓数量的获取问题。

一、最初计数结果为7的原因分析

你最初的流程里,虽然做了HSV分割和高斯模糊,但分割后的绿色区域大概率是大片连在一起的——航拍图里树木往往挨得近,高斯模糊又会让边缘更模糊,导致多个树木被当成了一个连通区域,所以measure.label(drops)只识别出7个大区域,而不是单个树木。

二、获取轮廓数量的正确方法

你补充的代码里,contours是OpenCV找到的轮廓列表,想要获取数量直接用len(contours)就可以啦!不过要注意:

  • 不要用contour.size()(这是单个轮廓的方法,你遍历的是每个cnt,而contours是列表)
  • 建议过滤掉面积太小的轮廓,避免把噪声误当成树木,比如:
tree_count = 0
min_contour_area = 100  # 根据你的图像大小调整这个值
for cnt in contours:
    if cv2.contourArea(cnt) > min_contour_area:
        tree_count += 1
        cv2.drawContours(finalImage,[cnt],0,(0,0,255),1)
print(f"树木数量:{tree_count}")

三、优化后的完整树木计数流程

针对航拍图树木计数,我们需要调整预处理和分割步骤,让相邻树木尽可能分开:

1. 更精准的HSV绿色分割

航拍图的绿色可能因为光照、阴影有变化,你可以调整HSV阈值,或者用更灵活的范围;另外,不要先转PIL的HSV再存盘读取,直接用OpenCV处理更高效:

import cv2
import numpy as np
from skimage import measure

# 直接读取原始图像
img = cv2.imread("D:\\Texture analysis\\K-2.jpg")
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# 调整HSV阈值,适配航拍绿色(可以根据实际图像微调)
lower_green = np.array([30, 20, 20])
upper_green = np.array([80, 255, 255])
mask = cv2.inRange(hsv, lower_green, upper_green)

# 先去除小噪声(开运算:先腐蚀后膨胀,比单纯腐蚀更能保留树木形状)
kernel = np.ones((5,5), np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=2)

# 填充树木内部的孔洞
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=3)

2. 分离相邻树木的关键操作

如果树木还是连在一起,可以用距离变换+阈值分割来分开它们:

# 距离变换:计算每个前景像素到背景的距离
dist_transform = cv2.distanceTransform(mask, cv2.DIST_L2, 5)
# 阈值化,得到单个树木的种子区域
ret, sure_fg = cv2.threshold(dist_transform, 0.3*dist_transform.max(), 255, 0)
sure_fg = np.uint8(sure_fg)

# 找到未知区域(用于分水岭算法)
sure_bg = cv2.dilate(mask, kernel, iterations=3)
unknown = cv2.subtract(sure_bg, sure_fg)

# 标记种子区域
ret, markers = cv2.connectedComponents(sure_fg)
markers = markers + 1
markers[unknown==255] = 0

# 应用分水岭算法分割相邻树木
markers = cv2.watershed(img, markers)
img[markers == -1] = [255,0,0]  # 用红色标记分割线

3. 最终计数

用measure.label或者轮廓计数都可以:

# 方法1:用skimage的label计数
labels = measure.label(sure_fg)
print(f"树木数量(skimage):{labels.max()}")

# 方法2:用OpenCV轮廓计数
contours, hierarchy = cv2.findContours(sure_fg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 过滤小轮廓
tree_count = sum(1 for cnt in contours if cv2.contourArea(cnt) > 150)
print(f"树木数量(OpenCV):{tree_count}")

四、小提示

  • 如果你不确定HSV阈值,可以用OpenCV的滑动条工具实时调整,找到最适合你图像的范围
  • 形态学操作的kernel大小和迭代次数需要根据图像分辨率调整,比如高分辨率图可以用更大的kernel
  • 分水岭算法对种子区域的质量很敏感,调整0.3*dist_transform.max()这个系数可以优化分割效果

内容的提问来源于stack exchange,提问作者Kamil Hassaan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 09:02:01