cv2.contourArea异常:如何筛选夜间地球照片中的大型光污染区域
解决小型光污染轮廓残留问题的方案
你遇到的这个残留小轮廓的问题,核心是踩了一个Python列表遍历的常见坑:在正向遍历列表的同时删除元素,会导致索引错位,部分小轮廓没被检查到。
当你用enumerate正向遍历contours时,每删掉一个元素,列表长度就会变短,后面的轮廓会自动往前移一位,下一次循环的索引就会跳过一个元素,所以总有一些小轮廓躲过去了。下面给你两种靠谱的解决方法,还有额外的优化建议:
方法1:反向遍历列表(直接修改原列表)
反向遍历的时候,删除后面的元素不会影响前面未遍历的元素索引,这样就能确保每个轮廓都被检查到:
# 从最后一个元素往前遍历 for counter in range(len(contours)-1, -1, -1): if cv2.contourArea(contours[counter]) < 250.0: contours.pop(counter)
方法2:创建新列表存储符合条件的轮廓(更推荐)
这种方法不修改原列表,而是直接筛选出符合面积要求的轮廓存入新列表,逻辑更清晰,也不容易出错:
# 列表推导式快速筛选面积≥250的轮廓 big_contours = [cnt for cnt in contours if cv2.contourArea(cnt) >= 250.0]
之后绘制轮廓的时候直接用big_contours就可以了。
额外优化:先做形态学预处理减少小轮廓
如果原图里的小型光污染噪点很多,建议在找轮廓之前先对二值图做开运算(先腐蚀后膨胀),提前把小噪点去掉,这样后续生成的轮廓数量会少很多,处理效率更高:
import cv2 import numpy as np image_orig = cv2.imread('C:\\Users\\pc\\Desktop\\middleeast.jpg') image_gray = cv2.cvtColor(image_orig, cv2.COLOR_BGR2GRAY) _, image_threshold = cv2.threshold(image_gray, 60, 255, cv2.THRESH_BINARY) # 定义5x5的矩形结构元素,可根据噪点大小调整尺寸 kernel = np.ones((5,5), np.uint8) # 开运算:先腐蚀消除小噪点,再膨胀恢复大区域形状 image_clean = cv2.morphologyEx(image_threshold, cv2.MORPH_OPEN, kernel) # 从清理后的二值图提取轮廓 _, contours, _ = cv2.findContours(image_clean, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE) # 筛选大轮廓 big_contours = [cnt for cnt in contours if cv2.contourArea(cnt) >= 250.0] # 绘制并展示结果 image_big_contours = image_orig.copy() cv2.drawContours(image_big_contours, big_contours, -1, (255,255,0), 1) cv2.imshow('big contours', image_big_contours) cv2.waitKey(0) cv2.destroyAllWindows()
开运算的作用是精准清除小的亮区域,同时不会破坏大型光污染区域的轮廓形状,能从根源上减少需要处理的小轮廓数量。
内容的提问来源于stack exchange,提问作者Krulg
相关产品推荐
相关产品推荐

