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

Python中如何为OpenCV提取的图像各轮廓区域生成直方图?

葡萄园热红外影像冠层误分像元剔除实现方案

环境准备

在PyCharm的终端执行以下命令安装依赖库:
pip install numpy opencv-python matplotlib scipy

核心实现逻辑

逐独立冠层轮廓做单独统计,避免不同区域冠层温度差异干扰阈值判断,整体流程:

  • 为每个检测到的冠层轮廓生成独立的填充掩膜
  • 提取轮廓范围内的有效像元,排除DEM初筛阶段已经标记为0的地面像元
  • 统计单区域内的温度值密度分布,自动划定温度阈值,剔除温度过高的误分地面像元
  • 汇总所有区域的有效冠层像元,生成修正后的最终掩膜
  • (可选)为每个轮廓单独输出温度密度直方图,方便校验阈值合理性

完整实现代码

首先确认你已经持有两个输入变量:

  • thermal_img:叠加DEM初筛掩膜后的热红外影像,为uint16类型的ndarray,尺寸6082×4922,已确认的地面像元值为0,冠层像元取值范围0-65535
  • contours:通过OpenCV cv2.findContours接口提取得到的冠层轮廓列表
import cv2
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import gaussian_kde

# 初始化修正后的冠层掩膜,尺寸与热影像一致,0代表地面,1代表冠层
refined_mask = np.zeros_like(thermal_img, dtype=np.uint8)

# 逐轮廓遍历处理
for contour_idx, contour in enumerate(contours):
    # 生成当前轮廓的独立填充掩膜
    single_contour_mask = np.zeros_like(thermal_img, dtype=np.uint8)
    cv2.drawContours(single_contour_mask, [contour], contourIdx=-1, color=1, thickness=-1)

    # 提取当前轮廓范围内的有效像元:在轮廓内、且值不为0(排除DEM初筛已识别的地面)
    roi_valid_pixels = thermal_img[(single_contour_mask == 1) & (thermal_img != 0)]

    # 跳过像元数不足10的噪点轮廓
    if len(roi_valid_pixels) < 10:
        continue

    # 阈值计算二选一即可,优先用分位法处理大尺寸影像
    # --- 方案1:分位阈值法(计算速度快,适合超大影像)---
    # 95表示取区域内温度从低到高排95%位置的值作为阈值,高于该值判定为地面
    # 该参数可根据实际误分情况调整:误分多就调低,误删冠层就调高
    temp_threshold = np.percentile(roi_valid_pixels, 95)

    # --- 方案2:KDE密度峰值法(精度更高,适合温度双峰分布明显的场景,计算速度慢)---
    # kde_model = gaussian_kde(roi_valid_pixels)
    # temp_series = np.arange(roi_valid_pixels.min(), roi_valid_pixels.max() + 1)
    # density_curve = kde_model(temp_series)
    # peak_pos = np.argmax(density_curve)
    # # 从密度峰值往高温方向遍历,取密度降到峰值10%的位置作为阈值
    # threshold_candidate = np.where(density_curve[peak_pos:] < density_curve[peak_pos] * 0.1)[0]
    # temp_threshold = temp_series[peak_pos + threshold_candidate[0]] if len(threshold_candidate) > 0 else np.percentile(roi_valid_pixels, 95)

    # 提取当前轮廓内符合冠层温度要求的像元坐标,写入最终掩膜
    roi_coord_y, roi_coord_x = np.where((single_contour_mask == 1) & (thermal_img != 0))
    valid_pixel_flag = thermal_img[roi_coord_y, roi_coord_x] <= temp_threshold
    refined_mask[roi_coord_y[valid_pixel_flag], roi_coord_x[valid_pixel_flag]] = 1

    # 可选:生成当前轮廓的温度密度直方图并保存
    plt.figure(figsize=(8, 4))
    plt.hist(roi_valid_pixels, bins=50, density=True, alpha=0.7, label="区域原始像元分布")
    plt.axvline(temp_threshold, color="red", linestyle="--", label=f"剔除阈值:{temp_threshold}")
    plt.title(f"冠层区域{contour_idx+1}温度分布")
    plt.xlabel("热影像DN值(对应温度)")
    plt.ylabel("像元密度")
    plt.legend()
    plt.savefig(f"contour_{contour_idx+1}_hist.png", dpi=150, bbox_inches="tight")
    plt.close()

# 生成修正后的热影像:地面像元全部置0,仅保留冠层温度值
refined_thermal_img = thermal_img * refined_mask

使用说明

  • 代码内存占用极低,常规16G内存设备即可流畅处理6082×4922尺寸的影像,不需要额外分块
  • 优先使用分位阈值法,单张影像处理耗时通常在10秒以内;如果需要更高精度可以切换KDE法,处理耗时会提升数倍
  • 阈值参数需要结合实地采样结果校准:如果结果里残留的误分地面像元多,可以把分位值从95下调到9093;如果发现冠层高温像元被误删,可以把分位值上调到9698
  • 输出的refined_mask是标准二值掩膜,可以直接用于后续温度统计、产量反演等后续分析

内容的提问来源于stack exchange,提问作者Thomas Hallemeesch

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 19:18:26