PWAT estimation and prediction

In this demo we will show how to perform the prediction of PWAT score using the features extracted from the available set of images. This analysis relies on the availability of a good segmentation model for the wound identification. For the development of the required segmentation model, we refer to the deepskin_assl demo of the deepskin package.

For the correct application of the code below, we surmise a folder tree close to:

data/
├── deepskin_images
├── deepskin_masks
└── pwat_db.csv

where: * deepskin_images contains the entire set of available images in the dataset; * deepskin_masks contains the entire set of validated masks in the dataset; * pwat_db.csv file with the PWAT score associated to each image file.

In this demo, we will use the functions proposed in deepskin package for the extraction of the wound masks and related features, showing how to implement the prediction of the PWAT score using a Lasso regression model. Other customization of the outputs could be obtained adding other features or changes in the machine learning pipeline.

First of all we need to load the information about the PWAT scores.

In [ ]:
import pandas as pd

# define the filename of the PWAT labels
LABEL_FILENAME = f'./data/pwat_db.csv'

# load the file with all the outcomes
pwat = pd.read_csv(LABEL_FILENAME, sep=',', header=0)
pwat.head()

The proposed PWAT file must have at least two columns, a first refered to the image filename, and a second refered to the associated PWAT score. An example is given by the following table

Filename

PWAT

image0.png

12

image1.png

4

imageN.png

17

According to the available images/masks, we will apply the deepskin pipeline for the extraction of the image features.

In [ ]:
from glob import glob

# define the filename of the PWAT labels
# define the directory in which the whole DB of images are stored
ALL_IMAGE_FOLDER = './data/deepskin_images'
# define the directory in which the whole DB of (validated!!) masks are stored
ALL_MASKS_FOLDER = './data/deepskin_masks'

# get all the image filenames
image_files = glob(f'{ALL_IMAGE_FOLDER}/*')

Now using the list of available images, we apply the feature extraction procedure.

In [ ]:
import cv2
from deepskin import evaluate_features

features = {}

# loop along the available image files:
for i, image_file in enumerate(image_files):

    # get the filename
    name = os.path.basename(image_file)

    # build the associated mask filename
    mask_file = f'{ALL_MASKS_FOLDER}/{name}'

    # load the image using opencv
    bgr = cv2.imread(image_file)
    # convert the image from BGR to RGB fmt
    rgb = bgr[..., ::-1]

    # load the mask using opencv
    mask = cv2.imread(mask_file, cv2.IMREAD_GRAYSCALE)

    # compute the features related to the current file
    features[name] = evaluate_features(
        img=rgb,
        mask=mask
    )

At the end of this step, you will have a set of numeric features which characterize both the wound and peri-wound areas identified by the segmentation model. A detailed description of the features pre-computed by the deepskin model is discussed in the work of Curti et al.

For a faster evaluation, a re-organization of the features into a dataframe structure could help for the next step.

In [ ]:
features = pd.DataFrame.from_dict(features, orient='index').T

Now we can start to build the prediction pipeline composed by a standardization step and a regression model. We will use the scikit-learn package to build our pipeline, splitting the available data into a K-fold cross-validation. The use of cross-validation ensures the correct evaluation of the model performances and the testing of the results into independent set of values. However, at the end of the cross validation we will have K different regression model, each one tested on a subset of the available data. Thus, the use of the cross-validation is used to check the effectiveness of the proposed pipeline for the PWAT evaluation, while for the final deploy of the model we will train a final model using all the available data.

In [ ]:
from sklearn.preprocessing import RobustScaler # standardization algorithm
from sklearn.model_selection import StratifiedKFold # cross validation algorithm
from sklearn.linear_model import Lasso # regression model
from sklearn.pipeline import make_pipeline # whole pipeline workflow manager
from sklearn.model_selection import cross_val_predict # pipeline workflow
from scipy.stats import pearsonr, spearmanr # model evaluation metrics

# define the K-fold algorithm setting the K value
K = 10
# use a stratified K-Fold to ensure a good subdivision of
# the data among train and test
cv10 = StratifiedKFold(
    n_splits=K,     # set the value of K
    shuffle=True,   # enable the shuffling of the data
    random_state=42 # fix the random seed for results reproducibility
)

# define the standardization method
scaler = RobustScaler()

# define the regression model
regressor = Lasso(
    alpha=1e-2,
    fit_intercept=True,
    random_state=42,
)

# define the pipeline steps
pipeline_steps = [scaler, regressor]
# build the machine learning pipeline
pipe = make_pipeline(*pipeline_steps)

# define the data (X) and labels (y_true) on which apply the pipeline
X = features
y_true = pwat['PWAT']

# run the pipeline to get the prediction
y_pred = cross_val_predict(pipe, X, y_true, cv=cv10)

# evaluate the pipeline performances
stat_pearson = pearsonr(y_true, y_pred)
stat_spearman = spearmanr(y_true, y_pred)

print(f"Pearson's R score: {stat_pearson[0]:.3f} (p-value: {stat_pearson[1]:.3f})")
print(f"Spearman's R score: {stat_spearman[0]:.3f} (p-value: {stat_spearman[1]:.3f})")

According to the performances obtained by the model, we can test the robustness of the developed pipeline re-iterating the cross-validation process on different train/test subdivisions, collecting the resulting metrics.

In [ ]:
# Perform 100 CV to test the robustness
spearman_coefs = []

# generate 100 iterations
for i in range(100):
    # define a different K-fold changing the random seed
    cv10 = StratifiedKFold(n_splits=K, shuffle=True, random_state=i+1)
    # run the pipeline
    y_pred = cross_val_predict(pipe, X, y_true, cv=cv10)
    # evaluate the metrics
    stat_spearman = spearmanr(y_true, y_pred)
    spearman_coefs.append(stat_spearman)