【问题标题】:Python/OpenCV — Matching Centroid Points of Bacteria in Two ImagesPython/OpenCV — 匹配两个图像中细菌的质心点
【发布时间】:2020-11-08 23:19:00
【问题描述】:

我正在研究一种使用计算机视觉匹配细菌质心的算法。

由于我是计算机视觉的本科生和初学者,因此我没有专门针对此问题的代码。只是为了提供一些背景知识,我在我的 GUI 中使用了以下函数。

“bact”变量指的是 Bacteria 对象,其中存储了每个细菌的 ID、位置等。

 def identify_fluor(img, frame: int):

    darkBlue = (139, 0, 0)

    for bact in fluor_at_frame(frame):
    
        pos = tuple([int(coord) for coord in bact.position[frame]])
        img = cv2.circle(img, pos, 5, darkBlue, -1)

    return img
 def identify_bright(img, frame: int):

    darkRed = (0, 0, 139)

    for bact in bright_at_frame(frame):

        pos = tuple([int(coord) for coord in bact.position[frame]])
        img = cv2.circle(img, pos, 5, darkRed, -1)

    return img

这些质心是使用当前图像处理文献中可用的最佳软件找到的。如您所见,右侧(明场)的处理图像明显欠发达,对细菌学研究人员来说是一个重大障碍和麻烦。

我们需要处理右侧的这些图像,因为它们具有明显更高的图像采样率(1 秒 [右] 与 11 秒 [左])。荧光图像(左)在采样频率过高时会累积化学损伤,从而失去荧光。

这些是图像完美对齐的一些实例:

Sample 1 of Bacteria Match:

Sample 2 of Bacteria Match:

Sample 3 of Bacteria Match:

在这些情况下,右侧的图像在到达下一个对齐图像之前处于中间阶段。

Sample 4 of Bacteria Match

Sample 5 of Bacteria Match

Sample 6 of Bacteria Match

明场图像

Sample 1 of Bright-Field

Sample 2 of Bright-Field

Sample 3 of Bright-Field

附加链接

Sample 4 of Bright-Field

Sample 5 of Bright-Field

Sample 6 of Bright-Field

Sample 7 of Bright-Field

Sample 8 of Bright-Field

Sample 9 of Bright-Field

注意:这不是家庭作业。我正在做一个研究项目,试图获取有关细菌时间动态的信息。我正在尝试在其中一个图像样本上实现可行的解决方案。

编辑#1:为澄清起见,我正在尝试使用左侧的细菌找到右侧细菌的质心。

编辑#2:我不希望通过应用线性变换来匹配图像。寻求一种计算机视觉算法。

编辑 #3:为了测试目的,单独添加了额外的明场图像。

【问题讨论】:

标签: python python-3.x opencv image-processing computer-vision


【解决方案1】:

我的方法直接适用于正确的图像。

代码分享如下,用cmets解释:

我在开始时创建了一个函数,它使用圆形内核侵蚀和膨胀图像,指定次数。

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

注意:右边的图像是在变量“img”中以灰度格式读取的。

# 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, 5)


# 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)

注意:我只拍摄右侧的图像,我的图像尺寸为 (221, 828)。如果您的输入图像小于或大于此值,请调整腐蚀和膨胀的迭代次数值以相应地去除噪声以获得良好的效果。

这是输出图像:

此外,正如您在第三张图片中看到的那样,最左边的细菌,其中心标记的并不完全在中心。发生这种情况是因为,在代码中,我在一个地方使用了轮廓的凸包。您可以通过跟踪所有轮廓来解决此问题,然后在最后取初始轮廓的中心。

我确信这段代码也可以修改并变得更好,但这是我现在能想到的。欢迎提出任何建议。

【讨论】:

  • e_d() 称为开口。
  • @CrisLuengo,是的,它是形态开放,但我更喜欢这样使用它,以便完全控制过程。
  • 出色的答案。我认为在第三张图片中您找到了数学中心。然而,看图片的人总是会将中心放在细菌内。由于细菌的轴通常是左右(在 x 方向),因此您可以通过使用数学 x 中心获得“人类”中心,对于 y 中心,计算 x 所在的局部中心。跨度>
  • 这是一个很好的解决方案,非常感谢 Rahul!我可以要求任何人使用此算法处理问题测试图像 7-9 吗?它适用于开始的图像,但逐渐崩溃,我想看看是否有办法解决这个问题。
  • @RaiyanChowdhury,Stack Overflow 不是免费的代码编写服务。您应该尝试自己编写代码。 RahulKedia 给出了很好的答案。
【解决方案2】:

这似乎是一个简单的校准问题。

找到左右两个对应点(即现实世界中的相同点)。如果您的设置是固定的,您可以“手动”执行此操作,并且一劳永逸。您可能必须为此添加标记(或使用您在视觉上匹配的两个遥远的细菌中心)。如果设置不固定,无论如何添加标记并设计它们,以便它们易于通过图像处理定位。

现在你通过求解得到左右坐标之间的简单线性关系

XR = a XL + b

为两点。然后使用其中一个点找到c

YR = a YL + c

持有。

现在知道abc,左边的每个点都可以映射到右边。从您的示例图像中,我确定

a ~ 1.128
b ~ 773
c ~ -16

非常严重。


不要尝试任何形状的匹配,依靠坐标的几何变换。

【讨论】:

  • 谢谢。但是,我正在寻找实际的计算机视觉算法的原因是因为左侧图像的采样率(11 秒 VS 1 秒)低于右侧。这个想法是在右侧有轻微移动后使用算法找到质心,这样我们可以获得更好的细菌时间动态。我已经发布了完全匹配的图像(即时间戳是 11 的整数倍)。
  • @RaiyanChowdhury:你一开始就应该这么说。事实上,大多数时候你不能做任何匹配,因为没有左图。所以呢 ?!?请提出正确的问题。
  • 您好 Yves,我理解您的想法,但是,我正在尝试分阶段解决问题。最终目标实际上是对正确的图像进行完全分割,这在文学中仍然是一个悬而未决的问题。在这个阶段发布整个问题可能是无效的。我想找到一种计算机视觉算法,当它们完全对齐时,可以匹配图像中的质心,然后慢慢地从这个开始。
  • @RaiyanChowdhury 我的帖子完全回答了您当前的问题。
  • @RaiyanChowdhury:您无法求解 2x2 线性系统吗?
猜你喜欢
  • 2020-11-16
  • 2020-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-09
  • 2012-02-12
相关资源
最近更新 更多