为了账号安全,请及时绑定邮箱和手机立即绑定

使用 Python 图像处理分割生物样本的照片以提取圆形感兴趣区域

使用 Python 图像处理分割生物样本的照片以提取圆形感兴趣区域

杨__羊羊 2022-07-05 19:49:24
我在完成一些生物样本照片的分割时遇到了问题,我正在尝试通过图像处理来分析细菌的生长,因为理论上它应该可以工作。这是我拥有的原始图像之一:我试图分割圆圈内的区域,看看像素的值如何随着时间的推移而变化。我一直在尝试很多技术,因为我对分析这类样本还比较陌生。最初我使用的是 opencv,但没有得到我想要的结果,所以现在我对所有人都使用 scikit-image图像处理和分割技术。这是我到目前为止的代码:from skimage import morphology, exposure, io, filtersfrom scipy import ndimage as ndifrom skimage.color import rgb2gray, label2rgbfrom skimage.filters import sobel, rankimport matplotlib.pyplot as plty1=400y2=1600x1=700x2=1900test_img = io.imread(folders_path+hour_tested[0]+'5.jpg')roi_test = test_img[y1:y2, x1:x2,:]gray_img = rgb2gray(roi_test)denoised_img = rank.median(gray_img, morphology.disk(5))val = filters.threshold_otsu(denoised_img)mask = denoised_img > valelevation_map=sobel(denoised_img)segmentation = morphology.watershed(elevation_map, mask=mask)labeled_bio, num_seg = ndi.label(segmentation)image_label_overlay = label2rgb(labeled_bio, image=gray_img)plt.imshow(image_label_overlay)plt.show()在最后一行,我用不同颜色分割样本区域并在一个标签中获得我想要分析的部分,现在我不知道如何继续或至少如何只看到该标签然后创建一个面具。我还分享了标记的图像供任何人查看,并可能在接下来的步骤中帮助我,我觉得或者我真的很接近分割我感兴趣的区域,或者真的很远很困惑。好吧,这是样本的标记图像:
查看完整描述

2 回答

?
一只萌萌小番薯

TA贡献1795条经验 获得超7个赞

修复代码后,这是生物膜分割的正确答案:


import cv2

import numpy as np

import os

def resize_image(image, percentage):

   scale_percent=percentage

   width = int(image.shape[1] * scale_percent/100)

   height= int(image.shape[0] * scale_percent/100)

   dimensions = (width, height)

   resized = cv2.resize(image, dimensions, interpolation = cv2.INTER_AREA)

   return resized

#this path is changed for each image in the DB

path=folders_path+hour_tested[0]+'1.jpg'

image = cv2.imread(path)

s_image = resize_image(image,50)

original = s_image.copy()

mask = np.zeros(s_image.shape, dtype=np.uint8)

gray = cv2.cvtColor(s_image, cv2.COLOR_BGR2GRAY)

thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

# Morph close

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7,7))

close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=3)

# Find contours and filter using contour area + contour approximation

# Determine perfect circle contour then draw onto blank mask

im,cnts,hierarchy = cv2.findContours(close, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

for c in cnts:

    peri = cv2.arcLength(c, True)

    approx = cv2.approxPolyDP(c, 0.04*peri, True)

    area = cv2.contourArea(c)

    if len(approx) > 4 and (area > 8000 and area < 250000) and (peri<2000 and peri>1000):

        ((x, y), r) = cv2.minEnclosingCircle(c)

        x,y,r = int(x),int(y),int(r)

        blank_circle=cv2.circle(mask, (x, y), r, (255, 255, 255), -1)

        filled_circle=cv2.circle(s_image, (x, y), r, (36, 255, 12), 3)

        # Extract ROI

        mask_ROI = blank_circle[y-r:y+r, x-r:x+r]

        mask_ROI = cv2.cvtColor(mask_ROI, cv2.COLOR_BGR2GRAY)

        image_ROI = filled_circle[y-r:y+r, x-r:x+r]

        result = cv2.bitwise_and(image_ROI, image_ROI, mask=mask_ROI)

        cv2.imwrite('result.png',result)


查看完整回答
反对 回复 2022-07-05
?
幕布斯6054654

TA贡献1876条经验 获得超7个赞

这是一种使用简单图像处理技术的方法

  • 获取二值图像。加载图像,转换为灰度,然后Otsu的阈值得到二值图像

  • 执行形态学操作。我们创建一个椭圆形的内核,然后执行变形来填充轮廓

  • 隔离感兴趣的区域。我们使用轮廓近似+轮廓区域找到轮廓和过滤器。一旦我们隔离了轮廓,找到一个最小的封闭圆以获得一个完美的圆,然后将它绘制到一个空白蒙版上。获得正圆的想法是从如何修改蒙版来制作正圆

  • 隔离投资回报率。我们在掩码上找到边界矩形 ROI,然后使用 Numpy 切片进行裁剪

  • 按位与获得结果。最后我们按位和提取的两个 ROI


这是每个步骤的可视化:

输入图像

二进制图像

变形关闭

以绿色突出显示的孤立感兴趣区域,并在空白蒙版上绘制填充轮廓

 

孤立的 ROI

 

按位与结果(两个版本,一个黑色背景,一个白色背景,取决于你想要的)

 


代码


import cv2

import numpy as np


# Load image, create blank mask, grayscale, Otsu's threshold

image = cv2.imread('1.jpg')

original = image.copy()

mask = np.zeros(image.shape, dtype=np.uint8)

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]


# Morph close

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))

close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=5)


# Find contours and filter using contour area + contour approximation

# Determine perfect circle contour then draw onto blank mask

cnts = cv2.findContours(close, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

cnts = cnts[0] if len(cnts) == 2 else cnts[1]

for c in cnts:

    peri = cv2.arcLength(c, True)

    approx = cv2.approxPolyDP(c, 0.04 * peri, True)

    area = cv2.contourArea(c)

    if len(approx) > 4 and area > 10000 and area < 500000:

        ((x, y), r) = cv2.minEnclosingCircle(c)

        cv2.circle(mask, (int(x), int(y)), int(r), (255, 255, 255), -1)

        cv2.circle(image, (int(x), int(y)), int(r), (36, 255, 12), 3)


# Extract ROI

mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)

x,y,w,h = cv2.boundingRect(mask)

mask_ROI = mask[y:y+h, x:x+w]

image_ROI = original[y:y+h, x:x+w]


# Bitwise-and for result

result = cv2.bitwise_and(image_ROI, image_ROI, mask=mask_ROI)

result[mask_ROI==0] = (255,255,255) # Color background white


cv2.imwrite('close.png', close)

cv2.imwrite('thresh.png', thresh)

cv2.imwrite('image.png', image)

cv2.imwrite('mask.png', mask)

cv2.imwrite('result.png', result)

cv2.waitKey()

注意:确定感兴趣的圆形区域的另一种方法是使用已经实现的霍夫圆变换,cv2.HoughCircles()但参数很多,因此它可能不是最实用的方法。


查看完整回答
反对 回复 2022-07-05
  • 2 回答
  • 0 关注
  • 187 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信