Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何删除附加到另一个大轮廓的小轮廓_Python_Image_Opencv_Computer Vision_Scikit Image - Fatal编程技术网

Python 如何删除附加到另一个大轮廓的小轮廓

Python 如何删除附加到另一个大轮廓的小轮廓,python,image,opencv,computer-vision,scikit-image,Python,Image,Opencv,Computer Vision,Scikit Image,我在做细胞分割,所以我试着编写一个函数,删除主轮廓周围的所有次要轮廓,以便制作遮罩。 这是因为我加载了带有一些颜色标记的图像: 问题是当我做阈值时,它假设颜色标记之间的“框”是主轮廓的一部分 正如您在我的代码中看到的,我不会直接将彩色图像传递给灰色,因为红色变为黑色,但也有其他颜色,至少有8种,并且在每个图像中总是不同的。我有数千张这样的图片,其中只有一个单元格显示,但在大多数图片中,总是有局外人。我的目标是得到一个函数,它为每个像这样的图像输入提供单个单元格的二进制图像。所以我从以下代码

我在做细胞分割,所以我试着编写一个函数,删除主轮廓周围的所有次要轮廓,以便制作遮罩。 这是因为我加载了带有一些颜色标记的图像:

问题是当我做阈值时,它假设颜色标记之间的“框”是主轮廓的一部分

正如您在我的代码中看到的,我不会直接将彩色图像传递给灰色,因为红色变为黑色,但也有其他颜色,至少有8种,并且在每个图像中总是不同的。我有数千张这样的图片,其中只有一个单元格显示,但在大多数图片中,总是有局外人。我的目标是得到一个函数,它为每个像这样的图像输入提供单个单元格的二进制图像。所以我从以下代码开始:

import cv2 as cv
cell1 = cv.imread(image_cell, 0)
imgray = cv.cvtColor(cell1,cv.COLOR_BGR2HSV)
imgray = cv.cvtColor(imgray,cv.COLOR_BGR2GRAY)
ret,thresh_binary = cv.threshold(imgray,107,255,cv.THRESH_BINARY)
cnts= cv.findContours(image =cv.convertScaleAbs(thresh_binary) , mode = 
cv.RETR_TREE,method = cv.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
   cv.drawContours(thresh_binary,[c], 0, (255,255,255), -1)    
kernel = cv.getStructuringElement(cv.MORPH_RECT, (3,3))
opening = cv.morphologyEx(thresh_binary, cv.MORPH_OPEN, kernel, 
iterations=2) # erosion followed by dilation

总之,如何从图1中获得红色轮廓

实际上,在您的代码中,“框”是一个合法的额外轮廓。在最终的图像上画出所有的轮廓,这样就包括了“盒子”。如果图像中的任何其他彩色单元格都已完全显示,这可能会导致问题

一个更好的方法是分离出你想要的颜色。下面的代码创建一个二进制掩码,该掩码仅显示定义的红色范围内的像素。您可以将此掩码与
findContours
一起使用

结果:

代码:


可以帮助您了解此过程中的不同值(带inRange的HSV)是如何工作的

另一种方法,没有颜色范围

我认为你的代码中有一些地方不对劲。首先,您正在
thresh_binary
上绘制轮廓,但这已经包含了其他单元格的外线-您正试图去除的外线。我认为这就是为什么您使用
打开
(?),而在这种情况下您不应该使用

要解决这些问题,首先需要了解findContours是如何工作的。findContours开始在黑色背景上寻找白色形状,然后在白色轮廓内寻找黑色形状,依此类推。这意味着
thresh\u二进制文件中单元格的白色轮廓被检测为轮廓。里面还有其他轮廓,包括你想要的轮廓

您应该做的是首先只查找内部没有轮廓的轮廓。findContours还返回轮廓的层次结构。它指示轮廓是否具有“children”。如果没有(值:-1),则查看轮廓的大小,忽略太小的轮廓。你也可以找最大的,因为那可能是你想要的。最后,在黑色遮罩上绘制轮廓

结果:

代码:

注意:我使用了您上传的图像,您的图像的像素可能要少得多,因此轮廓区域更小

注2:
枚举
循环遍历轮廓,并为每个循环返回轮廓和索引

如果我只有一种颜色可以分离,但我在其他单元格图像中有其他颜色标记,那么为每种颜色进行循环将非常昂贵。如果能将这一点放到问题中,那将是一件好事。有多贵?你有数百万张图片吗?几十种颜色?具有相同颜色的相邻单元格?图像中是否可以有多个完整的单元格?您计划如何在当前工作流程中区分颜色?您也可以使用删除小于阈值的轮廓。我已经尝试了轮廓区域,但无法识别该小轮廓,事实上,我提高了变形函数中的迭代次数并解决了此特定问题,但它不会纠正颜色问题。效果很好。很好的解释,现在我对这些OpenCV函数有了更好的了解。
    import cv2
    # load image
    img = cv2.imread("PjMQR.png")
    # Convert HSV
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

    # define range of red color in HSV
    lower_val = np.array([0,20,0])
    upper_val = np.array([15,255,255])

    # Threshold the HSV image to get only red colors
    mask = cv2.inRange(hsv, lower_val, upper_val)

    # display image
    cv2.imshow("Mask", mask)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    import cv2 as cv
    import numpy as np
    # load image as grayscale
    cell1 = cv.imread("PjMQR.png",0)
    # threshold image
    ret,thresh_binary = cv.threshold(cell1,107,255,cv.THRESH_BINARY)
    # findcontours
    contours, hierarchy = cv.findContours(image =thresh_binary , mode = cv.RETR_TREE,method = cv.CHAIN_APPROX_SIMPLE)

    # create an empty mask
    mask = np.zeros(cell1.shape[:2],dtype=np.uint8)

    # loop through the contours
    for i,cnt in enumerate(contours):
            # if the contour has no other contours inside of it
            if hierarchy[0][i][2] == -1 :
                    # if the size of the contour is greater than a threshold
                    if  cv2.contourArea(cnt) > 10000:
                            cv.drawContours(mask,[cnt], 0, (255), -1)    
    # display result
    cv2.imshow("Mask", mask)
    cv2.imshow("Img", cell1)
    cv2.waitKey(0)
    cv2.destroyAllWindows()