Skip to content

Commit

Permalink
Merge pull request #5 from eipm/update-ai-biopsy
Browse files Browse the repository at this point in the history
Update ai biopsy
  • Loading branch information
alexsigaras authored Sep 21, 2020
2 parents 9d348fb + aa46d17 commit a2c1751
Show file tree
Hide file tree
Showing 10 changed files with 145 additions and 55 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
README.md

data
env
.git
8 changes: 3 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
FROM python:3.6.8-stretch
FROM python:3.7.9-buster
#===============================#
# Docker Image Configuration #
#===============================#
LABEL vendor='Englander Institute for Precision Medicine' \
description='AI Biopsy' \
maintainer='[email protected]' \
base_image='python' \
base_image_version='3.6.8-stretch' \
base_image_SHA256='sha256:ab2670ec57d486f73e49e7352de6a80b6767e3c996c1c0d0c158f17ae6f2d113'
maintainer='[email protected]'

ENV APP_NAME='ai_biopsy' \
TZ='US/Eastern' \
AI_BIOPSY_SRC_DIR='/ai_biopsy/src/ai_biopsy_src' \
PREDICT_DIR='/ai_biopsy/src/ai_biopsy_src/slim'

ENV RESULT_DIR=${AI_BIOPSY}/result \
PROCESS_DIR=${AI_BIOPSY}/process \
PYTHONPATH=${PYTHONPATH}:${AI_BIOPSY}:${PREDICT_DIR}
Expand Down
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
# AI Biopsy

Needs to be updated
<p align="center">
<img src="docs/images/logo.png" width="256">
</p>

[![Python 3.6](https://img.shields.io/badge/python-3.6-blue.svg)](https://www.python.org/downloads/release/python-360/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
# AI Biopsy

![AI Biopsy Logo](docs/images/logo.png)
[![Python 3.7.9](https://img.shields.io/badge/python-3.7.9-blue.svg)](https://www.python.org/downloads/release/python-379/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## AI Biopsy Requirements

Expand Down
54 changes: 28 additions & 26 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,37 +1,39 @@
absl-py==0.7.0
astor==0.7.1
cachetools==2.1.0
certifi==2018.10.15
absl-py==0.10.0
astor==0.8.1
cachetools==4.1.1
certifi==2020.6.20
chardet==3.0.4
Click==7.0
Click==7.1.2
CouchDB==1.2
Flask==1.0.2
Flask-Cors==3.0.7
Flask==1.1.2
Flask-Cors==3.0.9
Flask-Uploads==0.2.1
gast==0.2.2
grpcio==1.15.0
h5py==2.9.0
idna==2.7
grpcio==1.32.0
h5py==2.10.0
idna==2.10
itsdangerous==1.1.0
Jinja2==2.10
Keras-Applications==1.0.6
Jinja2==2.11.2
Keras-Applications==1.0.8
Keras-Preprocessing==1.0.5
Markdown==3.0.1
MarkupSafe==1.1.0
numpy==1.15.2
protobuf==3.6.1
Markdown==3.2.2
MarkupSafe==1.1.1
numpy==1.16.0
protobuf==3.13.0
pyasn1==0.4.4
pyasn1-modules==0.2.2
pytz==2018.5
requests==2.20.0
rsa==4.0
selenium==3.14.1
six==1.12.0
tensorboard==1.12.2
tensorflow==1.12.0
requests==2.24.0
rsa==4.6
selenium==3.141.0
six==1.15.0
tensorboard==1.15.0
tensorflow==1.15.3
termcolor==1.1.0
urllib3==1.24
virtualenv==16.2.0
Werkzeug==0.14.1
urllib3==1.25.10
virtualenv==20.0.31
Werkzeug==1.0.1
opencv-python==4.0.0.21
matplotlib==3.0.3
matplotlib==3.3.2
pydicom==2.0.0
pypng==0.0.20
2 changes: 1 addition & 1 deletion src/ai_biopsy_src/slim/predict.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
session = tf.Session()

def get_test_images(mypath):
return [mypath + '/' + f for f in listdir(mypath) if isfile(join(mypath, f)) and f.find('.jpg') != -1]
return [mypath + '/' + f for f in listdir(mypath) if isfile(join(mypath, f)) and f.find('.png') != -1]

def transform_img_fn(path_list):
out = []
Expand Down
31 changes: 26 additions & 5 deletions src/api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import glob
import ntpath
import datetime
import numpy as np
import png, pydicom
from ast import literal_eval

# Relative Imports
Expand All @@ -20,7 +22,7 @@
STATIC_DIR = '/ai_biopsy/src'
RESULT_DIR = '/ai_biopsy/src/ai_biopsy_src/result/'

ALLOWED_EXTENSIONS = set(['jpg', 'png', 'tif', 'tiff'])
ALLOWED_EXTENSIONS = set(['jpg', 'png', 'tif', 'tiff', 'dcm'])

static_file_dir = os.path.join(STATIC_DIR, 'static')

Expand Down Expand Up @@ -103,10 +105,29 @@ def upload_image():

# 3. Normalize images to jpeg format
for image in glob.glob(os.path.join(request_dir, '*.*')):
img = cv2.imread(image)
os.remove(image)
filename = '%s.jpg' % os.path.splitext(image)[0]
cv2.imwrite(os.path.join(request_dir, filename), img)
filename = os.path.splitext(image)[0]
if os.path.splitext(image)[1] == '.dcm':
ds = pydicom.dcmread(image)
shape = ds.pixel_array.shape

# Convert to float to avoid overflow or underflow losses.
image_2d = ds.pixel_array.astype(float)

# Rescaling grey scale between 0-255
image_2d_scaled = (np.maximum(image_2d,0) / image_2d.max()) * 255.0

# Convert to uint
image_2d_scaled = np.uint8(image_2d_scaled)

# Write the PNG file
with open(os.path.join(request_dir, filename) + '.png' , 'wb') as png_file:
w = png.Writer(shape[1], shape[0], greyscale=True)
w.write(png_file, image_2d_scaled)
else:
img = cv2.imread(image)
os.remove(image)
filename = '%s.png' % filename
cv2.imwrite(os.path.join(request_dir, filename), img)

# 4. Specify Output log
output_filename = 'output_' + request_id + '.txt'
Expand Down
2 changes: 1 addition & 1 deletion src/api/version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version = '1.0.0'
version = '1.1.0'

def api_version():
return version
80 changes: 74 additions & 6 deletions src/static/assets/ai_biopsy.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const baseApiUrl = 'api'
let token = getCookie('ai-biopsy-auth');
checkTokenAndRedirectIfEmpty();

document.getElementById('year').innerHTML = new Date().getFullYear();

setInterval(function(){
checkTokenAndRedirectIfEmpty();
}, 5000);
Expand Down Expand Up @@ -68,8 +70,8 @@ function average(array) {
}

function isAnImage(file) {
if (file && file.type) {
return file.type.startsWith('image/jpeg') || file.type.startsWith('image/png') || file.type.startsWith('image/tiff');
if (file && (file.type || file.name)) {
return file.type.startsWith('image/jpeg') || file.type.startsWith('image/png') || file.type.startsWith('image/tiff') || file.name.endsWith('.dcm');
}

return false;
Expand Down Expand Up @@ -198,6 +200,64 @@ function clearAllImageCards() {
});
};

async function getDcmImage(file) {
const width = 256;
const height = 256;
let pixelData = null;

function str2ab(str) {
var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
var bufView = new Uint16Array(buf);
var index = 0;
for (var i=0, strLen=str.length; i<strLen; i+=2) {
var lower = str.charCodeAt(i);
var upper = str.charCodeAt(i+1);
bufView[index] = lower + (upper <<8);
index++;
}
return bufView;
};

const toBase64 = file => new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});

const base64 = await toBase64(file);
const base64PixelData = base64.substring(base64.indexOf('base64,') + 'base64,'.length);
const pixelDataAsString = atob(base64PixelData);
pixelData = str2ab(pixelDataAsString);

function getPixelData() {
return pixelData;
}

var image = {
imageId: file.name,
minPixelValue : 0,
maxPixelValue : 257,
slope: 1.0,
intercept: 0,
windowCenter : 127,
windowWidth : 256,
getPixelData: getPixelData,
rows: height,
columns: width,
height: height,
width: width,
color: false,
columnPixelSpacing: .8984375,
rowPixelSpacing: .8984375,
sizeInBytes: width * height * 2
};

return new Promise((resolve) => {
resolve(image);
});
}

function createImagesUIFromFiles(files, imagesPlaceholder) {
if (files === null || files === undefined || imagesPlaceholder === null || imagesPlaceholder === undefined) {
return;
Expand All @@ -209,9 +269,7 @@ function createImagesUIFromFiles(files, imagesPlaceholder) {
imagePlaceholder.id = `image-card-${file.name}`;
imagePlaceholder.innerHTML = `
<div class="card image-container">
<div class="card-image">
<img alt="${file.name}" width="330px" />
</div>
<div class="card-image" ></div>
<div class="card-file-name">${file.name}</div>
<div class="loader"></div>
Expand All @@ -227,8 +285,18 @@ function createImagesUIFromFiles(files, imagesPlaceholder) {
</div>
</div>`;
imagesPlaceholder.appendChild(imagePlaceholder);
const cardImage = imagePlaceholder.getElementsByClassName('card-image')[0];

if (file.name.endsWith('.dcm')) {
cornerstone.enable(cardImage);
getDcmImage(file).then(function(image) {
cornerstone.displayImage(cardImage, image);
});
} else {
cardImage.innerHTML = `<img alt="${file.name}" width="330px" />`;
}

const image = imagePlaceholder.getElementsByTagName('img')[0];
const image = cardImage.children[0];
const reader = new FileReader();
reader.onload = function (e) {
image.setAttribute('src', e.target.result);
Expand Down
7 changes: 4 additions & 3 deletions src/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<link rel="stylesheet" href="assets/materialize.min.css">
<link href="assets/font-material-icons.css" rel="stylesheet">
<link href="assets/ai_biopsy.css" rel="stylesheet">
<script src="https://unpkg.com/cornerstone-core/dist/cornerstone.min.js"></script>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-53992417-18"></script>
<script>
Expand All @@ -27,7 +28,7 @@
<label for="file-select" id="add-images-button" class="btn">
<i class="material-icons left">add</i>Add Images
</label>
<input type="file" id="file-select" multiple="multiple" accept="image/jpeg, image/png, image/tiff" class="hidden" />
<input type="file" id="file-select" multiple="multiple" class="hidden" />
<div id="error-message" class="error-message hidden">You can add up to 100 images</div>
</div >

Expand All @@ -53,8 +54,8 @@
<div class="push"></div>
</div>
<footer>
<div>Copyright © 2019 Englander Institute for Precision Medicine</div>
<div>AI Biopsy Version 1.0.0</div>
<div>Copyright © <span id="year"></span> Englander Institute for Precision Medicine</div>
<div>AI Biopsy Version 1.1.0</div>
<img alt="logo" class="footer-logo" src="assets/LOGO_ENGLANDER_2LINE_RGB.png">
</footer>

Expand Down
4 changes: 2 additions & 2 deletions src/static/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ <h5 class="login-title">Log in</h5>
</div>
</div>
<footer>
<div>Copyright © 2019 Englander Institute for Precision Medicine</div>
<div>AI Biopsy Version 1.0.0</div>
<div>Copyright © <span id="year"></span> Englander Institute for Precision Medicine</div>
<div>AI Biopsy Version 1.1.0</div>
<img alt="logo" class="footer-logo" src="assets/LOGO_ENGLANDER_2LINE_RGB.png">
</footer>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>
Expand Down

0 comments on commit a2c1751

Please sign in to comment.