{"cells":[{"metadata":{"_uuid":"c03230e3621efd92859a45f2f71ed2bd1bb1acb9"},"cell_type":"markdown","source":"<h1>Hello everyone!</h1>\nIn this notebook, I will show a bit of my fun... i mean, work with the DICOM imagens and how I have analised them in order to try to extract better samples for a future training (probably a ConvNet)\n\nIt is a step by step of what I was thinking at the time, so it goes to some dead ends and not necessarily leads to the best solution, but I hope that it might be usefull to compare different lines of thought and perhaps give you a few ideas on how to approach this matter.\n(Feel free to comment on yours thoughts on it as well)\n"},{"metadata":{"_uuid":"438322a523fe5844fc0ef7eb6434e122554f9585"},"cell_type":"markdown","source":"So let's start. I am using these libraries, with special mention to OpenCV"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport pydicom\nfrom matplotlib import pyplot\nimport cv2 \nimport random\nimport os","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"96aa22d7d26684253baf169d2db060e750a8a5ea"},"cell_type":"markdown","source":"Now let's set up the data and see what we are dealing with:"},{"metadata":{"trusted":true,"_uuid":"05185caf787c7012d3894536ee18f8703e7e69d1"},"cell_type":"code","source":"os.listdir('../input')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3ee09117efb5cd6030d4293f3fa780189b837ce0"},"cell_type":"code","source":"treino = pd.read_csv('../input/stage_1_train_labels.csv')\npac = pd.read_csv('../input/stage_1_detailed_class_info.csv')\nimg =[]\n                  \nfor pid in treino['patientId']:\n    DICOM = pydicom.read_file('../input/stage_1_train_images/{}.dcm'.format(pid))\n    img.append(DICOM)                 \n    ","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b3536a9b8c8cbc418effc78435bc8699cbefc256"},"cell_type":"markdown","source":"Visualizing..."},{"metadata":{"trusted":true,"_uuid":"c11e6383eb38628d5799d37a65109903d1882bf7"},"cell_type":"code","source":"pyplot.imshow(img[random.randrange(len(img))].pixel_array)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"49320a38a737d0eb5cf37eae7c88735f992c7911"},"cell_type":"markdown","source":"By the way, you can change the way the image is read including a maping option to make it looks more like a x-ray:"},{"metadata":{"trusted":true,"_uuid":"188c367fe20c8d6483bc9628b173117815103171"},"cell_type":"code","source":"pyplot.imshow(img[random.randrange(len(img))].pixel_array, cmap = 'gray')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"41f509f196a45c251b35976bceb6dc4f3cb8caa0"},"cell_type":"markdown","source":"To have a broader sample, let's get more images together.\n\n*Obs: The images on this notebook are randomly selected, so if you want more samples, just re-run the code lines*"},{"metadata":{"trusted":true,"scrolled":true,"_uuid":"c201b76db0c5c05bc7245a6200dc57905b5da91c"},"cell_type":"code","source":"numIm = [4,4]\nlista=[]\nlistaId=[]\nfor i in range(numIm[0]*numIm[1]):\n    lista.append(img[random.randrange(len(img))].pixel_array)\n    listaId.append(img[random.randrange(len(img))].PatientID)\n    \ngraf, loc= pyplot.subplots(numIm[0],numIm[1], figsize=(20,20))\ni=0\nfor lo in loc:\n    for l in lo:\n        l.imshow(lista[i])\n        i =i+1","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"38d955fa54996a4690adc36111d8a22fcf75e839"},"cell_type":"markdown","source":"Can't say much from just that, so let's get a positive image and see what a \"pneumonia region\" looks like\n"},{"metadata":{"trusted":true,"_uuid":"4ea341922e5581e5b87270658eb323a98f13f223"},"cell_type":"code","source":"positives = treino[treino['Target'] == 1]\nrand = random.randrange(len(positives))\ntempInfo = positives.iloc[rand]\nfor pid in img:\n    if(pid.PatientID == tempInfo.patientId):\n        temp = pid.pixel_array\n        t1 = pid.PatientID","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2bcf880b13fcedc1ff22babe53606dab975817e8"},"cell_type":"code","source":"graf, loc= pyplot.subplots(2, figsize=(20,20))\ntemp2 = temp.copy()\ntemp2=cv2.rectangle(temp2, (int(tempInfo['x']),int(tempInfo['y'])), (int(tempInfo['x']+tempInfo['width']), int(tempInfo['y']+tempInfo['height'])) , 255, 3)\nloc[0].imshow(temp2)\n\ntemp4 = temp2[  int(tempInfo['y']) : int(tempInfo['y']+tempInfo['height']+1), int(tempInfo['x']) : int(tempInfo['x']+tempInfo['width']+1) ]\nloc[1].imshow(temp4)\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"28b0a4d8da4def474cb5175ba94bcb7392d616e4"},"cell_type":"markdown","source":"hmm... I can see that it is foggy, but can't really differentiate from any other \"foggy part\".\n\nSo, still no ideia on how to approach this.   I also don't know how doctors classify penumonia,  so I can only try to play with the information at hand \n"},{"metadata":{"_uuid":"20212589cc4c0d6390d0963cae588692566663c7"},"cell_type":"markdown","source":" So let's try some transformations and see what happens. \n \n \n First, applying some blur filters (there are 3 types)\n"},{"metadata":{"trusted":true,"_uuid":"3c8f2c7ec6631062b62170d27cebcf70f5a70782"},"cell_type":"code","source":"rand = random.randrange(len(positives))\ntempInfo = positives.iloc[rand]\nfor pid in img:\n    if(pid.PatientID == tempInfo.patientId):\n        temp = pid.pixel_array\n        t1 = pid.PatientID\n#temp with the marked place\ntempM = temp.copy()\ntempM=cv2.rectangle(tempM, (int(tempInfo['x']),int(tempInfo['y'])), (int(tempInfo['x']+tempInfo['width']), int(tempInfo['y']+tempInfo['height'])) , 255, 3)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ec2ace83560bbeed9fb37b7c590ddd8a958549a8"},"cell_type":"code","source":"kernel=(5,5)\ntemp2 = cv2.blur(temp, (kernel))\ntemp2 = cv2.blur(temp2, (kernel))\ntemp2 = cv2.blur(temp2, (kernel))\ntemp2 = cv2.blur(temp2, (kernel))\n\ngraf, loc= pyplot.subplots(1,2, figsize=(15,15))\nloc[0].imshow(tempM)\nloc[1].imshow(temp2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"40100658d722c43f97cb6e312973d7e7699f28eb"},"cell_type":"code","source":"kernel=(3,3)\ntemp2 =  cv2.GaussianBlur(temp,(kernel),0)\ntemp2 =  cv2.GaussianBlur(temp2,(kernel),0)\ntemp2 =  cv2.GaussianBlur(temp2,(kernel),0)\ntemp2 =  cv2.GaussianBlur(temp2,(kernel),0)\n\ngraf, loc= pyplot.subplots(1,2, figsize=(15,15))\nloc[0].imshow(tempM)\nloc[1].imshow(temp2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"72b98af92e05a3e3451eb6f06a246d154367d494"},"cell_type":"code","source":"temp2 = cv2.medianBlur(temp, 5)\ntemp2 = cv2.medianBlur(temp2, 5)\ntemp2 = cv2.medianBlur(temp2, 5)\ntemp2 = cv2.medianBlur(temp2, 5)\n\ngraf, loc= pyplot.subplots(1,2, figsize=(15,15))\nloc[0].imshow(tempM)\nloc[1].imshow(temp2)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c6d63133d2e5a8a3e27b919fbd72c128e043750c"},"cell_type":"markdown","source":" Can't see anything new from that."},{"metadata":{"_uuid":"a05704fc8fad1b4a25c20da715b25d8eb8bba16e"},"cell_type":"markdown","source":"Perhaps some erode/dilatations  (operations sometimes good to extract features)?"},{"metadata":{"trusted":true,"_uuid":"dd49ba9701554dceb9dba1bf39af98c97e1a1a2a"},"cell_type":"code","source":"kernel =(5,5)\ntemp2 = cv2.erode(temp, (kernel),1)\ntemp2 = cv2.dilate(temp2, (kernel),1)\nfor i in range(50):\n    temp2 = cv2.erode(temp2, (kernel),1)\nfor i in range(50):\n    temp2 = cv2.dilate(temp2, (kernel),1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0dd6f60ef4bc1485cb3465576daa9fcf19cd9484"},"cell_type":"code","source":"graf, loc= pyplot.subplots(1,2, figsize=(15,15))\nloc[0].imshow(tempM)\nloc[1].imshow(temp2)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1a6f19d8867ac66a4b3a201d529e9d129b17252f"},"cell_type":"markdown","source":"It seems pretty interesting to \"reduce\" the bones over the lungs, leaving a higher density on places that had some \"fog\" previously, but I am not convinced that it will help to diferentiation between \"non-pneumonia\" and \"pneumonia\" fogs, so I will try other things"},{"metadata":{"_uuid":"b62ab1a82009dc574778037bd5e16e50ff6e1139"},"cell_type":"markdown","source":"Using some image oparations ( dilateded minus eroded image) to extract the borders"},{"metadata":{"trusted":true,"_uuid":"07c7e98e875c7fd31d2328f3f50cb9e9e2e09e09"},"cell_type":"code","source":"kernel =(3,3)\ntemp2 = cv2.erode(temp, (kernel),1)\ntemp2 = cv2.erode(temp2, (kernel),1)\ntemp3 = cv2.dilate(temp, (kernel),1)\ntemp3 = cv2.dilate(temp3, (kernel),1)\ntemp2 = temp3-temp2\npyplot.figure(figsize=(15,15))\n\ntemp2=cv2.rectangle(temp2, (int(tempInfo['x']),int(tempInfo['y'])), (int(tempInfo['x']+tempInfo['width']), int(tempInfo['y']+tempInfo['height'])) , 255, 3)\npyplot.imshow(temp2)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"967bccbc2f5e7456a5d1e540ee605527573ef246"},"cell_type":"markdown","source":"Kind hard to evaluate, but at a closer look, also seems be hard to diferentiate between the diferent fogs"},{"metadata":{"_uuid":"1e09198e7cb529cbc5cbc0221c63e548e9860848"},"cell_type":"markdown","source":"Now some thresholding"},{"metadata":{"trusted":true,"_uuid":"b65fb1e77269c7c23dba722a24c3f7e8a8f02867"},"cell_type":"code","source":"temp2 =  cv2.GaussianBlur(temp,(5,5),0)\nret, temp2 = cv2.threshold(temp2,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)\ngraf, loc= pyplot.subplots(1,2, figsize=(15,15))\nloc[0].imshow(tempM)\nloc[1].imshow(temp2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"dbcb8e9e5e9a4d360a5e87d943bc541721d559eb"},"cell_type":"code","source":"ret, temp2 = cv2.threshold(temp2,175,255,cv2.THRESH_BINARY)\ngraf, loc= pyplot.subplots(1,2, figsize=(15,15))\nloc[0].imshow(tempM)\nloc[1].imshow(temp2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0f1b92cb4bb92035adc7b38a3a7c41d63b099f99"},"cell_type":"code","source":"ret, temp2 = cv2.threshold(temp,70,1,1)\ngraf, loc= pyplot.subplots(1,2, figsize=(15,15))\nloc[0].imshow(tempM, cmap=\"gray\")\ntemp2=cv2.addWeighted(temp, 1.2, temp2, -50, 1.0)\nloc[1].imshow(temp2, cmap=\"gray\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9e999ff94d64e88f82dfa2b65d4eef9fb36ad7da"},"cell_type":"code","source":"graf, loc= pyplot.subplots(1,3, figsize=(15,15))\nret, temp2 = cv2.threshold(temp,50,255,1)\nloc[0].imshow(tempM)\ntemp2 = temp-temp2\nloc[1].imshow(temp2)\nret, temp2 = cv2.threshold(temp2,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)\nloc[2].imshow(temp2)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d26169e17a4b420816194881403fe1e1e4f4d6d9"},"cell_type":"markdown","source":"Again, I am not convinced that it might help, specially since \"fog\" and the bones have a very close color and they end up together"},{"metadata":{"_uuid":"0df6a4e9de64149e8c2c2362b997097411a515e9"},"cell_type":"markdown","source":"And some changes to the alfa e beta changes, trying to increasing the contrast"},{"metadata":{"trusted":true,"_uuid":"7b826f9d9121d04361803ad6c7d264cad2f1384f"},"cell_type":"code","source":"temp2= cv2.convertScaleAbs(temp, alpha=3, beta=-350)\ntemp3= cv2.convertScaleAbs(temp, alpha=5, beta=-700) \ntemp4= cv2.convertScaleAbs(temp, alpha=3.5, beta=-500)\n\ngraf, loc= pyplot.subplots(2,2, figsize=(15,15))\n\nloc[0,0].imshow(tempM, cmap='gray')\nloc[0,1].imshow(temp2, cmap='gray')\nloc[1,0].imshow(temp3, cmap='gray')\nloc[1,1].imshow(temp4, cmap='gray')\nloc[1,1].set_title('the selected values after some observation')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"4492e35f23f1fd17e0f58831f534bd9b05e07676"},"cell_type":"markdown","source":"Now it seems to be a better solution. Increasing the contrast exposes a lot more (at least visually) the \"fog\". \n\nIf we start from here and try to extract the features, we might have good results. So let's define a kernel to use to train the future ml model"},{"metadata":{"_uuid":"d0bf41b148d7f60fa6239983293fef04cac00305"},"cell_type":"markdown","source":"First, let's check if the image has anything significant in the density distribution"},{"metadata":{"trusted":true,"_uuid":"e01a41cf578121cb393cbe4aa92347839bf0271d"},"cell_type":"code","source":"rand = random.randrange(len(positives))\ntempInfo = positives.iloc[rand]\nfor pid in img:\n    if(pid.PatientID == tempInfo.patientId):\n        temp = pid.pixel_array\n        t1 = pid.PatientID","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2012307167cc6bb9cb2e17209480ba3cdacc451c"},"cell_type":"code","source":"def density(imag, x,y, alt, larg):    \n    dLin=[0]*alt\n    dCol=[0]*larg\n    for col in range(larg):       \n        for row in range(alt):  \n            dLin[row] = imag[y+row, x+col] + dLin[row]\n            dCol[col] = imag[y+row, x+col] + dCol[col]  \n    return({'lin':dLin , 'col':dCol})          ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true,"_uuid":"bf8ccf967e227872dc7c0ac10c935bd2abf0d05c"},"cell_type":"code","source":"temp2 = cv2.convertScaleAbs(temp, alpha=3.5, beta=-500)\nret = density(temp2, int(tempInfo['x']), int(tempInfo['y']),int(tempInfo['height']), int(tempInfo['width']) )\nret2= density(temp2, 0, 0, len(temp), len(temp) )\n\ngraf, loc= pyplot.subplots(3,2, figsize=(20,20))\nloc[0,0].barh(range(len(ret['lin'])),list(reversed(ret['lin'])))\nloc[0,0].set_title('Vertical density (roi)')\nloc[0,1].bar(range(len(ret['col'])),ret['col'])\nloc[0,1].set_title('Horizontal density (roi)')\nloc[2,0].barh(range(len(ret2['lin'])),list(reversed(ret2['lin'])))\nloc[2,0].set_title('Vertical density (whole image)')\nloc[2,1].bar(range(len(ret2['col'])),ret2['col'])\nloc[2,1].set_title('Horizontal density (whole image)')\nloc[1,0].imshow(temp2[  int(tempInfo['y']) : int(tempInfo['y']+tempInfo['height']+1), int(tempInfo['x']) : int(tempInfo['x']+tempInfo['width']+1) ],cmap='gray')\nloc[1,0].set_title('ROI')\nloc[1,1].imshow(temp2, cmap='gray')\nloc[1,1].set_title('whole image')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"99310c972cdc1af4ffc205dc260ff1d745e94bfe"},"cell_type":"markdown","source":"No ideia if the density might be significative, hehe. \n\nBut I am starating to think that  the \"pneumonia fog\" have a shape that is closer to a \"amoeba\"  (with some \"little arms\" on the edges) than a random fog, what gives a insteresting pattern to work with.\n\nAll that is left is to find the a way to extract this information from the image"},{"metadata":{"trusted":true,"_uuid":"34f037b95ab4206dfc19583896c2397bc2460d82"},"cell_type":"code","source":"graf, loc= pyplot.subplots(3,2, figsize=(20,20))\ntemp2 = temp.copy()\ntemp2=cv2.rectangle(temp2, (int(tempInfo['x']),int(tempInfo['y'])), (int(tempInfo['x']+tempInfo['width']), int(tempInfo['y']+tempInfo['height'])) , 255, 3)\nloc[0,0].imshow(temp2)\nloc[0,0].set_title('Original')\n\ntemp2= cv2.convertScaleAbs(temp, alpha=3.5, beta=-500)\ntemp2=cv2.rectangle(temp2, (int(tempInfo['x']),int(tempInfo['y'])), (int(tempInfo['x']+tempInfo['width']), int(tempInfo['y']+tempInfo['height'])) , 255, 3)\nloc[0,1].imshow(temp2)\nloc[0,1].set_title('Alfa/Beta changes')\n\ntemp2 = cv2.medianBlur(temp, 5)\ntemp2 = cv2.medianBlur(temp2, 5)\ntemp2 = cv2.medianBlur(temp2, 5)\ntemp2= cv2.convertScaleAbs(temp2, alpha=3.5, beta=-500)\ntemp2=cv2.rectangle(temp2, (int(tempInfo['x']),int(tempInfo['y'])), (int(tempInfo['x']+tempInfo['width']), int(tempInfo['y']+tempInfo['height'])) , 255, 3)\nloc[1,0].imshow(temp2)\nloc[1,0].set_title('Alfa/Beta + blur')\n\ntemp3 = cv2.resize(temp, (64,64))\ntemp3= cv2.convertScaleAbs(temp3, alpha=3.5, beta=-500)\nloc[1,1].imshow(temp3)\nloc[1,1].set_title('Alfa/Beta + resize')\n\ntemp4 = temp2[  int(tempInfo['y']) : int(tempInfo['y']+tempInfo['height']+1), int(tempInfo['x']) : int(tempInfo['x']+tempInfo['width']+1) ]\nloc[2,0].imshow(temp4)\nloc[2,0].set_title('Alfa/Beta + blur on ROI')\n\ntemp5= cv2.resize(temp4, (32,32))\nloc[2,1].imshow(temp5)\nloc[2,1].set_title('Alfa/Beta + resize on ROI')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"eb2896ae83757195bb2cf802331be309d3022483"},"cell_type":"markdown","source":"After some attempts, I figured that not only it is possible to reduce the image size without losing too much information (in this case, the \"fog\" still kind of looks likes an amoeba, what is a must to gain efficiency.\n\nSo, let's compare with some random negative data to see if they are really diferent and might be good subjects to a ml model\n"},{"metadata":{"trusted":true,"_uuid":"f1478928558cf1d358b14ba1b94f58ed889c1bd6"},"cell_type":"code","source":"negatives = treino[treino['Target'] == 0]\nrand = random.randrange(len(negatives))\ntempInfoN = negatives.iloc[rand]\nfor pid in img:\n    if(pid.PatientID == tempInfoN.patientId):\n        tempN = pid.pixel_array\n        t1 = pid.PatientID\n        \ntempN = cv2.convertScaleAbs(tempN, alpha=3.5, beta=-500)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"32004721b7ce39dbfc8aeb188dab3385313a55da"},"cell_type":"code","source":"rand = random.randrange(len(positives))\ntempInfo = positives.iloc[rand]\nfor pid in img:\n    if(pid.PatientID == tempInfo.patientId):\n        temp = pid.pixel_array\n        t1 = pid.PatientID\ntemp = cv2.convertScaleAbs(temp, alpha=3.5, beta=-500)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"030b170480d446d13e29c2dde909dc7763c8ef2e"},"cell_type":"code","source":"graf, loc= pyplot.subplots( 2 , figsize=(15,15))\n\ntemp = temp[int(tempInfo['y']) : int(tempInfo['y']+tempInfo['height']+1), int(tempInfo['x']) : int(tempInfo['x']+tempInfo['width']+1)]\ntemp = cv2.resize(temp, (32,32))\n\nloc[0].imshow(temp)\nloc[0].set_title('random positive sample')\ntam = 1024 - 32\n\nx= random.randrange(tam)\ny= random.randrange(tam)\n\nloc[1].imshow(tempN[y:y+32 , x:x+32] )       \nloc[1].set_title('random negative sample')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f8866a6a596049d4f852bf50610092966a3b3548"},"cell_type":"markdown","source":"Overall, the positive samples are more \"granulated\" than the negatives ones.\nSeems promissing!\n\nNow, all that is left to do is test this concept and see if we can train something from this.\n\n<hr>\n I hope that this might have been usefull to you.\n Please excuse any language mistakes and feel free to share your toughts/tips on this notebook as well!"},{"metadata":{"trusted":true,"_uuid":"06a36b70ef49a7ebac7b3f55d44b4f69ab527087"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}