Skip to content

Commit

Permalink
Merge pull request #38 from camicroscope/develop
Browse files Browse the repository at this point in the history
3.8.0
  • Loading branch information
birm authored Sep 17, 2020
2 parents 6171900 + d4186f4 commit 62b4b0f
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 37 deletions.
151 changes: 125 additions & 26 deletions SlideServer.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from os import listdir
from os.path import isfile, join
from spritemaker import createSpritesheet

from PIL import Image
import urllib
import flask
import flask_cors
Expand Down Expand Up @@ -38,6 +38,7 @@
app.config['TEMP_FOLDER'] = "/images/uploading/"
app.config['TOKEN_SIZE'] = 10
app.config['SECRET_KEY'] = os.urandom(24)
app.config['ROI_FOLDER'] = "/images/roiDownload"

ALLOWED_EXTENSIONS = set(['svs', 'tif', 'tiff', 'vms', 'vmu', 'ndpi', 'scn', 'mrxs', 'bif', 'svslide'])

Expand Down Expand Up @@ -280,38 +281,44 @@ def getLabelsZips():
@app.route('/workbench/getCustomData', methods=['POST'])
def getCustomData():
data = flask.request.get_json()
fileName = data['fileNames'][0]
userFolder = ''.join(random.choice(
string.ascii_uppercase + string.digits) for _ in range(20))
fileName = data['fileName']
userFolder = data['userFolder']
if not os.path.isdir(app.config['DATASET_FOLDER']+userFolder):
os.makedirs(app.config['DATASET_FOLDER']+userFolder)
path = os.path.join(app.config['DATASET_FOLDER']+userFolder+'/', fileName)
fileData = base64.b64decode(data['files'][0])
fileData = base64.b64decode(data['file'])
offset = data['offset']
file = open(path, "ab")
file.seek(0)
file.seek(int(offset))
file.write(fileData)
file.close()
if(zipfile.is_zipfile(path) == False):
deleteDataset(userFolder)
return flask.Response(json.dumps({'error': 'Not a valid zip file/files'}), status=400)
file = zipfile.ZipFile(path, 'r')
# app.logger.info(file.namelist())
contents = file.namelist()
labelsData = {'labels': [], 'counts': [], 'userFolder': userFolder}
for item in contents:
if '/' not in item:
return flask.Response(json.dumps({'error': 'zip should contain only folders!'}), status=400)
if item.endswith('/') == False and item.endswith('.jpg') == False and item.endswith('.png') == False:
return flask.Response(json.dumps({'error': 'Dataset should have only png/jpg files!'}), status=400)
if item.split('/')[0] not in labelsData['labels']:
labelsData['labels'].append(item.split('/')[0])
for label in labelsData['labels']:
count = -1
final = data['final']
if(final == 'true'):
if(zipfile.is_zipfile(path) == False):
deleteDataset(userFolder)
return flask.Response(json.dumps({'error': 'Not a valid zip file/files'}), status=400)
file = zipfile.ZipFile(path, 'r')
# app.logger.info(file.namelist())
contents = file.namelist()
labelsData = {'labels': [], 'counts': [], 'userFolder': userFolder}
for item in contents:
if item.startswith(label+'/'):
count+=1
labelsData['counts'].append(count)
return flask.Response(json.dumps(labelsData), status=200)
if '/' not in item:
deleteDataset(userFolder)
return flask.Response(json.dumps({'error': 'zip should contain only folders!'}), status=400)
if item.endswith('/') == False and item.endswith('.jpg') == False and item.endswith('.jpeg') == False and item.endswith('.png') == False and item.endswith('.tif') == False and item.endswith('.tiff') == False:
deleteDataset(userFolder)
return flask.Response(json.dumps({'error': 'Dataset zip should have only png/jpg/tif files!'}), status=400)
if item.split('/')[0] not in labelsData['labels']:
labelsData['labels'].append(item.split('/')[0])
for label in labelsData['labels']:
count = -1
for item in contents:
if item.startswith(label+'/'):
count+=1
labelsData['counts'].append(count)
return flask.Response(json.dumps(labelsData), status=200)
else:
return flask.Response(json.dumps({'status' : 'pending'}), status=200)


# Route to organise the extracted zip file data according to user sent customized labels and create a spritesheet
Expand Down Expand Up @@ -429,3 +436,95 @@ def deleteDataset(userFolder):
return flask.Response(json.dumps({"deleted": "false", 'message': 'Traversal detected or invalid foldername'}), status=403)
shutil.rmtree(app.config['DATASET_FOLDER']+userFolder)
return flask.Response(json.dumps({"deleted": "true"}), status=200)


# Helper function for converting slides into jpg
def _get_concat_h(img_lst):
width, height, h = sum([img.width for img in img_lst]), img_lst[0].height, 0
dst = Image.new('RGB', (width, height))
for img in img_lst:
dst.paste(img, (h, 0))
h += img.width
return dst

# Helper function for converting slides into jpg
def _get_concat_v(img_lst):
width, height, v = img_lst[0].width, sum([img.height for img in img_lst]), 0
dst = Image.new('RGB', (width, height))
for img in img_lst:
dst.paste(img, (0, v))
v += img.height
return dst

# FUnction to convert slides into jpg images
def convert(fname, input_dir , output_dir):
UNIT_X, UNIT_Y = 5000, 5000
try:

save_name = fname.split(".")[0] + ".jpg"
os_obj = openslide.OpenSlide(input_dir+"/"+fname)
w, h = os_obj.dimensions
w_rep, h_rep = int(w/UNIT_X)+1, int(h/UNIT_Y)+1
w_end, h_end = w%UNIT_X, h%UNIT_Y
w_size, h_size = UNIT_X, UNIT_Y
w_start, h_start = 0, 0
v_lst = []
for i in range(h_rep):
if i == h_rep-1:
h_size = h_end
h_lst = []
for j in range(w_rep):
if j == w_rep-1:
w_size = w_end
img = os_obj.read_region((w_start,h_start), 0, (w_size,h_size))
img = img.convert("RGB")
h_lst.append(img)
w_start += UNIT_X
v_lst.append(h_lst)
w_size = UNIT_X
h_start += UNIT_Y
w_start = 0
concat_h = [_get_concat_h(v) for v in v_lst]
concat_hv = _get_concat_v(concat_h)
concat_hv.save(output_dir+"/"+save_name)
except:
print("Can't open image file : %s"%fname)
traceback.print_exc()
return

# Route to extract the patches using the predictions recieved
@app.route('/roiExtract', methods = ['POST'])
def roiExtract():
data = flask.request.get_json()
pred = data['predictions']
filename = data['filename']
step = data['patchsize']
fn =filename.split(".")[0] + ".jpg"
if os.path.isdir("/images/roiDownload"):
shutil.rmtree(app.config['ROI_FOLDER'])
os.makedirs("/images/roiDownload")
filepath = "/images/roiDownload/roi_Download" + filename + ".zip"
convert(filename, "/images","/images/roiDownload")
download_patches = zipfile.ZipFile(filepath, 'w')
img = Image.open("/images/roiDownload/"+fn)
for i in range(len(data['predictions'])):
img1 = img.crop((int(data['predictions'][i]['X']),int(data['predictions'][i]['Y']) , int(data['predictions'][i]['X'])+int(step),int(data['predictions'][i]['Y'])+int(step)))
img1.save("/images/roiDownload/"+str(data['predictions'][i]['cls'])+'_'+str(i)+'_'+ str(data['predictions'][i]['acc']*100)+".jpg")
download_patches.write("/images/roiDownload/"+str(data['predictions'][i]['cls'])+'_'+str(i)+'_'+ str(data['predictions'][i]['acc']*100)+".jpg" , "/patches/"+
str(data['predictions'][i]['cls'])+"/"+str(data['predictions'][i]['cls'])+'_'+str(i)+'_'+ str(data['predictions'][i]['acc']*100)+".jpg")

download_patches.close()

# img = openslide.OpenSlide.read_region((0,0),0,(100,100))
# img = slide.open_image(img_path)
# res= { "data" :"" }
# res['data']= pred
return flask.Response(json.dumps({"extracted": "true"}), status=200)

# Route to send back the extracted
@app.route('/roiextract/<file_name>')
def roiextract(file_name):

return flask.send_from_directory(app.config["ROI_FOLDER"],filename=file_name, as_attachment=True, cache_timeout=0 )


2 changes: 1 addition & 1 deletion SlideUtil.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def openslidedata(metadata):
metadata['width'] = slideData.get(openslide.PROPERTY_NAME_BOUNDS_WIDTH, None)
metadata['vendor'] = slideData.get(openslide.PROPERTY_NAME_VENDOR, None)
metadata['level_count'] = int(slideData.get('level_count', 1))
metadata['objective'] = float(slideData.get("aperio.AppMag", None))
metadata['objective'] = float(slideData.get("aperio.AppMag", 0.0))
metadata['md5sum'] = file_md5(metadata['location'])
metadata['timestamp'] = time.time()
thumbnail_size = config.get('thumbnail_size', None)
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ flask
Werkzeug
flask-cors
requests
numpy
numpy
Pillow
15 changes: 6 additions & 9 deletions spritemaker.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,12 @@ def createSpritesheet(datasetPath, labelsNames, width, height):
y_offset = 0
imageCount = 0
imageFiles = []
for image_file in Path(TRAINING_PATH).glob("**/*.jpg"):
imageCount += 1
imageFiles.append(image_file)
for image_file in Path(TRAINING_PATH).glob("**/*.png"):
imageCount += 1
imageFiles.append(image_file)
for image_file in Path(TRAINING_PATH).glob("**/*.jpeg"):
imageCount += 1
imageFiles.append(image_file)

allowed_extentions = ['jpg', 'png', 'jpeg', 'tif', 'tiff']
for ext in allowed_extentions:
for image_file in Path(TRAINING_PATH).glob("**/*." + ext):
imageCount += 1
imageFiles.append(image_file)

print(imageCount, file=sys.stderr)
new_im = Image.new('RGB', (width*height, imageCount))
Expand Down

0 comments on commit 62b4b0f

Please sign in to comment.