Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Few questions on a medical dataset

I am currently working on a medical dataset containing whole slide images (~300 images).

These images are pretty big (.tif, average of 7k by 7k pixels). I am currently dividing each of these images into patches of size 224x224 and getting rid of the images showing just the background. Here is a code I quickly made for that using the patchify module I found.

import cv2 
from patchify import patchify
import numpy as np

img = cv2.imread('path/to/image.tif')

patches = patchify(img, (224,224,3), step=(224,224,3))

def is_blank(img, threashold=1):
    return np.std(img)<threshold

filtered_patches = []

for k in range(patches.shape[0]):
    for n in range(patches.shape[1]):
        for m in range(patches.shape[2]):
            # print(np.std(patches[k][n][m]))
            if not is_blank(patches[k][n][m]):
                filtered_patches.append(patches[k][n][m])

I was wondering if there was a more efficient/optimized way of first divinding each image in patches and then flagging the background images (which are almost completely white).

These images also come with color-annotated images (see the link below) that I am also going to divide into patches and I was wondering how I could detect which colors (RGB) are in a given image, because these colors correspond to a type of tissue. link to the whole-slide image and the color-annotated image

Here is the dataset : https://espace.library.uq.edu.au/view/UQ:8be4bd0

like image 301
Shini_ Gami Avatar asked Dec 19 '25 15:12

Shini_ Gami


1 Answers

Colors can be detected from the annotated image using OpenCV. If HSV color are preferred then uncomment line containing img_hsv and pass that image as arg to contour_center_colors or contour_avg_colors.
Half the image is used since in the used sample the annotated part was at the right.
Further filtering can be applied if tissue colors are known (see below).

import cv2 as cv
import random as rng
rng.seed(12345)

def contour_avg_colors(image, contours):
    for contour in contours:
        x, y, w, h = cv.boundingRect(contour)
        roi = image[y:y+h, x:x+w]
        
        # average color within the ROI (Region Of Interest)
        average_color_per_row = cv.mean(roi)
        average_color = (average_color_per_row[0], average_color_per_row[1], average_color_per_row[2])
        print(f"Average color for contour at ({x},{y}): {average_color}")
            
def contour_center_colors(image, contours):
    for i, contour in enumerate(contours):
        # color at center of the contour
        M = cv.moments(contour)
        if M["m00"] != 0:
            cx = int(M["m10"] / M["m00"])
            cy = int(M["m01"] / M["m00"])
            color_at_center = image[cy, cx]
            print(f"contour {i:>2} color: {color_at_center}")
        
def thresh_callback(im, val, orig_img):
    threshold = val
    # Detect edges using Canny
    canny_output = cv.Canny(src_gray, threshold, threshold * 2)
    # Find contours
    contours, hierarchy = cv.findContours(canny_output, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
    contour_center_colors(orig_img, contours)
    for i in range(len(contours)):
        #color = (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256))
        color = (252,226,5)
        cv.drawContours(im, contours, i, color, 2, cv.LINE_8, hierarchy, 0)
    # Show in a window
    cv.imshow('Contours', im)

img = cv.imread('/home/lmc/tmp/8MxYtM8T.png')
#img_hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
h, w = img.shape[:2] # We only need height and width for splitting

#half width
width= w // 2
# right_part
src = img[:, width:]
# Convert image to gray and blur it
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
src_gray = cv.blur(src_gray, (3,3))

max_thresh = 5000
thresh = 50
thresh_callback(src, thresh, img)
if cv.waitKey(0) & 0xFF == ord('q'):
    cv.destroyAllWindows()

Colors

contour  0 color: [242 221 241]
contour  1 color: [234 193 217]
contour  3 color: [224 148 216]
contour  4 color: [216 115 203]
contour  5 color: [245 223 245]
...

Regions of Interest (roi) or patches as named by OP, can be obtained by crafting the coordinates

roi = image[y:y+h, x:x+w]

Detected colors

Contours draw with a single color over the color image to identify opened contours and other irregularities.

Detected color contours

Detect specific color

Using HSV image color, get the list of colors above, pick a specific color and get contours

def get_center(contour):
    M = cv.moments(contour)
    area = M['m00']
    
    if area != 0:
        cx = int(M["m10"] / area)
        cy = int(M["m01"] / area)
    else:
        cx = contour[0][0][0]
        cy = contour[0][0][1]
    return cx, cy, area

upper_red= np.array([125, 43, 157], dtype = "uint8")
mask = cv.inRange(orig_img, upper_red, upper_red)
detected_output = cv.bitwise_and(orig_img, orig_img, mask = mask)
contours1, hierarch1 = cv.findContours(mask, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

for cnt in contours1:
    cx, cy, area = get_center(cnt)
    if area > 0.0:
        centroid_color = detected_output[cy, cx]
        if np.array_equal(upper_red, centroid_color):
            print(f"Centroid: ({cx},{cy}), area: {area}")
            cv.putText(detected_output, str(area), (cx, cy), cv.FONT_HERSHEY_SIMPLEX, 0.45, (0,255,0), 1, cv.LINE_AA)


# Draw contours on the original image (optional)
cv.drawContours(detected_output, contours1, -1, (0, 255, 0), 2)
#center1 = get_center(contours[i])
cv.imshow("red color detection", detected_output)

Result

Centroid: (385,401), area: 361618.5
Centroid: (703,325), area: 2.0
Centroid: (267,248), area: 2.0
Centroid: (180,210), area: 10156.0
Centroid: (374,93), area: 2.0

enter image description here

like image 195
LMC Avatar answered Dec 21 '25 06:12

LMC



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!