这是 Python/OpenCV 中一个非常简单的方法。
- Read the input image
- Convert to HSV and save the Hue channel
- Threshold at 165 since the beads are on the blue side of red and so have a high value out of 180. (OpenCV hues range from 0 to 180, which is half the normal 0 to 360 range).
- Apply morphology open and close to remove excess white spots and fill holes.
- Find external contours
- Loop over each contour and get the minimum enclosing circles radii and center
- Draw the circles on a copy of the input
- Compute the average radius
- Save results and print average radius
输入:
import cv2
import numpy as np
# Read image
img = cv2.imread('beads.jpg')
# Convert to HSV and keep the hue channel
hue = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)[:,:,0]
# beads are red but on the blue side, so very bright hues
# so threshold hue at 165 (out of 180)
thresh = cv2.threshold(hue, 165, 255, cv2.THRESH_BINARY)[1]
# apply morphology to fill beads and remove excess spots
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (6,6))
morph = cv2.morphologyEx(morph, cv2.MORPH_CLOSE, kernel)
# get contours and enclosing circles
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
circles = img.copy()
num_circles = len(contours)
ave = 0
for cntr in contours:
center, radius = cv2.minEnclosingCircle(cntr)
cx = int(round(center[0]))
cy = int(round(center[1]))
rr = int(round(radius))
# draw enclosing circle over beads
cv2.circle(circles, (cx,cy), rr, (0, 255, 0), 2)
# cumulate radii for average
ave = ave + radius
# print average radius
ave_radius = ave / num_circles
print("average radius:", ave_radius)
print ("number of circles:", num_circles)
# save results
cv2.imwrite('beads_thresh.jpg', thresh)
cv2.imwrite('beads_morph.jpg', morph)
cv2.imwrite('beads_circles.jpg', circles)
cv2.imshow('thresh', thresh)
cv2.imshow('morph', morph)
cv2.imshow('circles', circles)
cv2.waitKey(0)
cv2.destroyAllWindows()
阈值图像:
形态清洁图像:
输入的圆圈:
平均半径和计数:
average radius: 13.95605175635394
number of circles: 34