[英]How can I reliably choose only the outer contour of a maksed droplet image with python opencv?
I am writing a program which needs to detect the outer contour of a droplet and fit an ellipse to that shape.我正在编写一个程序,该程序需要检测液滴的外轮廓并将椭圆拟合到该形状。
I have a setup that has been working fine:我有一个运行良好的设置:
But now the process needs to include a mask for the syringe that dispenses the droplet, which splits the outer contour in half.但是现在这个过程需要包括一个用于分配液滴的注射器的面罩,它将外轮廓分成两半。 I know how to mask the detected edges from the array returned from canny but I don't know how to proceed from there.
我知道如何掩盖从 canny 返回的数组中检测到的边缘,但我不知道如何从那里开始。
I need to use the two outer contours to fit the ellipse but I don' know how to reliably extract those.我需要使用两个外部轮廓来拟合椭圆,但我不知道如何可靠地提取它们。
Minimal working code:最小的工作代码:
from typing import Tuple
import cv2
import numpy as np
def evaluate_droplet(img, y_base, mask: Tuple[int,int,int,int] = None):
# crop img from baseline down (contains no useful information)
crop_img = img[:y_base,:]
shape = img.shape
height = shape[0]
width = shape[1]
# calculate thrresholds
thresh_high, thresh_im = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
thresh_low = 0.5*thresh_high
bw_edges = cv2.Canny(crop_img, thresh_low, thresh_high)
# block detection of syringe
if (not mask is None):
x,y,w,h = mask
bw_edges[y:y+h, x:x+w] = 0
cv2.imshow('bw',bw_edges)
cv2.waitKey(0)
# for testing purposes:
if __name__ == "__main__":
im = cv2.imread('untitled1.png', cv2.IMREAD_GRAYSCALE)
im = np.reshape(im, im.shape + (1,) )
(h,w,d) = np.shape(im)
try:
drp = evaluate_droplet(im, 250, (int(w/2-40), 0, 80, h))
except Exception as ex:
print(ex)
cv2.imshow('Test',im)
cv2.waitKey(0)
I solved it like this for now:我现在这样解决了:
Calculate the area of the bounding rect for each contour and pick largest two计算每个轮廓的边界矩形的面积并选择最大的两个
def evaluate_droplet(img, y_base, mask: Tuple[int,int,int,int] = None):
# crop img from baseline down (contains no useful information)
crop_img = img[:y_base,:]
shape = img.shape
height = shape[0]
width = shape[1]
# calculate thrresholds
thresh_high, thresh_im = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
thresh_low = 0.5*thresh_high
bw_edges = cv2.Canny(crop_img, thresh_low, thresh_high)
# block detection of syringe
if (not mask is None):
x,y,w,h = mask
bw_edges[y:y+h, x:x+w] = 0
contours, hierarchy = cv2.findContours(bw_edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
if len(contours) == 0:
print("no contour found!")
cont_area_list = []
# match contours with their bounding rect area
for cont in contours:
x,y,w,h = cv2.boundingRect(cont)
cont_area_list.append((cont, w*h))
# sort combined list by area
cont_areas_sorted = sorted(cont_area_list, key=lambda item: item[1])
# largest 2 contours, assumes mask splits largest contour in the middle
if not mask is None:
largest_conts = [elem[0] for elem in cont_areas_sorted[-2:]]
# merge largest 2 contorus into one for handling purposes
contour = np.concatenate((largest_conts[0], largest_conts[1]))
# if no mask is used use only single largest contour
else:
contour = cont_areas_sorted[-1][0]
# display bounding rect of final contour
x,y,w,h = cv2.boundingRect(contour)
bw_edges = cv2.rectangle(bw_edges, (x,y), (x+w,y+h), (255,255,255))
cv2.imshow('bw',bw_edges)
cv2.waitKey(0)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.