Find and split shelves from an image

118 Views Asked by At

I need to find and split each shelves from planogram image. In this case split using blue(it can be black, gray, etc.) lines so it should give me 8 shelves. I tried using Hough lines, contours to recognize the shelf. Tell me, please, how to recognize shelves.

enter image description here

Here's my code:

import cv2
import numpy as np

# Load the image
img = cv2.imread("display.jpg")

# Convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Threshold the image to binarize it
threshold, binary = cv2.threshold(gray, 128, 255, cv2.THRESH_BINARY_INV)

# Find contours
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# Loop through each contour
for i, contour in enumerate(contours):
    # Get bounding box of contour
    x, y, w, h = cv2.boundingRect(contour)

    # Crop the image to the bounding box
    shelf_img = img[y:y+h, x:x+w]

    # Save the cropped image
    cv2.imwrite(f"shelf_{i}.jpg", shelf_img)

Here's the second approach:

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

# In[5]:


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


# In[6]:


image = imread("display.jpg", as_gray=True) * 255


# In[7]:


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('Input image')
ax[0].axis('image')

ax[1].imshow(edges, cmap=plt.cm.gray)
ax[1].set_title('Canny edges')
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('Probabilistic Hough')
ax[2].axis('image')


# In[8]:


height, width = image.shape


# In[9]:


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])


# In[10]:


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)


# In[11]:


#fig2, ax = plt.subplots(1, 2, figsize=(8, 8))
plt.figure(figsize=(20, 10))
plt.imshow(image, cmap=plt.cm.gray)
plt.title('Input image')
plt.plot(s_h, np.arange(height), linewidth=2, label="s_h")
plt.plot(s_v, np.arange(height), linewidth=2, label="s_v")
plt.ylim([height, 0])
plt.xlim([0, width])
plt.legend()


# In[13]:


import scipy.ndimage
s_f = 20 * s_h / (s_v + 1)
s_f = scipy.ndimage.gaussian_filter1d(s_f, 1)


# In[14]:


plt.figure(figsize=(20, 10))
plt.imshow(image, cmap=plt.cm.gray)
plt.title('Input image')
plt.plot(s_f, np.arange(height), linewidth=2, label="s_h")
plt.ylim([height, 0])
plt.xlim([0, width])


# In[15]:


import scipy.signal


# In[26]:


cands = scipy.signal.find_peaks_cwt(s_f, np.arange(1, 50))
print(zip(cands, s_f[cands]))


# In[18]:


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


# In[19]:


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


# In[20]:


y0, y1 = y_tagets


# In[21]:


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('Input image')
ax.add_patch(
    patches.Rectangle(
        (0, y0),
        width,
        y1 - y0,
        facecolor="red",
        alpha=0.4      # remove background
    )
)
0

There are 0 best solutions below