Spaces:
Build error
Build error
import streamlit as st | |
from numpy import load | |
from numpy import expand_dims | |
from matplotlib import pyplot | |
from PIL import Image, ImageDraw, ImageFont | |
import numpy as np | |
import os | |
import os,sys | |
sys.path.insert(0,"..") | |
from glob import glob | |
import torch | |
import torchvision | |
import sys | |
import torch.nn.functional as F | |
import torchxrayvision as xrv | |
import pydicom as dicom | |
import PIL # optional | |
import pandas as pd | |
import matplotlib.pyplot as plt | |
import os | |
import cv2 | |
import skimage | |
from skimage.transform import rescale, resize, downscale_local_mean | |
import operator | |
import mols2grid | |
import streamlit.components.v1 as components | |
from rdkit import Chem | |
from rdkit.Chem.Descriptors import ExactMolWt | |
from chembl_webresource_client.new_client import new_client | |
### Title | |
st.markdown("<h1 style='text-align: center;'>Chest Anomaly Identifier</h1>",unsafe_allow_html=True) | |
### Description | |
st.markdown("""<p style='text-align: center;'>The goal of this application is mainly to help doctors to interpret | |
Chest X-Ray Images, being able to find medical compounds in a quick way to deal with Chest's anomalies found</p>""",unsafe_allow_html=True) | |
### Image | |
st.image("doctors.jpg") | |
### Uploder | |
# st.markdown("""<p style='text-align: center;'>The goal of this application is mainly to help doctors to interpret | |
# Chest X-Ray Images, being able to find medical compounds in a quick way to deal with Chest's anomalies found</p>""",unsafe_allow_html=True) | |
uploaded_file = st.file_uploader("Choose an X-Ray image to detect anomalies of the chest (the file must be a dicom extension or jpg)") | |
#### Get Compounds found | |
def getdrugs(name,phase): | |
drug_indication = new_client.drug_indication | |
molecules = new_client.molecule | |
obj = drug_indication.filter(efo_term__icontains=name) | |
appdrugs = molecules.filter(molecule_chembl_id__in=[x['molecule_chembl_id'] for x in obj]) | |
if phase!=[]: | |
temp = None | |
for ph in phase: | |
dftemp = pd.DataFrame.from_dict(appdrugs.filter(max_phase=int(ph))) | |
dftemp["phase"] = int(ph) | |
if isinstance(temp,pd.DataFrame): | |
temp= pd.concat([temp,dftemp],axis=0) | |
else: | |
temp = dftemp | |
df = temp | |
else: | |
df = pd.DataFrame.from_dict(appdrugs) | |
try: | |
df.dropna(subset=["molecule_properties","molecule_structures"],inplace=True) | |
df["smiles"] = df.molecule_structures.apply(lambda x:x["canonical_smiles"]) | |
df["Acceptors"] = df.molecule_properties.apply(lambda x :x["hba"]) | |
df["Donnors"] = df.molecule_properties.apply(lambda x :x["hbd"]) | |
df["mol_weight"] = df.molecule_properties.apply(lambda x :x["mw_freebase"]) | |
df["Logp"] = df.molecule_properties.apply(lambda x :x["cx_logp"]) | |
subs = ["pref_name","smiles","Acceptors","Donnors","mol_weight","Logp"] | |
df.dropna(subset=subs,inplace=True) | |
df["Acceptors"] = df["Acceptors"].astype(int) | |
df["Donnors"] = df["Donnors"].astype(int) | |
df["mol_weight"] = df["mol_weight"].astype(float) | |
df["Logp"] = df["Logp"] .astype(float) | |
return df.loc[:,subs] | |
except: | |
return None | |
### Read Chest X Ray Image | |
def read_image(imgpath): | |
if (str(imgpath).find("jpg")!=-1) or (str(imgpath).find("png")!=-1): | |
# sample = Image.open("JPG_test/0c4eb1e1-b801903c-bcebe8a4-3da9cd3c-3b94a27c.jpg") | |
sample = Image.open(imgpath) | |
return np.array(sample) | |
if str(imgpath).find("dcm")!=-1: | |
img = dicom.dcmread(imgpath).pixel_array | |
return img | |
### Generate torchxrayvision model to find output probabilities | |
def generatemodel(xrvmodel,wts): | |
return xrvmodel(weights=wts) | |
### Transform the image to ouput some illness | |
def transform2(img): | |
input_tensor = torch.from_numpy(img).unsqueeze(0) | |
img = input_tensor.numpy()[0, 0, :] | |
img = (img / 1024.0 / 2.0) + 0.5 | |
img = np.clip(img, 0, 1) | |
img = Image.fromarray(np.uint8(img * 255) , 'L') | |
return img | |
### Transform the image to test an output image | |
def transform(img): | |
img = ((img-img.min())/(img.max()-img.min())*255) | |
# img = (img / 1024.0 / 2.0) + 0.5 | |
# img = np.clip(img, 0, 1) | |
# img = Image.fromarray(np.uint8(img * 255) , 'L') | |
# print(img.shape) | |
# img = skimage.io.imread("JPG_test/0c4eb1e1-b801903c-bcebe8a4-3da9cd3c-3b94a27c.jpg") | |
# print(img.max()) | |
img = xrv.datasets.normalize(np.array(img), 255) | |
# Check that images are 2D arrays | |
if len(img.shape) > 2: | |
img = img[:, :, 0] | |
if len(img.shape) < 2: | |
print("error, dimension lower than 2 for image") | |
# Add color channel | |
img = img[None, :, :] | |
transform = torchvision.transforms.Compose([xrv.datasets.XRayCenterCrop(), | |
xrv.datasets.XRayResizer(224,engine="cv2")]) | |
img = transform(img) | |
return img | |
### Returns the output probabilities of having certain illnesses anomalies | |
def testimage(model,img): | |
# with torch.no_grad(): | |
model.eval() | |
out = model(torch.from_numpy(img).unsqueeze(0)).cpu() | |
# out = model(img).cpu() | |
# out = torch.sigmoid(out) | |
return {key:value for (key,value) in zip(model.pathologies, out.detach().numpy()[0]) if len(key)>2} | |
### Resize the model | |
def outputprob2(img,pr_model,visimage=True): | |
### Read an image | |
img = resize(img, (img.shape[0] // 2, img.shape[1] // 2), | |
anti_aliasing=True) | |
### Preprocessmodel | |
img_t = transform(img) | |
### Test an image | |
return testimage(pr_model,img_t) | |
### Pipeline since we read an image until the ouput it is generated | |
def outputprob(imgpath,pr_model,visimage=True): | |
### Read an image | |
img = read_image(imgpath) | |
if visimage: | |
plt.imshow(img,cmap="gray") | |
plt.show() | |
### Preprocessmodel | |
img_t = transform(img) | |
### Test an image | |
return testimage(pr_model,img_t) | |
### Error in case we do not find compounds | |
def error(option): | |
option = str(option).replace(" ","%20") | |
st.markdown(f""" | |
We have not found compounds for this illness; for more information visit this link: | |
[Chemble](https://www.ebi.ac.uk/chembl/g/#search_results/all/query={option}) | |
""", unsafe_allow_html=True) | |
### If you insert an image | |
if uploaded_file is not None: | |
## Controller header | |
st.sidebar.markdown("<h1 style='text-align: center;'>Compound's filter</h1>",unsafe_allow_html=True) | |
## Write the compound | |
st.sidebar.markdown(''' | |
<h4 style='text-align: center;'>This controller sidebar is used to filter the compounds by the following features</h4> | |
- Molecular weight : is the weight of a compound in grame per mol | |
- LogP : it measures how hydrophilic or hydrophobic a compound is | |
- NumDonnors : number of chemical components that are able to deliver electrons to other chemical components | |
- NumAcceptors : number of chemical components that are able to accept electrons to other chemical components | |
''',unsafe_allow_html=True) | |
weight_cutoff = st.sidebar.slider( | |
label="Molecular weight", | |
min_value=0, | |
max_value=1000, | |
value=500, | |
step=10, | |
help="Look for compounds that have less or equal molecular weight than the value selected" | |
) | |
logp_cutoff = st.sidebar.slider( | |
label="LogP", | |
min_value=-10, | |
max_value=10, | |
value=5, | |
step=1, | |
help="Look for compounds that have less or equal logp than the value selected" | |
) | |
NumHDonors_cutoff = st.sidebar.slider( | |
label="NumHDonors", | |
min_value=0, | |
max_value=15, | |
value=5, | |
step=1, | |
help="Look for compounds that have less or equal donors weight than the value selected" | |
) | |
NumHAcceptors_cutoff = st.sidebar.slider( | |
label="NumHAcceptors", | |
min_value=0, | |
max_value=20, | |
value=10, | |
step=1, | |
help="Look for compounds that have less or equal acceptors weight than the value selected" | |
) | |
max_phase = st.sidebar.multiselect("Phase of the compound", | |
['1','2', '3', '4'], | |
help=""" | |
- Phase 1 : Phase I of the compound in progress | |
- Phase 2 : Phase II of the compound in progress | |
- Phase 3 : Phase III of the compound in progress | |
- Phase 4 : Approved compound | |
""" | |
) | |
#### Read an image | |
imgdef = read_image(uploaded_file) | |
### Plot the input image | |
fig, ax = plt.subplots() | |
ax.imshow(imgdef,cmap="gray") | |
st.pyplot(fig=fig) | |
# Printing the possibility of having anomalies | |
st.markdown("<h3 style='text-align: center;'>Possibility of anomalies</h3>",unsafe_allow_html=True) | |
model = generatemodel(xrv.models.DenseNet,"densenet121-res224-mimic_ch") ### MIMIC MODEL+ | |
model.eval() | |
pr = outputprob2(imgdef,model) | |
# Sort results by the descending probability order | |
pr = dict( sorted(pr.items(), key=operator.itemgetter(1),reverse=True)) | |
# Select the treatment | |
option = st.sidebar.selectbox('Select the treatment you believe for these illness',list(pr.keys())) | |
col1,col2,col3 = st.columns((1,1,1)) | |
cnt = 1 | |
for (key,value) in pr.items(): | |
if cnt%3==1: | |
col1.metric(label=key, value=str(cnt), delta=str(value)) | |
if cnt%3==2: | |
col2.metric(label=key, value=str(cnt), delta=str(value)) | |
if cnt%3==0: | |
col3.metric(label=key, value=str(cnt), delta=str(value)) | |
cnt+=1 | |
# temp = st.expander("Compunds to take care of {}".format(key)) | |
#### Get the compounds for the anomaly selected | |
df = getdrugs(option,max_phase) | |
st.markdown("<h3 style='text-align: center;'>Compounds for {}</h3>".format(option),unsafe_allow_html=True) | |
### If exists the compounds | |
if df is not None: | |
#### Filter dataframe by controllers | |
df_result = df[df["mol_weight"] < weight_cutoff] | |
df_result2 = df_result[df_result["Logp"] < logp_cutoff] | |
df_result3 = df_result2[df_result2["Donnors"] < NumHDonors_cutoff] | |
df_result4 = df_result3[df_result3["Acceptors"] < NumHAcceptors_cutoff] | |
if len(df_result4)==0: | |
error(option) | |
else: | |
raw_html = mols2grid.display(df_result, mapping={"smiles": "SMILES","pref_name":"Name","Acceptors":"Acceptors","Donnors":"Donnors","Logp":"Logp","mol_weight":"mol_weight"}, | |
subset=["img","Name"],tooltip=["Name","Acceptors","Donnors","Logp","mol_weight"],tooltip_placement="top",tooltip_trigger="click hover")._repr_html_() | |
components.html(raw_html, width=900, height=900, scrolling=True) | |
#### We do not find compounds for the anomaly | |
else: | |
error(option) | |