You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于卫星图像的农田作物区域检测:OpenCV处理难题求助

卫星农田地块检测的基础方法建议

嗨,我来给你几个适合从基础入手的实用思路,帮你搞定卫星图像里的作物区域检测~

一、优化阈值与形态学处理,规整二值图像

你现在用全局阈值得到的结果噪点多、轮廓乱,核心原因是卫星图像光照不均,全局阈值没法适配局部区域。可以试试这两个方向:

  • 自适应阈值/Otsu阈值:自适应阈值会根据每个局部区域的灰度调整阈值,能更好应对光照差异;Otsu阈值则会自动计算最优的全局阈值,适合灰度分布比较明显的图像。可以结合高斯模糊后使用,示例代码:
    import cv2
    import numpy as np
    
    # 转灰度+高斯模糊
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(gray, (5, 5), 0)
    # 自适应阈值(反二值化,让农田区域为白色)
    thresh = cv2.adaptiveThreshold(blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
    
  • 形态学操作清洗图像:阈值后的图像难免有小噪点或空洞,用开运算(先腐蚀再膨胀)去掉细碎噪点,闭运算填补小空洞,让地块轮廓更规整:
    # 创建结构元素
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
    # 开运算去噪
    cleaned_thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
    # 闭运算补空洞
    cleaned_thresh = cv2.morphologyEx(cleaned_thresh, cv2.MORPH_CLOSE, kernel, iterations=1)
    

二、用好你提到的洪水填充,精准定位单地块

洪水填充确实适合检测点击位置的地块,只要调整好容差就能避免溢出到其他地块:

  • 先对图像做平滑处理(比如高斯模糊),减少局部灰度波动;
  • 设置合适的loDiffupDiff参数,同一块农田的灰度差异一般不大,可以设为10-20左右;
  • 示例代码(假设你用鼠标点击获取种子点(x,y)):
    # 复制图像用于绘制结果
    flood_img = img.copy()
    # 设置填充的掩码(要比原图大2px)
    mask = np.zeros((img.shape[0]+2, img.shape[1]+2), np.uint8)
    # 洪水填充,用红色标记目标地块
    cv2.floodFill(flood_img, mask, (x,y), (0,0,255), loDiff=(10,10,10), upDiff=(10,10,10))
    

如果想自动检测所有地块,可以先通过轮廓检测找到每个地块的种子点(比如轮廓中心),再批量做洪水填充。

三、换个颜色空间,精准提取作物区域

卫星图像的RGB空间不一定是最优选择,试试HSV或LAB空间,作物的绿色在这些空间里更容易区分:
比如用HSV提取绿色作物区域:

# 转HSV颜色空间
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 定义绿色的HSV范围(根据你的图像微调,不同卫星图像的绿色色调可能有差异)
lower_green = np.array([30, 40, 40])
upper_green = np.array([90, 255, 255])
# 生成绿色掩码
green_mask = cv2.inRange(hsv, lower_green, upper_green)
# 再对掩码做形态学清洗,之后就能找轮廓了

四、轮廓检测+筛选,区分不同地块

不管用阈值还是颜色掩码得到二值图后,都可以用轮廓检测提取地块,再过滤掉小噪点:

# 找外部轮廓
contours, _ = cv2.findContours(cleaned_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 筛选掉面积太小的轮廓(根据图像分辨率调整min_area)
min_area = 1000
valid_fields = [cnt for cnt in contours if cv2.contourArea(cnt) > min_area]
# 在原图上绘制地块轮廓
result = img.copy()
cv2.drawContours(result, valid_fields, -1, (0,255,0), 2)

进阶小技巧(不用CNN也能提升效果)

如果想再提升鲁棒性,可以试试超像素分割,OpenCV的cv2.ximgproc.createSuperpixelSLIC()能把图像分成相似的小色块,之后合并颜色/灰度相近的相邻块,就能得到更规整的地块区域,比单纯的阈值分割更能应对复杂的图像情况。

先从这些基础方法试起,比如先尝试“HSV颜色提取+形态学清洗+轮廓检测”的组合,效果应该会比单纯的灰度阈值好很多~

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

火山引擎 最新活动