Search code examples
pythonopencvimage-processingcomputer-visionscikit-image

Segment photos of bio-samples to extract circular area of interest with Python image processing


I'm having issues with finishing the segmentation in some photos of bio-samples, I'm trying to analyze growth of bacteria with image processing, as in theory it should work. Here is one of the original images I have:

biofilm of pseudomona

I'm trying to segment the area inside the circle and see how the values of the pixels change as time passes. I've been trying a lot of techniques, as I'm relative new to analyzing these kind of samples.Initially I was using opencv, but I wasn't getting the results I wanted so now I'm using scikit-image for all the techniques for image processing and segmentation. Here's the code I have until now:

from skimage import morphology, exposure, io, filters
from scipy import ndimage as ndi
from skimage.color import rgb2gray, label2rgb
from skimage.filters import sobel, rank
import matplotlib.pyplot as plt
y1=400
y2=1600
x1=700
x2=1900
test_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 > val
elevation_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()

On the last line I get to segment by different colors the areas of the sample and get the part I want to analyze in one label, is now that I don't know how to continue or at least how to just see that label and then create a mask.

I'm also sharing the labeled image for anyone to see and maybe help me in the next steps, I feel like or I'm really close to segment my area of interest or really far and confused.

Well here's the labeled image of the sample:

segmented area with labels


Solution

  • After fixing the code this is the correct answer for the biofilm segmentation:

    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)