我正在数一群蟋蟀(昆虫)的数量。我将使用 openCV 库的图像处理方法。当农民出售他们的蟋蟀时,这将提供更准确的练习。照片是用智能手机拍摄的。不幸的是,结果并不如预期。由于大多数蟋蟀相互重叠,我的代码无法将它们分开,导致计数不正确。
我应该用什么方法来解决这个问题?我的代码有问题吗?
蟋蟀图片
这是我的代码。
import cv2
import numpy as np
img = cv2.imread("c1.jpg",1)
roi=img[0:1500,0:1100]
gray = cv2.cvtColor(roi,cv2.COLOR_BGR2GRAY)
gray_blur=cv2.GaussianBlur(gray,(15,15),0)
thresh = cv2.adaptiveThreshold(gray_blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY_INV,11,1)
kernel=np.ones((1,1),np.uint8)
closing=cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,kernel,iterations=10)
result_img=closing.copy()
contours,hierachy=cv2.findContours(result_img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
counter=0
for cnt in contours:
area = cv2.contourArea(cnt)
if area < 150 :
#if area< 300 :
continue
counter+=1
ellipse = cv2.fitEllipse(cnt)
cv2.ellipse(roi,ellipse,(0,255,0),1)
cv2.putText(roi,"Crickets="+str(counter),(100,70),cv2.FONT_HERSHEY_SIMPLEX,1,(255,0,0),1,cv2.LINE_AA)
cv2.imshow('ImageOfCrickets',roi)
#cv2.imshow('ImageOfGray',gray)
#cv2.imshow('ImageOfGray_blur',gray_blur)
#cv2.imshow('ImageOfThreshold',thresh)
#cv2.imshow('ImageOfMorphology',closing)
print('Crickets = '+ str(counter))
cv2.waitKey(0)
cv2.destroyAllWindows()
现在,我正在使用闭合形态学和等高线层次结构进行椭圆形方法。
这里有一个选项。使用自适应阈值,执行腐蚀/扩张和高斯模糊,然后轮廓,然后按大小和纵横比过滤它们,最后找到每个过滤轮廓的质心。
import cv2
# Load the image
img = cv2.imread('insects.jpg')
# Convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray,(3,3),2)
# Threshold the grayscale image
thresh = cv2.adaptiveThreshold(gray,300,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY_INV,85,-21)
# # Perform morphological operations
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (9,9))
thresh = cv2.erode(thresh, kernel, iterations=2)
thresh = cv2.dilate(thresh, kernel, iterations=1)
thresh = cv2.GaussianBlur(thresh, (3,3), 1)
# Find contours
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
print(contours)
# Filter contours by area and aspect ratio
min_area = 500 # minimum area of contour
max_area = 10000 # maximum area of contour
min_aspect_ratio = 0.3 # minimum aspect ratio of contour
max_aspect_ratio = 3 # maximum aspect ratio of contour
filtered_contours = []
for contour in contours:
area = cv2.contourArea(contour)
x, y, w, h = cv2.boundingRect(contour)
aspect_ratio = float(w) / h if h != 0 else 0
if area >= min_area and area <= max_area and aspect_ratio >= min_aspect_ratio and aspect_ratio <= max_aspect_ratio:
filtered_contours.append(contour)
print(contour)
# Compute centers of mass and draw circles for filtered contours
for contour in filtered_contours:
# Compute moments of the contour
M = cv2.moments(contour)
if M['m00'] != 0:
# Compute center of mass
cx = int(M['m10'] / M['m00'])
cy = int(M['m01'] / M['m00'])
# Draw circle at center of mass
cv2.circle(img, (cx, cy), 5, (0, 255, 0), -1)
# Show the original image with filtered contours
cv2.drawContours(img, filtered_contours, -1, (0, 0, 255), 2)
cv2.imwrite('Image_contours.jpg', img)
cv2.imshow('Gray', gray)
cv2.imwrite('image_thresholded_preprocessed.jpg', thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()
另一种选择,类似于这里所做的事情:
图像是经过阈值处理的(不是昆虫是白色的),以及带有中心(红点)的轮廓。在现实中不是很好,但我能想到的最好的。似乎有很多工作要做,但解决误报(在空白处)的方法可能是通过第二次传递去除质心不暗的轮廓。
这是一个答案,使用新发布的 Meta 的
Segment Anything
库来完成繁重的工作,而 OpenCV 仅用于操作。我刚看了一个关于 Segment Anything 的 youtube 视频,想用这个问题来测试一下,这个问题困扰了我一段时间——我喜欢这个例子,因为对我来说这并不容易。
roboflow 的这篇博文非常有用:Roboflow:如何使用分段任何模型 (SAM)。
github页面中的信息也很有帮助:GitHub Facebook Research: Automatic mask generation (facebook research's Segment Anything)
这是代码,最后计算出 135 只昆虫(一些重复计算)。为了提取适当的蒙版,蒙版按区域(相对于图像区域)进行过滤。可能有更好的过滤方法,例如,您还可以按纵横比过滤 - 这可能会丢弃腹部并允许增加区域范围。
这是代码。很短,但有点慢。也许使用灰度可以加快速度。
# Import Libraries
import cv2, torch
import supervision as sv
from segment_anything import SamAutomaticMaskGenerator, sam_model_registry, SamAutomaticMaskGenerator
# Note that Segment anything requires that you download the checkpoint. In my case I downloaded it to the same path as the image
# Replace the following with the actual paths and model type
model_type = "default" # default is the same as vit_h
checkpoint_path = "sam_vit_h_4b8939.pth" # you have to download this from the github
image_path = "insects.jpg"
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
min_area = 0.1/100 # 0.1% of image area (insects should be larger than 5% of the image area)
max_area = 0.6/100 # 0.6% of image area (insects should be smaller than 10% of the image area)
# Print Information for this run
print('Device in use =', DEVICE)
# Load the image
image = cv2.imread(image_path)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# Create the SAM model and mask generator
sam = sam_model_registry[model_type](checkpoint=checkpoint_path)
mask_generator = SamAutomaticMaskGenerator(sam)
# Generate masks for the entire image
masks = mask_generator.generate(image_rgb)
# Calculate the threshold for mask area (10% of the image size)
area_hi_thres = max_area * image.shape[0] * image.shape[1]
area_low_thres = min_area * image.shape[0] * image.shape[1]
# Filter the masks based on their area
filtered_masks = [mask for mask in masks if area_low_thres < mask['area'] < area_hi_thres]
# Use supervision package to anotate masks
mask_annotator = sv.MaskAnnotator()
detections = sv.Detections.from_sam(filtered_masks)
annotated_image = mask_annotator.annotate(image, detections)
# Write Images to File
cv2.imwrite('Image RGB.jpg', image_rgb) # it will likely work also in gray scale and a bit faster
cv2.imwrite('annoated_image.jpg', annotated_image)
# Print the count
print('Number of Objects', len(filtered_masks))