Sure!
Original image:
My code:
import cv2
import numpy as np
from scipy.spatial import distance
while True:
image = cv2.imread('/path/original-image.png')
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh, output_binthresh = cv2.threshold(image_gray, 48, 255, cv2.THRESH_BINARY)
cv2.imshow("Binary Threshold (fixed)", output_binthresh)
thresh, output_otsuthresh = cv2.threshold(image_gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
cv2.imshow("Binary Threshold (otsu)", output_otsuthresh)
output_adapthresh = cv2.adaptiveThreshold (image_gray, 253, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 51, 0)
cv2.imshow("Adaptive Thresholding", output_adapthresh)
kernel = np.ones((3,3),np.uint8)
output_erosion = cv2.erode(output_adapthresh, kernel)
cv2.imshow("Morphological Erosion", output_erosion)
contours, _ = cv2.findContours(output_erosion, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
output_contour = cv2.cvtColor(image_gray, cv2.COLOR_GRAY2BGR)
cv2.drawContours(output_contour, contours, -1, (0, 0, 255), 2)
cv2.imshow("Contours", output_contour)
contours_sorted = sorted(contours, key=lambda ctr: cv2.boundingRect(ctr)[0])
image_result = image.copy()
pixelsPerMm = 5.509
rices = []
for c in contours_sorted:
box = cv2.minAreaRect(c)
box = cv2.boxPoints(box)
box = np.array(box, dtype="int")
(top_left, top_right, bottom_right, bottom_left) = box
distance_a = distance.euclidean((top_left[0], top_left[1]), (top_right[0], top_right[1]))
distance_b = distance.euclidean((top_left[0], top_left[1]), (bottom_left[0], bottom_left[1]))
dimension_a = distance_a / pixelsPerMm
dimension_b = distance_b / pixelsPerMm
length = max(dimension_a, dimension_b)
width = min(dimension_a, dimension_b)
if length < 1.4 or length > 12.3:
continue
if width < 1.4 or width > 3.5:
continue
rice = [box.astype("int")]
# Check class
if length <= 1.6:
rices.append({'class': 'class1', 'box': rice, 'color': (255, 0, 255), 'width': width, 'length': length, 'top_right': top_right})
elif length <= 1.8:
rices.append({'class': 'class2', 'box': rice, 'color': (255, 0, 0), 'width': width, 'length': length, 'top_right': top_right})
elif length <= 3.8:
rices.append({'class': 'class3', 'box': rice, 'color': (0, 255, 0), 'width': width, 'length': length, 'top_right': top_right})
elif length <= 5.6:
rices.append({'class': 'class4', 'box': rice, 'color': (51, 255, 255), 'width': width, 'length': length, 'top_right': top_right})
elif length <= 12:
rices.append({'class': 'class5', 'box': rice, 'color': (0, 0, 255), 'width': width, 'length': length, 'top_right': top_right})
else:
continue
for rice in rices:
cv2.drawContours(image_result, rice['box'], -1, rice['color'], 1)
cv2.putText(image_result, "l={:.1f}mm".format(rice['length']), (rice['top_right'][0]-10, rice['top_right'][1]-20), cv2.FONT_HERSHEY_SIMPLEX, 0.3, (255, 255, 255), 1)
cv2.putText(image_result, "w={:.1f}mm".format(rice['width']), (rice['top_right'][0]-10, rice['top_right'][1]-10), cv2.FONT_HERSHEY_SIMPLEX, 0.3, (255, 255, 255), 1)
cv2.imshow("Result", image_result)
key = cv2.waitKey(1)
if key%256 == 27:
break
cv2.destroyAllWindows()