I've been tackling a problem to characterize/decode bars in a barcode.
So far, I can localize and extract the barcode from surrounding image by:
After localizing, I copy the ROI and perform connectedcomponentswithstats(), which identifies the bars quite accurately. In the image below, I've iterated over the ROI horizontally, but because connectedcomponents seems to work left-right, top down, I'm missing bars.
If I rotate the ROI to vertical, then all bars are read in the correct order (reader's left-to-right when the barcode is horizontal).
What is the best way to sort labels generated by connectedcomponentswithstats() by the x-axis position (key=cv.CC_STAT_LEFT)?
I was thinking sort by sorted_by_cc_stat_left = sorted(analysis, key=cv.CC_STAT_LEFT)
, or
analysis.sorted(key=totalLabels[cv.CC_STAT_LEFT])
, but I can't figure out the right syntax.
analysis = cv.connectedComponentsWithStats(roi_image_copy,4, cv.CV_32S)
(totalLabels, label_ids, values, centroid) = analysis
output = np.zeros(roi_image_copy.shape, dtype="uint8")
# Loop through each component
for i in range(1, totalLabels):
# Area of the component
area = values[i, cv.CC_STAT_AREA]
if (area > 1) and (area < 400):
# Create a new image for bounding boxes
new_img = roi_image_copy.copy()
# Now extract the coordinate points
x1 = values[i, cv.CC_STAT_LEFT]
y1 = values[i, cv.CC_STAT_TOP]
w = values[i, cv.CC_STAT_WIDTH]
h = values[i, cv.CC_STAT_HEIGHT]
# Coordinate of the bounding box
pt1 = (x1, y1)
pt2 = (x1 + w, y1 + h)
(X, Y) = centroid[i]
new_img = cv.cvtColor(new_img, cv.COLOR_BGR2RGB)
# Bounding boxes for each component
cv.rectangle(new_img, pt1, pt2,
(255, 255, 0), 3)
cv.circle(new_img, (int(X),
int(Y)),
4, (0, 255, 255), -1)
# Create a new array to show individual component
component = np.zeros(roi_image_copy.shape, dtype="uint8")
componentMask = (label_ids == i).astype("uint8") * 255
# Apply the mask using the bitwise operator
component = cv.bitwise_or(component, componentMask)
output = cv.bitwise_or(output, componentMask)
# Show the final images
cv.imshow("Image", new_img)
cv.imshow("Individual Component", component)
cv.imshow("Filtered Components", output)
cv.waitKey(0)
Thanks for the read. I appreciate any insights so I can better understand this cool function!
Use np.argsort
to sort your connected components by centroid position.
y_coords = centroids[:,1] # use all of them. background skipped later.
indices = np.argsort(y_coords)
Now you can iterate over these indices
, and use each index to look up that component.
for index in indices:
if index == 0: continue # that's the background component
... # use `index` to access `values`
Note: make sure to skip component 0 (i.e. when index == 0
) because that's the background. If you excluded that before sorting, you'd have to mind the indexing (would require offsetting).