File size: 2,504 Bytes
6ffe23f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84b28c9
6ffe23f
84b28c9
6ffe23f
84b28c9
 
 
 
 
 
 
 
 
6ffe23f
84b28c9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6ffe23f
84b28c9
 
6ffe23f
 
84b28c9
 
6ffe23f
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
from scipy.ndimage import label, find_objects
import numpy as np
import cv2

IMAGE_SPACING_X = 0.7031
IMAGE_SPACING_Y = 0.7031
IMAGE_SPACING_Z = 2.5 


def compute_largest_diameter(binary_mask):
    
    # Label connected components in the binary mask
    labeled_array, num_features = label(binary_mask)

    # Find the objects (tumors) in the labeled array
    tumor_objects = find_objects(labeled_array)

    # Initialize the largest diameter variable
    largest_diameter = 0

    # Iterate through each tumor object
    for obj in tumor_objects:
        # Calculate the dimensions of the tumor object
        z_dim = obj[2].stop - obj[2].start
        y_dim = obj[1].stop - obj[1].start
        x_dim = obj[0].stop - obj[0].start

        # Calculate the diameter using the longest dimension
        diameter = max(z_dim * IMAGE_SPACING_Z, y_dim * IMAGE_SPACING_Y, x_dim * IMAGE_SPACING_X)

        # Update the largest diameter if necessary
        if diameter > largest_diameter:
            largest_diameter = diameter

    return largest_diameter / 10 # IN CM


def compute_shape(binary_mask):

    contours, _ = cv2.findContours(binary_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    shape, margin = None, None

    if contours:
        tumor_contour_area = cv2.contourArea(contours[0])

        tumor_contour_perimeter = cv2.arcLength(contours[0], True)
        epsilon = 0.02 * tumor_contour_perimeter
        approx = cv2.approxPolyDP(contours[0], epsilon, True)
        num_sides = len(approx)

        # determine the shape based on the number of sides
        if num_sides < 5: shape = "Round"
        else: shape = "Irregular"

        # determine the margin characteristics based on solidity
        hull = cv2.convexHull(contours[0])
        hull_area = cv2.contourArea(hull)
        tumor_solidity = tumor_contour_area / hull_area
        if tumor_solidity > 0.95: margin = "Smooth"
        elif tumor_solidity > 0.80: margin = "Irregular"
        else: margin = "Spiculated"

    return shape, margin

def generate_features(img, liver, tumor):
    
    # shape, margin = compute_shape(tumor)
    shape, margin = "irregular", "irregular"
    features = {
        "lesion size (cm)": compute_largest_diameter(tumor),
        "lesion boundary": margin,
        "lesion shape": shape, 
        "lesion density (HU)": np.mean(img[tumor==1]),
        "involvement of adjacent organs:": "Yes" if np.sum(np.multiply(liver==0, tumor)) > 0 else "No"
    }
    
    return features