如何使用 python opencv 可靠地仅选择 maksed 液滴图像的外轮廓?
How can I reliably choose only the outer contour of a maksed droplet image with python opencv?
我正在编写一个程序,它需要检测液滴的外轮廓并将椭圆拟合到该形状。
我有一个运行良好的设置:
- canny 边缘检测
- 找到等高线
- 选择最长的轮廓
- 拟合椭圆
但现在该过程需要包括用于分配液滴的注射器的面罩,它将外轮廓分成两半。
我知道如何屏蔽从 canny 返回的数组中检测到的边缘,但我不知道如何从那里继续。
我需要使用两个外部轮廓来拟合椭圆,但我不知道如何可靠地提取它们。
最小工作代码:
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)
使用的图像:
我暂时这样解决了:
计算每个轮廓的边界矩形的面积并选择最大的两个
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)
我正在编写一个程序,它需要检测液滴的外轮廓并将椭圆拟合到该形状。
我有一个运行良好的设置:
- canny 边缘检测
- 找到等高线
- 选择最长的轮廓
- 拟合椭圆
但现在该过程需要包括用于分配液滴的注射器的面罩,它将外轮廓分成两半。 我知道如何屏蔽从 canny 返回的数组中检测到的边缘,但我不知道如何从那里继续。
我需要使用两个外部轮廓来拟合椭圆,但我不知道如何可靠地提取它们。
最小工作代码:
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)
使用的图像:
我暂时这样解决了:
计算每个轮廓的边界矩形的面积并选择最大的两个
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)