haesleinhuepf / git-bob-bioimage-analysis-example

BSD 3-Clause "New" or "Revised" License
2 stars 0 forks source link

Segmenting an image and counting nuclei #1

Closed haesleinhuepf closed 2 days ago

haesleinhuepf commented 3 days ago

I have this image:

hela-cells-8bit

I would like to segment the nuclei in it. How could I achieve this?

haesleinhuepf commented 3 days ago

This message was generated by git-bob (version: 0.3.0, model: gpt-4o-2024-08-06), an experimental AI-based assistant. It can make mistakes and has limitations. Check its messages carefully.

To segment the nuclei in the provided image, you can use image processing techniques with Python libraries such as OpenCV and scikit-image. Below is a Python script that might help you achieve the expected segmentation:

import cv2
import numpy as np
from skimage import measure
import matplotlib.pyplot as plt

# Load image
image_path = "path/to/your/image.png"
image = cv2.imread(image_path)
# Convert to grayscale (assuming the blue channel is the DAPI stain for nuclei)
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# Apply a Gaussian blur to the grayscale image to remove noise
blurred_image = cv2.GaussianBlur(gray_image, (5, 5), 0)

# Adaptive thresholding or Otsu's thresholding can be used to create a binary image
_, binary_image = cv2.threshold(blurred_image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# Find contours of the nuclei in the binary image
contours, _ = cv2.findContours(binary_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# Optionally filter contours and count valid nuclei
nuclei_count = 0
for cnt in contours:
    area = cv2.contourArea(cnt)
    if area > 50:  # Example threshold for minimum area
        nuclei_count += 1

# Display the results
print(f'Number of nuclei: {nuclei_count}')

# Draw contours on the original image for visualization
contour_image = cv2.drawContours(image.copy(), contours, -1, (0, 255, 0), 2)

# Plot the images
plt.figure(figsize=(10,5))
plt.subplot(1,2,1), plt.title("Binary Image"), plt.imshow(binary_image, cmap='gray')
plt.subplot(1,2,2), plt.title("Detected Nuclei"), plt.imshow(cv2.cvtColor(contour_image, cv2.COLOR_BGR2RGB))
plt.show()

This script loads the image, converts it to grayscale, applies a Gaussian blur, performs Otsu's thresholding to create a binary image, finds contours to identify the nuclei, and finally counts and displays them. Adjust the threshold and area filter based on your image specifics for better accuracy. Make sure you have OpenCV, scikit-image, and matplotlib installed in your Python environment.

haesleinhuepf commented 3 days ago

I'd like to use scikit-image instead of cv2. Also the image path should be "data/hela-cells-8bit.jpg". Please modify the code.

haesleinhuepf commented 3 days ago

This message was generated by git-bob (version: 0.3.0, model: gpt-4o-2024-08-06), an experimental AI-based assistant. It can make mistakes and has limitations. Check its messages carefully.

import numpy as np
import matplotlib.pyplot as plt
from skimage import io, color, filters, measure, morphology

# Load image
image_path = "data/hela-cells-8bit.jpg"
image = io.imread(image_path)

# Convert to grayscale (assuming the blue channel is the DAPI stain for nuclei)
gray_image = color.rgb2gray(image)

# Apply a Gaussian blur to the grayscale image to remove noise
blurred_image = filters.gaussian(gray_image, sigma=1)

# Otsu's thresholding to create a binary image
thresh = filters.threshold_otsu(blurred_image)
binary_image = blurred_image > thresh

# Remove small objects (debris)
cleaned_image = morphology.remove_small_objects(binary_image, min_size=50)

# Find and count nuclei
labeled_image = measure.label(cleaned_image)
nuclei_count = labeled_image.max()

# Display the results
print(f'Number of nuclei: {nuclei_count}')

# Plot the images
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.title("Binary Image")
plt.imshow(cleaned_image, cmap='gray')
plt.subplot(1, 2, 2)
plt.title("Detected Nuclei")
plt.imshow(color.label2rgb(labeled_image, image=image, bg_label=0))
plt.show()
haesleinhuepf commented 3 days ago

Instead of gray_image = color.rgb2gray(image), we should extract the channel like this: gray_image = image[...,2].

haesleinhuepf commented 3 days ago

This message was generated by git-bob (version: 0.3.0, model: gpt-4o-2024-08-06), an experimental AI-based assistant. It can make mistakes and has limitations. Check its messages carefully.

import numpy as np
import matplotlib.pyplot as plt
from skimage import io, filters, measure, morphology, color

### Load image
image_path = "data/hela-cells-8bit.jpg"
image = io.imread(image_path)

### Extract the blue channel (assuming the blue channel is the DAPI stain for nuclei)
gray_image = image[..., 2]

### Apply a Gaussian blur to the blue channel to remove noise
blurred_image = filters.gaussian(gray_image, sigma=1)

### Otsu's thresholding to create a binary image
thresh = filters.threshold_otsu(blurred_image)
binary_image = blurred_image > thresh

### Remove small objects (debris)
cleaned_image = morphology.remove_small_objects(binary_image, min_size=50)

### Find and count nuclei
labeled_image = measure.label(cleaned_image)
nuclei_count = labeled_image.max()

### Display the results
print(f'Number of nuclei: {nuclei_count}')

### Plot the images
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.title("Binary Image")
plt.imshow(cleaned_image, cmap='gray')
plt.subplot(1, 2, 2)
plt.title("Detected Nuclei")
plt.imshow(color.label2rgb(labeled_image, image=image, bg_label=0))
plt.show()
haesleinhuepf commented 3 days ago

Ok cool. Please create a new notebook in the "notebooks" directory, which does exactly what is written above. The code should be split in multiple cells and above each code cell, there should be a markdown cell explaining what the next code cell does. And keep in mind that the data is in the "data" folder, which is next to the "notebooks" folder.