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