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

如何从Planogram图像中识别并分割8层货架?(已试Hough线、轮廓法)

货架识别与分割方案求助

需求

  • 从Planogram图像中识别并分割出全部货架,使用蓝色(或黑色、灰色等)线条进行分割,最终需得到8层货架。

已尝试方法

  • 采用Hough线变换、轮廓检测法识别货架,但未实现预期目标。

参考图像

货架平面图

已尝试代码1(OpenCV轮廓法)

import cv2
import numpy as np

# 加载图像
img = cv2.imread("display.jpg")

# 转换为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 阈值二值化
threshold, binary = cv2.threshold(gray, 128, 255, cv2.THRESH_BINARY_INV)

# 查找轮廓
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 遍历轮廓并裁剪保存
for i, contour in enumerate(contours):
    # 获取轮廓外接矩形
    x, y, w, h = cv2.boundingRect(contour)
    # 裁剪货架区域
    shelf_img = img[y:y+h, x:x+w]
    # 保存裁剪后的图像
    cv2.imwrite(f"shelf_{i}.jpg", shelf_img)

已尝试代码2(Scikit-image Hough线法)

#!/usr/bin/env python
# coding: utf-8

from skimage.transform import (hough_line, hough_line_peaks,probabilistic_hough_line)
from skimage.feature import canny
from skimage import data
from skimage.io import imread
import numpy as np
import matplotlib.pyplot as plt

from skimage.filters import roberts, sobel, scharr

# 加载图像
image = imread("display.jpg", as_gray=True) * 255

# Canny边缘检测+概率Hough线检测
edges = canny(image, 4, 1, 25)
lines = probabilistic_hough_line(edges, threshold=2, line_length=10, line_gap=3)

# 可视化检测结果
fig2, ax = plt.subplots(1, 3, figsize=(20, 8))
ax[0].imshow(image, cmap=plt.cm.gray)
ax[0].set_title('输入图像')
ax[0].axis('image')

ax[1].imshow(edges, cmap=plt.cm.gray)
ax[1].set_title('Canny边缘')
ax[1].axis('image')

ax[2].imshow(edges * 0)
for line in lines:
    p0, p1 = line
    ax[2].plot((p0[0], p1[0]), (p0[1], p1[1]))
ax[2].set_title('概率Hough线检测')
ax[2].axis('image')

height, width = image.shape

# 定义投影计算函数
def proj_x(line):
    p0, p1 = line
    return np.abs(p0[0] - p1[0])

def proj_y(line):
    p0, p1 = line
    return np.abs(p0[1] - p1[1])

# 统计水平/垂直线投影
s_h = np.zeros(height)
s_v = np.zeros(height)
for line in lines:
    p0, p1 = line
    y1 = max(p0[1], p1[1])
    y0 = min(p0[1], p1[1])
    if proj_y(line) > 2:
        s_v[y0: y1] += proj_y(line)
    if proj_x(line) > 2:
        s_h[y0: y1] += proj_x(line)

# 可视化投影结果
plt.figure(figsize=(20, 10))
plt.imshow(image, cmap=plt.cm.gray)
plt.title('输入图像')
plt.plot(s_h, np.arange(height), linewidth=2, label="水平投影")
plt.plot(s_v, np.arange(height), linewidth=2, label="垂直投影")
plt.ylim([height, 0])
plt.xlim([0, width])
plt.legend()

# 投影特征滤波
import scipy.ndimage
s_f = 20 * s_h / (s_v + 1)
s_f = scipy.ndimage.gaussian_filter1d(s_f, 1)

plt.figure(figsize=(20, 10))
plt.imshow(image, cmap=plt.cm.gray)
plt.title('输入图像')
plt.plot(s_f, np.arange(height), linewidth=2, label="滤波后投影")
plt.ylim([height, 0])
plt.xlim([0, width])

# 峰值检测与候选区域提取
import scipy.signal
cands = scipy.signal.find_peaks_cwt(s_f, np.arange(1, 50))
print(zip(cands, s_f[cands]))

pairs = []
for c in cands:
    for d in cands:
        if (c < d) and (d -c < 100):
            pairs.append((c, d))

y_tagets = pairs[np.argmax([s_f[a] * s_f[b] for a, b in pairs])]
y0, y1 = y_tagets

# 可视化候选货架区域
import matplotlib.patches as patches
fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111, aspect='equal')
ax.imshow(image, cmap=plt.cm.gray)
ax.set_title('输入图像')
ax.add_patch(
    patches.Rectangle(
        (0, y0),
        width,
        y1 - y0,
        facecolor="red",
        alpha=0.4
    )
)

可行优化方案

1. Hough线变换针对性优化

  • 筛选水平线:货架层为水平结构,计算每条检测线的斜率,只保留斜率绝对值小于0.1的线条,排除垂直/倾斜干扰线。
  • 聚类合并相近线条:将筛选后的水平线按y坐标做K-means聚类(指定聚类数为8),取聚类中心作为最终的货架分割线,避免重复检测。
  • 增强水平边缘:用Sobel算子单独提取水平边缘,或在Canny检测前做高斯模糊降噪,突出货架的水平结构。

2. 水平投影分析法

  • 计算灰度图的水平像素和,货架区域的投影曲线会出现明显的极值点;对投影曲线做高斯平滑后,提取局部极值点作为分割线。
  • 替换固定阈值为自适应阈值二值化,应对图像光照不均问题,更好保留货架结构。

3. 形态学操作辅助

  • 用水平方向的结构元素(如cv2.getStructuringElement(cv2.MORPH_RECT, (50,1)))做开运算,过滤垂直干扰,强化水平货架线。
  • 对二值图做闭运算,填补货架线的间隙,让水平结构更连贯。

优化后代码示例(Hough线+K-means聚类)

import cv2
import numpy as np
from sklearn.cluster import KMeans

# 加载图像
img = cv2.imread("display.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 高斯模糊+Sobel水平边缘检测
blur = cv2.GaussianBlur(gray, (5,5), 0)
sobel_x = cv2.Sobel(blur, cv2.CV_64F, 1, 0, ksize=3)
abs_sobel = np.uint8(np.absolute(sobel_x))
_, binary = cv2.threshold(abs_sobel, 50, 255, cv2.THRESH_BINARY)

# Hough线检测(只保留长水平线)
lines = cv2.HoughLinesP(binary, 1, np.pi/180, threshold=100, minLineLength=img.shape[1]*0.8, maxLineGap=20)

# 筛选水平线的y坐标
horizontal_lines = []
for line in lines:
    x1,y1,x2,y2 = line[0]
    if abs(y2-y1) < 10:  # 过滤非水平线
        horizontal_lines.append((y1 + y2)//2)

# K-means聚类得到8个分割线
kmeans = KMeans(n_clusters=8, random_state=42)
kmeans.fit(np.array(horizontal_lines).reshape(-1,1))
shelf_y = sorted(kmeans.cluster_centers_.flatten())

# 绘制蓝色分割线
result_img = img.copy()
for y in shelf_y:
    y = int(y)
    cv2.line(result_img, (0, y), (img.shape[1], y), (255,0,0), 2)

# 保存结果
cv2.imwrite("shelf_divided.jpg", result_img)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 20:41:07