Skip to content

Commit

Permalink
YaDV code changes
Browse files Browse the repository at this point in the history
  • Loading branch information
prahalad12345 committed Jul 10, 2021
1 parent 3d0d0b3 commit 98c2e51
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 59 deletions.
4 changes: 2 additions & 2 deletions yadv.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
def main():
# YaDV Application setup
st.header("YaDV - Yet Another DICOM Viewer")
icon = Image.open('./images/YADV.png')
icon = Image.open('images/YADV.png')
st.sidebar.image(icon, caption="Yet another DICOM Viewer")
st.sidebar.title("YaDV - Options")

Expand All @@ -73,6 +73,6 @@ def main():
for medical images designed to provide users with simple experience
to view and analyze DICOM images..
""")

if __name__ == "__main__":
main()
36 changes: 32 additions & 4 deletions yadv_3ddicom_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,30 @@
from plotly.tools import FigureFactory as FF
from plotly.offline import plot,iplot
from mpl_toolkits.mplot3d.art3d import Poly3DCollection


def threedVisulaization():

'''
3d visualization is a function only accesible to CT images , because CT image have specification of z axis which helps in plotting in 3d
This helps in viewing the CT images in 3D which help in finding the dislocation and error in the bone structure more effectively
The implementation is done using the marching cube algorithm though slow works well
'''

st.subheader("DICOM Operation")
uploaded_file = st.file_uploader("Upload a DICOM image file",accept_multiple_files=True)
if uploaded_file:
st.subheader("DICOM Image List:")
imagelist = load_file(uploaded_file)
count=0

type_name = st.sidebar.selectbox("Choose DICOM operation", ["Plot 3d","Interactive 3d"])

st.set_option('deprecation.showPyplotGlobalUse', False)

try:
for i in range(len(imagelist)):
'''
check if the list of images selected has only CT images
'''
if(imagelist[i].Modality!='CT'):
st.error('This section is for CT images')
return
Expand All @@ -81,6 +89,11 @@ def threedVisulaization():
st.error("error")

def getPixelHounsFieldUnit(scans):
'''
Hounsfield Units is the relative density of the material with respect to water
the data in different CT scan is stored in a different format .
To make it uniform globally a slope and intercept is present in every image which on equating with the image produce a value which is constant to all Modality
'''
image=np.stack([files.pixel_array for files in scans])

image=image.astype(np.int16)
Expand All @@ -98,6 +111,12 @@ def getPixelHounsFieldUnit(scans):
return np.array(image , dtype=np.int16)

def resampleDICOMImage(image, scan, new_spacing=[1,1,1]):
'''
The slice thickness is relative to the first image and second image
pixel spacing provides the physical distance of spacing between the center of each pixel
to provide spacing between the two images resampling is required and a matching plot with the image
'''
# Determine current pixel spacing
spacing = np.array([scan[0].SliceThickness] + (list)(scan[0].PixelSpacing), dtype=np.float32)
resize_factor = spacing / new_spacing
Expand All @@ -111,10 +130,16 @@ def resampleDICOMImage(image, scan, new_spacing=[1,1,1]):
return image, new_spacing

def create3dMesh(image, threshold=-300, step_size=1):
'''
this function creates the 3d meesh for the data of image given to this function
'''
p = image.transpose(2,1,0)
verts, faces, norm, val = measure.marching_cubes(p, threshold, step_size=step_size, allow_degenerate=True)
return verts, faces

'''
plotly_3d and plt_3d are the two different approach to plot with the mesh
plotly_3d is works better than plt_3d
'''
def plotly_3d(verts, faces):
x,y,z = zip(*verts)

Expand Down Expand Up @@ -148,6 +173,9 @@ def plt_3d(verts, faces):
ax.set_facecolor((0.7, 0.7, 0.7))

def load_file(path):
'''
this function reads the file and adds the slice thickness to estimate the thickness of the respective image
'''
images=[dicom.read_file(files) for files in (path)]
if(images[0].Modality!='CT'):
return images
Expand Down
7 changes: 6 additions & 1 deletion yadv_covid_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,16 @@
from streamlit import uploaded_file_manager

def covidDetector():
'''
The model detect whether he is infected with covid or not
The difference between the covid and non covid patients:
covid frontal lungs are swollen due to the excess mucus secretion
this factor is used to train the models using fast.ai
'''
st.subheader("COVID Detector")
uploaded_file = st.file_uploader("Upload a front lung scan image ")
#filee=uploaded_file
if uploaded_file:
print(type(uploaded_file.type))
if uploaded_file.type == 'application/dicom' or uploaded_file.type=='application/octet-stream':
file_bytes = dicom.read_file(uploaded_file)
img = file_bytes.pixel_array
Expand Down
107 changes: 60 additions & 47 deletions yadv_dicom_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,36 +48,15 @@
from PIL import Image,ImageOps
from pydicom.pixel_data_handlers.numpy_handler import pack_bits

def load_file(path):
images=[dicom.read_file(files) for files in (path)]

images.sort(key=lambda x:int(x.InstanceNumber))
slicethickness=np.abs(images[0].ImagePositionPatient[2]-images[1].ImagePositionPatient[2])
for files in images:
files.SliceThickness=slicethickness
return images


def getPixelHounsFieldUnit(scans):
image=np.stack([files.pixel_array for files in scans])

image=image.astype(np.int16)

image[image==-2000] = 0

intercept=scans[0].RescaleIntercept
slope=scans[0].RescaleSlope

if slope != 1:
image=slope*image.astype(np.float64)
image=image.astype(np.int16)
image+=np.int16(intercept)

return np.array(image , dtype=np.int16)



def dicomProcessing():
'''
This function helps physician to work with a single dicom image effectively
This funciton has 4 subfunciton
1)Windowing
2)zoom
3)rotating the image
4)overlay section
'''
st.subheader("DICOM Operation")
uploaded_file = st.file_uploader("Upload a DICOM image file", type=[".dcm"])
col1, col2 = st.beta_columns(2)
Expand All @@ -90,12 +69,17 @@ def dicomProcessing():
col1.image(image)
df = create_table(file_bytes)
st.write(df)
#this code below allow to plot graph on streamlit without warning message
st.set_option('deprecation.showPyplotGlobalUse', False)
if(file_bytes.Modality=='CT'):
imagetoplot=gethu(file_bytes)
leftcol,rightcol = st.beta_columns(2)
leftcol.pyplot(hounsfieldunitgraphh(imagetoplot))
rightcol.write(hudataframe())
leftcol.pyplot(generateHounsFieldUnitGraph(imagetoplot))
rightcol.write(getHounsFieldUnitDataFrame())
'''
To add overlay the location on the dicom file(0x60000x3000) should have some data in it otherwise the Overlay section will not be accepted
To obtain the overlay first check if overlay section exist if there is an error a numpy array of zero is converted to bits and stored at that respective location
'''
try:
elem=file_bytes[0x6000, 0x3000]
except:
Expand All @@ -106,10 +90,13 @@ def dicomProcessing():

# types
type_name = st.sidebar.selectbox("Choose DICOM operation", ["Windowing",
"Zoom", "Rotate", "Overlays"])
dict={"Windowing":windowing,"Zoom":handle_zoom,"Rotate":rotation,"Overlays":overlay}
"Zoom",
"Rotate",
"Overlays"])
dict={"Windowing":handle_windowing,"Zoom":handle_zoom,"Rotate":handle_rotation,"Overlays":handle_overlay}
try:
if st.button('Export'):
#if you want to save that dicom file (This option doesnt save your overlay diom file)
exportbutton(file_bytes)
if type_name == "Zoom" or type_name=="Rotate":
col2.subheader(type_name)
Expand All @@ -123,6 +110,7 @@ def dicomProcessing():
col2.subheader(type_name)
file=dict['Overlays'](file_bytes,image)
col2.image(file)
#on clicking on the button the image with overlay is exported
if(st.sidebar.button('Export Overlay image')):
exportoverlay(file_bytes,file)
else:
Expand All @@ -135,6 +123,11 @@ def dicomProcessing():
st.error(exception, False)

def handle_zoom(image):
'''
Zooming is an important option in a dicom viewer
It allows the physician to view the error in the scan in a greater view
if the value goes less than zero it zoom out else it zoom in
'''
try:
zoomslider = st.sidebar.slider('Zoom In/Out', -9, 15,0)
if(zoomslider<0):
Expand All @@ -154,7 +147,11 @@ def handle_zoom(image):
# Output unexpected Exceptions.
st.error(exception, False)

def rotation(image):
def handle_rotation(image):
'''
rotation is used when a physician wants to view an image with a beter angle for clarity
this is done using opencv warpAffine function . The matrice give information about the angle of rotation to the respective image and the center of rotation
'''
rotateslider = st.sidebar.slider('Angle of rotation', 0,359)
centerX=(image.shape[0])/2
centerY=(image.shape[1])/2
Expand All @@ -173,7 +170,12 @@ def rotation(image):
return result


def windowing(img):
def handle_windowing(img):
'''
Windowing is used to view the image based on the respective hounsfield unit interval
This helps physicians to view only the parts of the scan which is a matter of concern and ignoring the rest
most of the positive value window is occupied by the bone
'''
hu1slider = st.sidebar.slider('Minimum HU value', -1000,2999)
hu2slider = st.sidebar.slider('Maximum HU value', -1000,3000)

Expand All @@ -183,6 +185,9 @@ def windowing(img):
return finalimage

def create_table(ds):
'''
This is just an info table about the dicom file
'''
flag=0
for i in ds.keys():
flag=i
Expand All @@ -208,6 +213,7 @@ def create_table(ds):
return df

def gethu(dicomfile):
#obtain the hounsfield unit
im=dicomfile.pixel_array
im=im.astype(np.int16)
im[im==-2000] = 0
Expand All @@ -220,22 +226,16 @@ def gethu(dicomfile):
im+=np.int16(intercept)

return im

def hounsfieldunitgraph(image):
im=image.astype(np.float64)
plt.hist(im.flatten(),bins=40,color='c')
plt.xlabel('Hounsfield unit')
plt.ylabel=('frequency')
fig=plt.figure()
return fig

def hounsfieldunitgraphh(image):
def generateHounsFieldUnitGraph(image):
#plotting the hounsfield unit in a histogram plot
im=image.astype(np.float64)
plt.hist(im.flatten(),bins=40,color='c')
plt.xlabel('Hounsfield unit')
plt.ylabel=('frequency')

def hudataframe():
def getHounsFieldUnitDataFrame():
#this is a static function which prints the window of hounsfield unit
hulist=[['Air','-1000'],['Lung','-500'],['Fat','-100 to -50'],['Water','0'],['CSF','15'],['Kidney','30'],['Blood','30 to 45'],['Muscle','10 to 40'],['whitematter','20 to 30'],['greymatter','37 to 45'],['Liver','40 to 60'],['Softtissue','100 to 300'],['Bone','700 (cancellous bone) to 3000 (cortical bone']]
df=pd.DataFrame(hulist,columns=['Substance','HU value'])
return df
Expand Down Expand Up @@ -276,19 +276,31 @@ def get_first_of_dicom_field_as_int(x):


def get_windowing(data):
#obtains the rescale intercept and rescale slope from the dicom file
dicom_fields = [ data.RescaleIntercept,
data.RescaleSlope]
return [get_first_of_dicom_field_as_int(x) for x in dicom_fields]

def exportbutton(file):
'''
The SHA (Secure Hash Algorithm) is one of a number of cryptographic hash functions .A cryptographic hash is like a signature for a data set.
one of hasing algorith to encrypt data . The California Consumer Privacy Act of 2018 provides control over personal information that buisnesses
collect about them .Voilation of this act has hefty fine amount.
After encryption the file is save in the Exportfile folder
'''
file.PatientName=sha256(file.PatientName)
file.PatientSex=sha256(file.PatientSex)
file.save_as('Exportfile/'+(str)(file.PatientName)+'-'+(str)(file.InstanceNumber) + ".dcm")
st.success("file saved")

return

def overlay(ds,image):
def handle_overlay(ds,image):

'''
overlays are an important feature in a dicom viewer .This helps the physician to draw on the image and helps in pointing out excessive growth ,inflammation .etc
(Use only white color for drawing)
'''
stroke_width = st.sidebar.slider("Stroke width: ", 1, 25, 3)
stroke_color = st.sidebar.color_picker("Stroke color hex: ",'#ffffff')
bg_color = st.sidebar.color_picker("Background color hex: ", "#000000")
Expand Down Expand Up @@ -339,6 +351,7 @@ def overlay(ds,image):
return imagefinal

def exportoverlay(file,image):
#function stores the image after overlay
name=sha256(file.PatientName)
cv2.imwrite('overlayimage/'+(str)(name)+'-'+(str)(file.InstanceNumber)+".jpg",image)
st.success("file saved")
st.success("file saved")
Loading

0 comments on commit 98c2e51

Please sign in to comment.