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

Python中非结构化形状识别:岩石目标计数、像素面积统计及粘连块分割优化求助

Python中非结构化形状识别:岩石目标计数、像素面积统计及粘连块分割优化求助

看起来你现在卡在岩石检测的粘连分割上了——你的现有代码已经尝试了自适应阈值+固定阈值的组合,还做了开运算去噪,但还是没法把连在一起的岩石准确分开对吧?针对你的场景(浅色背景下的深色不规则岩石),我给你几个针对性的优化方案,结合代码调整应该能解决问题:

核心优化方向:用分水岭算法处理粘连目标

分水岭算法是处理这类紧密粘连物体分割的经典方法,它能基于距离变换找到每个目标的“种子点”,然后精准分割开粘连的区域,非常适合你的岩石检测场景。

代码优化实现

我在你的原有代码基础上做了修改,加入了距离变换、种子点标记和分水岭分割的步骤,同时优化了形态学操作和阈值参数:

import cv2
import numpy as np
import matplotlib.pyplot as plt

image_path = "medium.png"
original_image = cv2.imread(image_path)
gray_image = cv2.cvtColor(original_image, cv2.COLOR_BGR2GRAY)

# 1. 优化阈值组合:适配岩石的灰度特征
_, binary_global = cv2.threshold(gray_image, 220, 255, cv2.THRESH_BINARY_INV)
binary_adaptive = cv2.adaptiveThreshold(gray_image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, 
                                       cv2.THRESH_BINARY_INV, 15, 3)
combined_binary = cv2.bitwise_or(binary_global, binary_adaptive)

# 2. 形态学操作:先补空洞再去噪,保证前景完整性
kernel_close = np.ones((3,3), np.uint8)
closed = cv2.morphologyEx(combined_binary, cv2.MORPH_CLOSE, kernel_close, iterations=2)
kernel_open = np.ones((2,2), np.uint8)
cleaned_binary = cv2.morphologyEx(closed, cv2.MORPH_OPEN, kernel_open, iterations=1)

# 3. 距离变换+分水岭:分割粘连核心步骤
# 距离变换:计算每个前景像素到最近背景的距离,找到岩石中心区域
dist_transform = cv2.distanceTransform(cleaned_binary, cv2.DIST_L2, 5)
# 确定前景种子点:取距离变换峰值区域作为每个岩石的核心
_, sure_fg = cv2.threshold(dist_transform, 0.3*dist_transform.max(), 255, 0)
sure_fg = np.uint8(sure_fg)
# 确定背景区域:膨胀操作扩大背景范围
sure_bg = cv2.dilate(cleaned_binary, np.ones((3,3), np.uint8), iterations=3)
# 找到前景/背景的过渡区域
unknown = cv2.subtract(sure_bg, sure_fg)

# 标记种子点:给每个前景核心分配唯一ID
_, markers = cv2.connectedComponents(sure_fg)
# 调整标记值:背景从0改为1,过渡区域保持0
markers = markers + 1
markers[unknown==255] = 0

# 应用分水岭分割,分割线用红色标记
markers = cv2.watershed(original_image, markers)
original_image[markers == -1] = [255,0,0]

# 4. 提取分割后的轮廓并统计数据
contours, _ = cv2.findContours(sure_fg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

output_image = np.ones_like(original_image) * 255
np.random.seed(42)
hues = np.linspace(0, 179, len(contours), dtype=np.uint8)
np.random.shuffle(hues)
colors = []
for hue in hues:
    hsv = np.array([[[hue, 255, 255]]], dtype=np.uint8)
    rgb = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)[0][0]
    colors.append(rgb.tolist())

min_area_threshold = 15  # 可根据岩石实际大小调整
valid_rocks = 0
rock_pixel_areas = []

for i, contour in enumerate(contours):
    area = cv2.contourArea(contour)
    if area >= min_area_threshold:
        valid_rocks += 1
        rock_pixel_areas.append(area)
        # 绘制分割后的岩石区域
        cv2.drawContours(output_image, [contour], -1, colors[i % len(colors)], -1)
        cv2.drawContours(output_image, [contour], -1, (0,0,0), 1)

# 可视化结果
plt.figure(figsize=(16, 10))
plt.subplot(131)
plt.imshow(cv2.cvtColor(original_image, cv2.COLOR_BGR2RGB))
plt.title('Watershed Segmentation (Red Lines = Boundaries)')
plt.axis('off')

plt.subplot(132)
plt.imshow(cleaned_binary, cmap='gray')
plt.title('Preprocessed Binary Image')
plt.axis('off')

plt.subplot(133)
plt.imshow(cv2.cvtColor(output_image, cv2.COLOR_BGR2RGB))
plt.title(f'Total Rocks Detected: {valid_rocks}')
plt.axis('off')

plt.tight_layout()
plt.show()

# 输出统计结果
print(f"Total number of rocks detected: {valid_rocks}")
print(f"Pixel area of each rock: {[round(area, 2) for area in rock_pixel_areas]}")
print(f"Average rock pixel area: {np.mean(rock_pixel_areas):.2f}")

# 保存结果
cv2.imwrite('watershed_result.png', original_image)
cv2.imwrite('segmented_rocks.png', output_image)

关键步骤解释

  1. 阈值优化:调整固定阈值到220、自适应阈值块大小到15,让岩石区域更完整地被提取,减少遗漏
  2. 形态学操作顺序调整:先闭运算填补岩石内部小空洞,再开运算去掉背景噪点,保证前景区域的完整性
  3. 距离变换+分水岭:
    • 距离变换定位每个岩石的中心核心区域(种子点)
    • 通过膨胀和减法确定确定的前景、背景和过渡区域
    • 基于种子点用分水岭分割粘连区域,红色线条是分割边界
  4. 数据统计:不仅统计岩石数量,还通过cv2.contourArea直接获取每个岩石的像素面积,满足你的统计需求

额外调参建议

  • 如果出现过度分割/分割不足,可以调整距离变换的阈值(0.3*dist_transform.max()),比如改成0.2或0.4
  • 若背景仍有噪点,可增大开运算的kernel尺寸(如(3,3))或增加迭代次数
  • 可加入形状过滤:计算轮廓的圆度(4*np.pi*area / (perimeter**2)),过滤掉形状过于不规则的非岩石区域

备注:内容来源于stack exchange,提问作者Razark

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 19:53:09