Python/OpenCV——细菌簇中的质心确定

Rai*_*ury 9 python opencv image-processing computer-vision python-3.x

我目前正在开发一种算法来确定细菌簇的(明场)显微镜图像的质心位置。这是目前图像处理中的一个主要未解决的问题。

这个问题是对:Python/OpenCV — 匹配两个图像中细菌的质心点的后续问题。

目前,该算法对稀疏、间隔开的细菌有效。然而,当细菌聚集在一起时,它变得完全无效。

在这些图像中,请注意细菌质心是如何有效定位的。

明场图像 #1 明场图像 #1

明场图像 #2 明场图像 #2

明场图像 #3 明场图像 #3

然而,当细菌聚集在不同的水平时,算法就会失败。

明场图像 #4 明场图像 #4

明场图像 #5 明场图像 #5

明场图像 #6 明场图像 #6

明场图像 #7 明场图像 #7

明场图像 #8 明场图像 #8

原始图像

明场图像 #1

明场图像 #2

明场图像 #3

明场图像 #4

明场图像 #5

明场图像 #6

明场图像 #7

明场图像 #8

我想优化我当前的算法,使其对这些类型的图像更加健壮。这是我正在运行的程序。

import cv2
import numpy as np
import os

kernel = np.array([[0, 0, 1, 0, 0],
                   [0, 1, 1, 1, 0],
                   [1, 1, 1, 1, 1],
                   [0, 1, 1, 1, 0],
                   [0, 0, 1, 0, 0]], dtype=np.uint8)


def e_d(image, it):
    image = cv2.erode(image, kernel, iterations=it)
    image = cv2.dilate(image, kernel, iterations=it)
    return image


path = r"(INSERT IMAGE DIRECTORY HERE)"
img_files = [file for file in os.listdir(path)]


def segment_index(index: int):
    segment_file(img_files[index])


def segment_file(img_file: str):
    img_path = path + "\\" + img_file
    print(img_path)
    img = cv2.imread(img_path)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # Applying adaptive mean thresholding
    th = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 11, 2)
    # Removing small noise
    th = e_d(th.copy(), 1)

    # Finding contours with RETR_EXTERNAL flag and removing undesired contours and
    # drawing them on a new image.
    cnt, hie = cv2.findContours(th, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    cntImg = th.copy()
    for contour in cnt:
        x, y, w, h = cv2.boundingRect(contour)
        # Eliminating the contour if its width is more than half of image width
        # (bacteria will not be that big).
        if w > img.shape[1] / 2:
            continue
        cntImg = cv2.drawContours(cntImg, [cv2.convexHull(contour)], -1, 255, -1)

    # Removing almost all the remaining noise.
    # (Some big circular noise will remain along with bacteria contours)
    cntImg = e_d(cntImg, 3)

    # Finding new filtered contours again
    cnt2, hie2 = cv2.findContours(cntImg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

    # Now eliminating circular type noise contours by comparing each contour's
    # extent of overlap with its enclosing circle.
    finalContours = []  # This will contain the final bacteria contours
    for contour in cnt2:
        # Finding minimum enclosing circle
        (x, y), radius = cv2.minEnclosingCircle(contour)
        center = (int(x), int(y))
        radius = int(radius)

        # creating a image with only this circle drawn on it(filled with white colour)
        circleImg = np.zeros(img.shape, dtype=np.uint8)
        circleImg = cv2.circle(circleImg, center, radius, 255, -1)

        # creating a image with only the contour drawn on it(filled with white colour)
        contourImg = np.zeros(img.shape, dtype=np.uint8)
        contourImg = cv2.drawContours(contourImg, [contour], -1, 255, -1)

        # White pixels not common in both contour and circle will remain white
        # else will become black.
        union_inter = cv2.bitwise_xor(circleImg, contourImg)

        # Finding ratio of the extent of overlap of contour to its enclosing circle.
        # Smaller the ratio, more circular the contour.
        ratio = np.sum(union_inter == 255) / np.sum(circleImg == 255)

        # Storing only non circular contours(bacteria)
        if ratio > 0.55:
            finalContours.append(contour)

    finalContours = np.asarray(finalContours)

    # Finding center of bacteria and showing it.
    bacteriaImg = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)

    for bacteria in finalContours:
        M = cv2.moments(bacteria)
        cx = int(M['m10'] / M['m00'])
        cy = int(M['m01'] / M['m00'])

        bacteriaImg = cv2.circle(bacteriaImg, (cx, cy), 5, (0, 0, 255), -1)

    cv2.imshow("bacteriaImg", bacteriaImg)
    cv2.waitKey(0)

# Segment Each Image
for i in range(len(img_files)):
    segment_index(i)
Run Code Online (Sandbox Code Playgroud)

理想情况下,我希望至少改进一些已发布的图片。

MJ_*_*MJ_ 5

面具始终是识别物体的薄弱环节,也是最重要的一步。这将改进具有大量细菌的识别图像。我通过添加一个 OPEN 和另一个带有内核的 ERODE 传递修改了您的 e_d 函数,并更改了它(迭代次数)变量(为 1, 2 而不是 1,3),以便您的代码执行此操作。这绝不是一个完成的工作,但我希望它能让您了解您可以尝试进一步增强它的方法。我使用了你提供的图像,因为它们已经有一个红点,这可能会干扰我的结果图像......但你可以看到它能够识别出更多的细菌。我的一些结果显示了两个点,我错过了只有一种细菌的图像,每个点很可能是因为它已经被标记了。用原始图像尝试一下,看看效果如何。

此外,由于细菌在大小和形状上都相对均匀,我认为您可以使用每个细菌的高宽比和/或平均值来过滤掉极端形状(小或大)和瘦长的形状也。你可以测量足够多的细菌,看看平均轮廓长度是多少,或者高度和宽度,或者高度/宽度比等等,以找到合理的公差而不是图像大小本身的比例。另一个建议是重新考虑如何将所有图像屏蔽在一起,可能分两步进行尝试。一是找到含有细菌的长条形的边界,然后找到里面的细菌。这假设您的所有图像都与这些图像相似,如果是这样,它可能有助于消除此边界之外的杂散命中,这些杂散命中绝不是细菌。

明场图像 #1

明场图像 #2

明场图像 #3

明场图像 #4

明场图像 #5

明场图像 #6

明场图像 #7

明场图像 #8

#!usr/bin/env python
# /sf/ask/4422745281/
import cv2
import numpy as np
import os

kernel = np.array([[0, 0, 1, 0, 0],
                   [0, 1, 1, 1, 0],
                   [1, 1, 1, 1, 1],
                   [0, 1, 1, 1, 0],
                   [0, 0, 1, 0, 0]], dtype=np.uint8)


def e_d(image, it):
    print(it)
    image = cv2.erode(image, kernel, iterations=it)
    image = cv2.dilate(image, kernel, iterations=it)
    image = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel, iterations = 1)
    image = cv2.morphologyEx(image, cv2.MORPH_ERODE, kernel, iterations = 1)
    return image


#path = r"(INSERT IMAGE DIRECTORY HERE)"
path = r"E:\stackimages"
img_files = [file for file in os.listdir(path)]


def segment_index(index: int):
    segment_file(img_files[index])


def segment_file(img_file: str):
    img_path = path + "\\" + img_file
    print(img_path)
    head, tail = os.path.split(img_path)
    img = cv2.imread(img_path)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    cv2.imshow("bacteriaImg-1", img)
    cv2.waitKey(0)
    # Applying adaptive mean thresholding
    th = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 11, 2)
    # Removing small noise
    th = e_d(th.copy(), 1)

    # Finding contours with RETR_EXTERNAL flag and removing undesired contours and
    # drawing them on a new image.
    cnt, hie = cv2.findContours(th, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    cntImg = th.copy()
    for contour in cnt:
        x, y, w, h = cv2.boundingRect(contour)
        # Eliminating the contour if its width is more than half of image width
        # (bacteria will not be that big).
        
        if w > img.shape[1] / 2:
            continue
  
        else:
           
            cntImg = cv2.drawContours(cntImg, [cv2.convexHull(contour)], -1, 255, -1)


    # Removing almost all the remaining noise.
    # (Some big circular noise will remain along with bacteria contours)
    cntImg = e_d(cntImg, 2)
    cv2.imshow("bacteriaImg-2", cntImg)
    cv2.waitKey(0)

    # Finding new filtered contours again
    cnt2, hie2 = cv2.findContours(cntImg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

    # Now eliminating circular type noise contours by comparing each contour's
    # extent of overlap with its enclosing circle.
    finalContours = []  # This will contain the final bacteria contours
    for contour in cnt2:
        # Finding minimum enclosing circle
        (x, y), radius = cv2.minEnclosingCircle(contour)
        center = (int(x), int(y))
        radius = int(radius)

        # creating a image with only this circle drawn on it(filled with white colour)
        circleImg = np.zeros(img.shape, dtype=np.uint8)
        circleImg = cv2.circle(circleImg, center, radius, 255, -1)

        # creating a image with only the contour drawn on it(filled with white colour)
        contourImg = np.zeros(img.shape, dtype=np.uint8)
        contourImg = cv2.drawContours(contourImg, [contour], -1, 255, -1)

        # White pixels not common in both contour and circle will remain white
        # else will become black.
        union_inter = cv2.bitwise_xor(circleImg, contourImg)

        # Finding ratio of the extent of overlap of contour to its enclosing circle.
        # Smaller the ratio, more circular the contour.
        ratio = np.sum(union_inter == 255) / np.sum(circleImg == 255)

        # Storing only non circular contours(bacteria)
        if ratio > 0.55:
            finalContours.append(contour)

    finalContours = np.asarray(finalContours)

    # Finding center of bacteria and showing it.
    bacteriaImg = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)

    for bacteria in finalContours:
        M = cv2.moments(bacteria)
        cx = int(M['m10'] / M['m00'])
        cy = int(M['m01'] / M['m00'])

        bacteriaImg = cv2.circle(bacteriaImg, (cx, cy), 5, (0, 0, 255), -1)

    cv2.imshow("bacteriaImg", bacteriaImg)
    cv2.waitKey(0)


# Segment Each Image
for i in range(len(img_files)):
    segment_index(i)
Run Code Online (Sandbox Code Playgroud)