From: Bernardo TOD Date: Mon, 17 Jun 2019 16:07:49 +0000 (+0200) Subject: integrate distinction_word, for deployment X-Git-Url: https://bilbo.iut-bm.univ-fcomte.fr/and/gitweb/myo-class.git/commitdiff_plain/bdfe02afe03428e59b3c85b6cae19d579d82f55c integrate distinction_word, for deployment --- diff --git a/draw.py b/draw.py new file mode 100644 index 0000000..227fd34 --- /dev/null +++ b/draw.py @@ -0,0 +1,60 @@ +# import numpy as np +# import matplotlib.pyplot as plt + +# from topng import affine + + +from numpy import exp,arange +from pylab import meshgrid,cm,imshow,contour,clabel,colorbar,axis,title,show + +# the function that I'm going to plot +def z_func(x,y): + return (1-(x**2+y**3))*exp(-(x**2+y**2)/2) + +x = arange(-3.0,3.0,0.1) +y = arange(-3.0,3.0,0.1) +X,Y = meshgrid(x, y) # grid of point +Z = z_func(X, Y) # evaluation of the function on the grid + +im = imshow(Z,cmap=cm.RdBu) # drawing the function +# adding the Contour lines with labels +cset = contour(Z,arange(-1,1.5,0.2),linewidths=2,cmap=cm.Set2) +clabel(cset,inline=True,fmt='%1.1f',fontsize=10) +colorbar(im) # adding the colobar on the right +# latex fashion title +title('$z=(1-x^2+y^3) e^{-(x^2+y^2)/2}$') +show() + + +# dep = ( 0, pow(2, 8) ) # 9 bits +# arr = ( 0, pow(2, 16) ) # 16 bits + +# deprange = np.arange(0, pow(2, 8), 1) # 9 bits + + +# # test << +# # plt.plot(dep, arr, 'r--', deprange, deprange<<8, 'bs') +# # plt.show() + +# # print("decalage") +# # for i in deprange: +# # print( 'i, i<<8:', (i, i<<8) ) +# # test >> + +# # test << +# print("affine transfo") +# count = 0 +# for i in deprange: +# ab = dep +# cd = arr + +# a, b = ab[0], ab[1] +# c, d = cd[0], cd[1] + +# r = max( 0, ( (i-a) * (d-c) / (b-a) + c ) ) +# r2 = i<<8 +# print( 'i, r:', (i, r) ) +# print( 'i, i<<8:', (i, r2) ) +# count += (r != r2) + +# print('count', count) \ No newline at end of file diff --git a/helpers.py b/helpers.py index 9784900..808a4a5 100644 --- a/helpers.py +++ b/helpers.py @@ -1,2 +1,106 @@ +from timeit import timeit +import numpy as np + + +INPUT_DIR = '../../Data/Images_anonymous/Case_0002/' +OUT_DIR = './generated/' + + +np.set_printoptions(edgeitems=272, linewidth=500)# hey numpy, take advantage of my large screen + +def check(p1, p2, Mat): + """ + Not by @res + Uses the line defined by p1 and p2 to check array of + input indices against interpolated value + + Returns boolean array, with True inside and False outside of shape + """ + idxs = np.indices(Mat.shape) # Create 3D array of indices + + try: + p1 = p1.astype(float) + p2 = p2.astype(float) + + # Calculate max column idx for each row idx based on interpolated line between two points + max_col_idx = (idxs[0] - p1[0]) / (p2[0] - p1[0]) * (p2[1] - p1[1]) + p1[1] + sign = np.sign(p2[0] - p1[0]) + return idxs[1] * sign <= max_col_idx * sign + except RuntimeWarning as e: + print("p1, p2") + print(p1, p2) + return True + +def drawcontours(Mat, vertices): + """ + Not by @res + + Mat.shape : (20,20) or something like.. + vertices : np.array([ + [5,12], + [8,18], + [13,14], + [11,6], + [4,6], + ]) + + return Mat : the resulting matrix + + Creates np.array with dimensions defined by shape + Fills polygon defined by vertices with ones, all other values zero""" + + fill = np.ones(Mat.shape) # Initialize boolean array defining shape fill + + # Create check array for each edge segment, combine into fill array + for k in range(vertices.shape[0]): # .shape[0] is the number of vertices, like len(vertices) + fill = np.all([fill, check(vertices[k-1], vertices[k], Mat)], axis=0) + + # Set all values outside polygon to zero + # print("fill") + # print(fill) + Mat[np.invert(fill)] = 0 + + return Mat + def getdir(filepath): - return '/'.join(filepath.split('/')[:-1]) + '/' + return '/'.join(filepath.split('/')[:-1]) + '/' + + +if __name__ == '__main__': + # vertices = np.array(list(reversed([ + # (5,12), + # (8,18), + # (13,14), + # (11,6), + # ]) )) + + vertices = np.array([ + [ 97, 129], + [103, 134], + [108, 139], + [109, 146], + [109, 155], + [105, 161], + [ 99, 165], + [ 93, 166], + [ 83, 164], + [ 78, 161], + [ 73, 153], + [ 72, 147], + [ 72, 140], + [ 75, 133], + [ 79, 129], + [ 85, 127], + [ 93, 127], + ]) + + from topng import topng + Mat = topng(INPUT_DIR+'Image00003', OUT_DIR + INPUT_DIR.split('/')[-2] +'-Image00003', epimask="/Users/user/Desktop/Master/Stage/Data/json/json_GT/0_Case_0002/contours/1.2.3.4.5.6/31/-85.9968/Epicardic.json") + # print(Mat) + # Mat = np.ones((20, 25)).astype(np.int32) + # Mat[:,:] = 14 + + # print( timeit(lambda:create_polygon([20,20], vertices), number=100000) ) + polygon_array = drawcontours(Mat, vertices) + print(polygon_array.shape) + # print(polygon_array.astype(np.int32)) diff --git a/regularjson.py b/regularjson.py index ba7f97e..87addeb 100644 --- a/regularjson.py +++ b/regularjson.py @@ -21,9 +21,9 @@ from pprint import pprint # |--> json_GT_part2 RT_PATH = '../../Data/json/' JSON_GTS = ['json_GT', 'json_GT_part2'] -INFA_STR = 'Infa' -EPI_STR = 'Epi' -ENDO_STR = 'Endo' +INFA_STR = 'Infarction' +EPI_STR = 'Epicardic' +ENDO_STR = 'Endocardic' # Globals featurerefs = [] diff --git a/reversesample.py b/reversesample.py new file mode 100644 index 0000000..5b3bb2b --- /dev/null +++ b/reversesample.py @@ -0,0 +1,20 @@ +from os import listdir as ls +from os.path import join, splitext +from shutil import move as mv, copyfile as cp +import pathlib + +def move(indir, outdir, n, distinction_word='', copy=True):# move n ordered files from indir to outdir + l = sorted(ls(indir)) + for filename in l[:n]: + # print(join(indir, filename), join(outdir, filename)) + pathlib.Path(outdir).mkdir(parents=True, exist_ok=True) + fname, fextension = splitext(filename) + action = cp if copy else mv + action(join(indir, filename), join(outdir, fname + distinction_word + fextension)) + +if __name__ == '__main__': + + move('./sample-crop-mask/train/infarctus', './generated/90/infarctus/crop-mask', 400) # move 400 ordered files from param 1 to param 2 + move('./sample-crop-mask/train/noinfarctus', './generated/90/noinfarctus/crop-mask', 400) + move('./sample-crop-mask/valid/infarctus', './generated/90/infarctus/crop-mask', 100) + move('./sample-crop-mask/valid/noinfarctus', './generated/90/noinfarctus/crop-mask', 100) \ No newline at end of file diff --git a/test.py b/test.py new file mode 100644 index 0000000..dae3446 --- /dev/null +++ b/test.py @@ -0,0 +1,89 @@ +from timeit import timeit +import numpy as np + + +np.set_printoptions(linewidth=500)# hey numpy, take advantage of my large screen + +def check(p1, p2, base_array): + """ + Not by @res + Uses the line defined by p1 and p2 to check array of + input indices against interpolated value + + Returns boolean array, with True inside and False outside of shape + """ + idxs = np.indices(base_array.shape) # Create 3D array of indices + + p1 = p1.astype(float) + p2 = p2.astype(float) + + # Calculate max column idx for each row idx based on interpolated line between two points + max_col_idx = (idxs[0] - p1[0]) / (p2[0] - p1[0]) * (p2[1] - p1[1]) + p1[1] + sign = np.sign(p2[0] - p1[0]) + return idxs[1] * sign <= max_col_idx * sign + +def create_polygon(shape, vertices): + """ + Not by @res + + shape : (20,20) + vertices : np.array([ + (5,12), + (8,18), + (13,14), + (11,6), + (4,6), + ]) + + return base_array : the resulting matrix + + Creates np.array with dimensions defined by shape + Fills polygon defined by vertices with ones, all other values zero""" + base_array = np.zeros(shape, dtype=float) # Initialize your array of zeros + base_array[:,:] = 4 + + fill = np.ones(base_array.shape) # Initialize boolean array defining shape fill + # print('timeit (base_array.shape) ', timeit( lambda:np.ones(base_array.shape) )) + # print('timeit (base_array.shape) * True ', timeit( lambda:np.ones(base_array.shape) * True )) + print('base_array.shape', base_array.shape) + print('fill.dtype', fill.dtype) + print('fill - 1:', fill) + + # Create check array for each edge segment, combine into fill array + for k in range(vertices.shape[0]):# .shape[0] is the number of vertices, like len(vertices) + fill = np.all([fill, check(vertices[k-1], vertices[k], base_array)], axis=0) + + # Set all values inside polygon to one + print("fill:") + print(fill) + base_array[np.invert(fill)] = 0 + + return base_array + + +# (Row, Col) Vertices of Polygon (Defined Clockwise) +vertices = np.array([ + (5,12), + (8,18), + (13,14), + (11,6), + (4,6), +]) + +# print( timeit(lambda:create_polygon([20,20], vertices), number=100000) ) +polygon_array = create_polygon((14,19), vertices) +print("1)") +print(polygon_array.astype(np.int32)) + +# This section prints numbers at each vertex for visual check, just comment out +# to print an array of only zeros and ones +# for n, vertex in enumerate(vertices): +# polygon_array[vertex[0],vertex[1]] = 10*(n+1) + +# Simple routine to print the final array +# for row in polygon_array.tolist(): +# for c in row: +# print( '{:4.1f}'.format(c) ) +# print() +# print("2)") +# print(polygon_array.astype(np.int32)) \ No newline at end of file diff --git a/topng.py b/topng.py index 8722d98..fde569b 100644 --- a/topng.py +++ b/topng.py @@ -2,36 +2,52 @@ import cv2 import os from os.path import isdir, join from os import mkdir +from timeit import timeit import pydicom from pprint import pprint import numpy as np import pathlib import json +from scipy import ndimage +from scipy import misc + + from decimal import Decimal as d, ROUND_HALF_UP as rhu +# locals +from helpers import drawcontours + +np.set_printoptions(edgeitems=372, linewidth=1200)# hey numpy, take advantage of my large screen + PNG16_MAX = pow(2, 16) - 1 # here if thinks the heaviest weight bit is for transparency or something not in use with dicom imgs PNG8_MAX = pow(2, 8+1) - 1 # heaviest weight bit is 8 => 2**8, but dont forget the others: the reason of +1 INPUT_DIR = '../../Data/Images_anonymous/Case_0002/' OUT_DIR = './generated/' -#os.mkdir(outdir) + +CROP_SIZE = (45, 45) # (width, height) +RED_COLOR = 100 def roundall(*l): - return (round(e) for e in l) + return (int(round(e)) for e in l) def ftrim(Mat): + # ---------- FTRIM ---------- # private func to trim the Matrix, but in one direction, vertically | horizontally # return the slice, don't affect the Matrix - # y | : for column, x -> : for rows + # y | : for (top to bottom), x -> : for (left to right) # v # not my fault, numpy architecture + y1 = y2 = i = 0 + while i < len(Mat):# search by top if Mat[i].max() > 0: y1 = i break i += 1 + i = len(Mat) - 1 while i >= 0:# search by bottom if Mat[i].max() > 0: @@ -48,29 +64,8 @@ def trim(Mat): # print('horizontal:vertical', horizontal, vertical) return Mat[horizontal, vertical] -def mask(Mat, maskfile): - # return - xmin, ymin, xmax, ymax = minmax(Mat, maskfile) - - y1 = y2 = i = 0 - while i < len(Mat):# search by top - if i < ymin: - Mat[i].fill(0)# paint the row in black - else: break - i += 1 - - i = len(Mat) - 1 - while i >= 0:# search by bottom - if i > ymax: - Mat[i].fill(0)# paint the row in black - else: break - i -= 1 - # print('y1, y2', y1, y2) - # return slice(y1, y2+1)# +1 to stop at y2 - - -def minmax(Mat, file): +def getxy(file): """ { 'Image00001': [{ @@ -93,35 +88,170 @@ def minmax(Mat, file): ] }] } - return xmin, ymin, xmax, ymax + return [(94.377, 137.39), ...] """ with open(file) as jsonfile: data = json.load(jsonfile) - pprint(data) - - for imgXXX in data:pass # get the value of key ~= "Image00001", cause it's dynamic - - for obj in data[imgXXX]:pass # get the object that contains the points, cause it's a list - points = obj['points'] + # pprint(data) + + for imgXXX in data: pass # get the value of key ~= "Image00001", cause it's dynamic + for obj in data[imgXXX]: pass # get the object that contains the points, cause it's a list + points = obj['points'] # print("print, ", data) # print("imgXXX, ", imgXXX) # print("points, ", points) # print("imgXXX, ", obj['points']) - tmp = [(pt['x'], pt['y']) for pt in points ] # extract x,y. {'x': 94.377, 'y': 137.39} => (94.377, 137.39) - r = np.array(tmp) - - print(r) # log - + tmp = [np.array( (round(pt['x']), round(pt['y'])) ).astype(np.int32) for pt in + points] # extract x,y. {'x': 94.377, 'y': 137.39} => (94.377, 137.39) + return np.array(tmp, dtype=np.int32) + # return tmp + +def minmax(file): + r = getxy(file) + if r is not None: + # print(r) # log xmin, ymin = np.min(r, axis=0) xmax, ymax = np.max(r, axis=0) - print('xmax, ymax', xmax, ymax) - print('xmin, ymin', xmin, ymin) + # print('xmax, ymax', xmax, ymax) + # print('xmin, ymin', xmin, ymin) return roundall(xmin, ymin, xmax, ymax) +def crop(Mat, maskfile, size=None): + """ + size : if filled with a (45, 45), it will search the center of maskfile then crop by center Mat + """ + xmin, ymin, xmax, ymax = minmax(maskfile) + if size: + xcenter = (xmin + xmax) / 2 + ycenter = (ymin + ymax) / 2 + + # crop coords + ymin, xmin, ymax, xmax = roundall(xcenter - size[0], ycenter - size[0], + xcenter + size[1], ycenter + size[1]) + + return Mat[xmin:xmax, ymin:ymax] + +def contour(Mat, maskfiles, color, thickness=1): + # ---------- CONTOUR POLYGON ---------- + # thickness = -1 => fill it + # = 1 => just draw the contour with color + # + # return new Mat + contours = [getxy(maskfile) for maskfile in maskfiles] # list of list of coords, + # [ + # [ (3,43), (3,4) ], + # [ (33,43) ] + # ] + # print("log: contours", contours) + if contours is not None: + # print('type contours', type(contours)) + # print('contours', contours) + msk = np.zeros(Mat.shape, dtype=np.int32) # init all the mask with True... + cv2.drawContours(msk, contours, -1, True, thickness) # affect Mat, fill the polygone with False + msk = msk.astype(np.bool) + # print('msk') + # print(msk) + # print("bool", timeit(lambda:msk, number=1000)) + # print("normal", timeit(lambda:msk.astype(np.bool), number=1000)) + # Mat = cv2.cvtColor(Mat, cv2.COLOR_RGB2GRAY) # apply gray + + # Mat = drawcontours(Mat, contours) + # pass + Mat[msk] = color # each True in msk means 0 in Mat. msk is like a selector + return Mat + +def mask(Mat, maskfile, color=0, thickness=-1): + # ---------- MASK POLYGON ---------- + # thickness = -1 => fill it + # = 1 => just draw the contour with color + # + # return new Mat + contours = getxy(maskfile) + # print("log: contours", contours) + if contours is not None: + # print('type contours', type(contours)) + # print('contours', contours) + msk = np.ones(Mat.shape, dtype=np.int32) # init all the mask with True... + cv2.drawContours(msk, [contours], -1, False, thickness) # affect msk, fill the polygone with False, => further, don't touch where is False + msk = msk.astype(np.bool) + # print('msk') + # print(msk) + # print("bool", timeit(lambda:msk, number=1000)) + # print("normal", timeit(lambda:msk.astype(np.bool), number=1000)) + # Mat = cv2.cvtColor(Mat, cv2.COLOR_RGB2GRAY) # apply gray + + # Mat = drawcontours(Mat, contours) + # pass + Mat[msk] = color # each True in msk means 0 in Mat. msk is like a selector + return Mat + + +def hollowmask(Mat, epifile, endofile, color=0, thickness=-1): + # ---------- MASK POLYGON ---------- + # thickness = -1 => fill it + # = 1 => just draw the contour with color + # + # return new Mat + epicontours = getxy(epifile) + endocontours = getxy(endofile) + if epicontours is not None and endocontours is not None: + msk = np.ones(Mat.shape, dtype=np.int32) # init all the mask with True... + cv2.drawContours(msk, [epicontours], -1, False, thickness) # affect msk, fill the polygone with False, => further, don't touch where is False + cv2.drawContours(msk, [endocontours], -1, True, thickness) # fill the intern polygone with True, (the holow in the larger polygon), => further, color where is True with black for example + msk = msk.astype(np.bool) + + Mat[msk] = color # each True in msk means 0 in Mat. msk is like a selector + return Mat + + +def sqrmask1(Mat, maskfile): + # ---------- SQUARE MASK 1st approach ---------- + # print( timeit( lambda:sqrmask1(img, epimask), number=1000 ) ) # 0.48110522600000005 + # return new Mat + xmin, ymin, xmax, ymax = minmax(maskfile) + # print("xmin, ymin, xmax, ymax", xmin, ymin, xmax, ymax) + + i = 0 + while i < ymin:# search by top + Mat[i].fill(0)# paint the row in black + i += 1 + + i = len(Mat) - 1 + while i > ymax:# search by bottom + Mat[i].fill(0)# paint the row in black + i -= 1 + + i = 0 + while i < xmin:# search by top + Mat.T[i, ymin:ymax+1].fill(0) # paint the column (row of the Transpose) in black, ymin and ymax to optimize, cause, I previously painted a part + i += 1 + + i = len(Mat.T) - 1 + while i > xmax:# search by bottom + Mat.T[i, ymin:ymax+1].fill(0) # paint the column (row of the Transpose) in black, ymin and ymax to optimize, cause, I previously painted a part + i -= 1 + + return Mat + +def sqrmask2(Mat, maskfile): + # ---------- SQUARE MASK 2nd and best approach ---------- + # print( timeit( lambda:sqrmask2(img, epimask), number=1000 ) ) # 0.3097705270000001 + # return new Mat + xmin, ymin, xmax, ymax = minmax(maskfile) + # print("xmin, ymin, xmax, ymax", xmin, ymin, xmax, ymax) + + msk = np.ones(Mat.shape, dtype=np.int32) # init all the mask with True... + msk = msk.astype(np.bool) + + msk[ymin:ymax, xmin:xmax] = False # for after, don't touch between min and max region + Mat[msk] = 0 + + return Mat + def map16(array):# can be useful in future return array * 16 @@ -145,17 +275,31 @@ def affine(Mat, ab, cd): def getdir(filepath): return '/'.join(filepath.split('/')[:-1]) + '/' -def topng(inputfile, outfile=None, overwrite=True, verbose=False): +def readpng(inputfile):# just a specific func to preview a "shape = (X,Y,3)" image + image = misc.imread(inputfile) + + print("image") + print("image.shape", image.shape) + + for tab in image: + for i, row in enumerate(tab): + print(row[0]*65536 + row[0]*256 + row[0], end=" " if i % image.shape[0] != 0 else "\n") + +def topng(inputfile, outfile=None, overwrite=True, verbose=False, epimask='', endomask='', centercrop=None, blackmask=False, square=False, redcontour=False): """ (verbose) return (64, 64) : the width and height (not verbose) return (img, dicimg) : the image and the dicimg objects + centercrop : it's a size (45, 45), to mention I want to crop by center of epimask and by size. + blackmask : draw the outside with black + """ try: dicimg = pydicom.read_file(inputfile) # read dicom image except pydicom.errors.InvalidDicomError as e: # @TODO: log, i can't read this file return - img = trim(dicimg.pixel_array)# get image array (12bits) + # img = trim(dicimg.pixel_array)# get image array (12bits), Don't trim FOR THE MOMENT + img = dicimg.pixel_array# get image array (12bits) # test << # return img.shape # $$ COMMENT OR REMOVE THIS LINE @@ -170,14 +314,52 @@ def topng(inputfile, outfile=None, overwrite=True, verbose=False): # affine transfo to png 16 bits, func affects img variable maxdepth = pow(2, dicimg.BitsStored) - 1 - print('dicimg.BitsStored, (img.min(), img.max())', dicimg.BitsStored, (img.min(), img.max())) # testing.. + # print('dicimg.BitsStored, (img.min(), img.max())', dicimg.BitsStored, (img.min(), img.max())) # testing.. + if int(dicimg.BitsStored) < 12: + print("\n\n\n-----{} Bits-----\n\n\n\n".format(dicimg.BitsStored)) affine(img, (0, maxdepth), # img.min() replace 0 may be, but not sure it would be good choice (0, PNG16_MAX if maxdepth > PNG8_MAX else PNG8_MAX) ) - mask(img, '/Users/user/Desktop/Master/Stage/Data/json/json_GT/0_Case_0002/contours/1.2.3.4.5.6/31/-85.9968/Epicardic.json') + # test << + # imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) + # ret,thresh = cv2.threshold(img,127,255,0) + # im2, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) + # print("im2, contours, hierarchy", im2, contours, hierarchy) + # test >> + + # return img + + # print("log: epimask", epimask) + + if epimask: + if redcontour: + + contours = [epimask] # list of list of coords + if endomask:contours.append(endomask) + img = contour(img, contours, color=RED_COLOR, thickness=1) + + if blackmask:# if is there a mask => apply + if square: + img = sqrmask2(img, epimask) + else: + if endomask: + img = hollowmask(img, epimask, endomask) + else: + img = mask(img, epimask) + + if centercrop: + img = crop(img, epimask, centercrop) + + + # return + # test + # if verbose: + # return img, dicimg, minmax(epimask) + # else: + # return img.shape savepath = (outfile or inputfile) + '.png' savedir = getdir(savepath) @@ -194,11 +376,17 @@ def topng(inputfile, outfile=None, overwrite=True, verbose=False): # np.savetxt(savepath + '.npy', img) # test >> - cv2.imwrite(savepath, img, [cv2.IMWRITE_PNG_COMPRESSION, 0]) # write png image + if np.count_nonzero(img) > 0: # matrix not full of zero + cv2.imwrite(savepath, img, [cv2.IMWRITE_PNG_COMPRESSION, 0]) # write png image + + # print("ndimage.imread(savepath)", ndimage.imread(savepath).shape) + # print( ndimage.imread(savepath) ) + # print("np.expand_dims(ndimage.imread(savepath), 0)", np.expand_dims(ndimage.imread(savepath), 0).shape) + # print(np.expand_dims(ndimage.imread(savepath), 0)) # test if verbose: - return img, dicimg + return img, dicimg, minmax(epimask) else: return img.shape @@ -213,4 +401,5 @@ def topngs(inputdir, outdir): if __name__ == '__main__': # topngs( INPUT_DIR, join(OUT_DIR, INPUT_DIR.split('/')[-2]) ) - topng(INPUT_DIR+'Image00003', OUT_DIR + INPUT_DIR.split('/')[-2] +'-Image00003') + readpng(OUT_DIR+'aug_circle.png') + # topng(INPUT_DIR+'Image00003', OUT_DIR + INPUT_DIR.split('/')[-2] +'-Image00003', epimask="/Users/user/Desktop/Master/Stage/Data/json/json_GT/0_Case_0002/contours/1.2.3.4.5.6/31/-85.9968/Epicardic.json") diff --git a/tosampledir.py b/tosampledir.py index 87effac..1846c1d 100644 --- a/tosampledir.py +++ b/tosampledir.py @@ -1,18 +1,20 @@ from os import listdir as ls -from os.path import join -from shutil import move as mv +from os.path import join, splitext +from shutil import move as mv, copyfile as cp import pathlib -def move(indir, outdir, n):# move n ordered files from indir to outdir +def move(indir, outdir, n, distinction_word='', copy=True):# move n ordered files from indir to outdir l = sorted(ls(indir)) for filename in l[:n]: # print(join(indir, filename), join(outdir, filename)) pathlib.Path(outdir).mkdir(parents=True, exist_ok=True) - mv(join(indir, filename), join(outdir, filename)) + fname, fextension = splitext(filename) + action = cp if copy else mv + action(join(indir, filename), join(outdir, fname + distinction_word + fextension)) # distinction_word='-mask'; /path/file.jpg => /path/file-mask.jpg if __name__ == '__main__': - move('./train/infarctus', './sample/train/infarctus', 1000) # move 1000 ordered files from param 1 to param 2 - move('./train/noinfarctus', './sample/train/noinfarctus', 1000) - move('./train/infarctus', './sample/valid/infarctus', 300) - move('./train/noinfarctus', './sample/valid/noinfarctus', 300) \ No newline at end of file + move('./generated/90/infarctus/crop-nomask', './sample/train/infarctus', 400, distinction_word="-crop-nomask") # move 400 ordered files from param 1 to param 2 + move('./generated/90/noinfarctus/crop-nomask', './sample/train/noinfarctus', 400, distinction_word="-crop-nomask") + move('./generated/90/infarctus/crop-nomask', './sample/valid/infarctus', 100, distinction_word="-crop-nomask") + move('./generated/90/noinfarctus/crop-nomask', './sample/valid/noinfarctus', 100, distinction_word="-crop-nomask") \ No newline at end of file diff --git a/totraindir.py b/totraindir.py index 1fbaf08..b901b85 100644 --- a/totraindir.py +++ b/totraindir.py @@ -4,12 +4,12 @@ import pydicom from os.path import join # locals -from topng import topng, mask -from regularjson import search, RT_PATH, JSON_GTS, INFA_STR, EPI_STR +from topng import topng, mask, CROP_SIZE +from regularjson import search, RT_PATH, JSON_GTS, INFA_STR, EPI_STR, ENDO_STR # constants GLOB_DIR = '../../Data/Images_anonymous/' -OUT_DIR = './generated/train/' +OUT_DIR = './generated/90/' INDICE_CASE = 'Case' START = None # to manage the number of Patient Case to use in training + validation, if START == None => 0, if END == None => last index, it will use all in GLOB_DIR @@ -65,27 +65,95 @@ if __name__ == '__main__': for i, dic in enumerate(l1): # print('join', r, l2[i]) - ref = join(r, l2[i]) # logically, should be the json ref of i dicom image + ref = join(r, l2[i]) # logically, should be the json ref's "parent directory" of i dicom image infarctus = search(ref, INFA_STR) - # epimask = mask(ref, EPI_STR) + epimask = search(ref, EPI_STR) + endomask = search(ref, ENDO_STR) + # print("ref left:", l1[i]) # Testing.. + # print("ref right:", ref) # Testing.. # print("infarctus:", infarctus) # Testing.. # topng(join(caspath, dic), '%/%-%' % (join(OUT_DIR, 'infarctus'), cas, dic) - w, h = topng(join(caspath, dic), '{}/{}-{}'.format(join(OUT_DIR, 'infarctus' if infarctus else 'noinfarctus'), cas, dic)) - - # search maximums - if wmax < w: wmax = w - if hmax < h: hmax = h - - # search width minimum - if wmin is None: wmin = w - elif wmin > w: wmin = w - - # search height minimum - if hmin is None: hmin = h - elif hmin > h: hmin = h - - print('min-width, max-width:', (wmin, wmax)) - print('min-height, max-height:', (hmin, hmax)) - - print('Ended!') + # print('epimask', epimask) + + if epimask:# this condition could be if necessary + # w, h = topng(join(caspath, dic), '{}/{}-{}'.format(join(OUT_DIR, 'infarctus' if infarctus else 'noinfarctus'), cas, dic), epimask=epimask['path'] if epimask else None) + # img_, dicimg_, minmax_ = topng(join(caspath, dic), + # '{}/{}-{}'.format(join(OUT_DIR, 'infarctus' if infarctus else 'noinfarctus'), cas, dic), + # epimask=epimask['path'] if epimask else None, + # verbose=True, + # ) + + # Possibly data augmentation purpose here + w, h = topng( + join(caspath, dic), + outfile='{}/crop-mask/{}-{}'.format(join(OUT_DIR, + 'infarctus' if infarctus else 'noinfarctus'), + cas, + dic, + ), + epimask=epimask['path'] if epimask else None, + centercrop=CROP_SIZE, + blackmask=True, + ) # crop and mask with black + + if endomask: + w, h = topng( + join(caspath, dic), + outfile='{}/crop-mask-hollow/{}-{}'.format(join(OUT_DIR, + 'infarctus' if infarctus else 'noinfarctus'), + cas, + dic, + ), + epimask=epimask['path'] if epimask else None, + endomask=endomask['path'] if endomask else None, + centercrop=CROP_SIZE, + blackmask=True, + ) # crop and (mask and fill hollow) with black + + w, h = topng( + join(caspath, dic), + outfile='{}/crop-nomask/{}-{}'.format(join(OUT_DIR, + 'infarctus' if infarctus else 'noinfarctus'), + cas, + dic, + ), + epimask=epimask['path'] if epimask else None, + centercrop=CROP_SIZE, + ) # just crop, don't apply black mask + + # w, h = topng( + # join(caspath, dic), + # outfile='{}/contour/{}-{}'.format(join(OUT_DIR, + # 'infarctus' if infarctus else 'noinfarctus'), + # cas, + # dic, + # ), + # epimask=epimask['path'] if epimask else None, + # redcontour=True, + # ) # draw a red contour for visibily purpose + + # segmentation width & height << + # xmin, ymin, xmax, ymax = minmax_ + # w = xmax - xmin + 1 # +1 : even the position takes a bit + # h = ymax - ymin + 1 + # segmentation width & height >> + + + # # search maximums + # if wmax < w: wmax = w + # if hmax < h: hmax = h + + # # search width minimum + # if wmin is None: wmin = w + # elif wmin > w: wmin = w + + # # search height minimum + # if hmin is None: hmin = h + # elif hmin > h: hmin = h + + + # print('min-width, max-width:', (wmin, wmax)) + # print('min-height, max-height:', (hmin, hmax)) + + # print('Ended!')