]> AND Private Git Repository - myo-class.git/blob - topng.py
Logo AND Algorithmique Numérique Distribuée

Private GIT Repository
8722d98c785f756ab87452b1574fb0d97966fa3c
[myo-class.git] / topng.py
1 import cv2
2 import os
3 from os.path import isdir, join
4 from os import mkdir
5 import pydicom
6 from pprint import pprint
7 import numpy as np
8 import pathlib
9 import json
10
11 from decimal import Decimal as d, ROUND_HALF_UP as rhu
12
13 PNG16_MAX = pow(2, 16) - 1 # here if thinks the heaviest weight bit is for transparency or something not in use with dicom imgs
14 PNG8_MAX = pow(2, 8+1) - 1 # heaviest weight bit is 8 => 2**8, but dont forget the others: the reason of +1
15
16 INPUT_DIR = '../../Data/Images_anonymous/Case_0002/'
17 OUT_DIR = './generated/'
18 #os.mkdir(outdir)
19
20 def roundall(*l):
21         return (round(e) for e in l)
22
23 def ftrim(Mat):
24         # private func to trim the Matrix, but in one direction, vertically | horizontally
25         # return the slice, don't affect the Matrix
26         # y | : for column, x -> : for rows
27         #   v
28         # not my fault, numpy architecture
29         y1 = y2 = i = 0
30         while i < len(Mat):# search by top
31                 if Mat[i].max() > 0:
32                         y1 = i
33                         break
34                 i += 1
35         i = len(Mat) - 1
36         while i >= 0:# search by bottom
37                 if Mat[i].max() > 0:
38                         y2 = i
39                         break
40                 i -= 1
41         # print('y1, y2', y1, y2)
42         return slice(y1, y2+1)# +1 to stop at y2
43
44 def trim(Mat):
45         # most use who make implicit call of ftrim twice
46         horizontal = ftrim(Mat)
47         vertical = ftrim(Mat.T)
48         # print('horizontal:vertical', horizontal, vertical)
49         return Mat[horizontal, vertical]
50
51 def mask(Mat, maskfile):
52         # return
53         xmin, ymin, xmax, ymax = minmax(Mat, maskfile)
54
55         y1 = y2 = i = 0
56         while i < len(Mat):# search by top
57                 if i < ymin: 
58                         Mat[i].fill(0)# paint the row in black
59                 else: break
60                 i += 1
61         
62         i = len(Mat) - 1
63         while i >= 0:# search by bottom
64                 if i > ymax:
65                         Mat[i].fill(0)# paint the row in black
66                 else: break
67                 i -= 1
68         # print('y1, y2', y1, y2)
69         # return slice(y1, y2+1)# +1 to stop at y2
70
71
72
73 def minmax(Mat, file):
74         """
75                 {
76                         'Image00001': [{
77                                 'color': '#ff0000',
78                                 'points': [
79                                         {'x': 94.377, 'y': 137.39},
80                                         {'x': 100.38, 'y': 139.55},
81                                         {'x': 103.26, 'y': 142.67},
82                                         {'x': 105.91, 'y': 147.95},
83                                         {'x': 105.42, 'y': 152.76},
84                                         {'x': 100.62, 'y': 156.84},
85                                         {'x': 95.338, 'y': 159.96},
86                                         {'x': 89.573, 'y': 158.52},
87                                         {'x': 84.53, 'y': 153},
88                                         {'x': 82.848, 'y': 149.15},
89                                         {'x': 82.368, 'y': 142.91},
90                                         {'x': 85.01, 'y': 138.11},
91                                         {'x': 89.813, 'y': 137.39},
92                                         {'x': 94.377, 'y': 137.39}
93                                 ]
94                         }]
95                 }
96                 return xmin, ymin, xmax, ymax
97         """
98         with open(file) as jsonfile:
99                 data = json.load(jsonfile)
100                 pprint(data)
101                 
102                 for imgXXX in data:pass # get the value of key ~= "Image00001", cause it's dynamic
103                 
104                 for obj in data[imgXXX]:pass # get the object that contains the points, cause it's a list
105                 points = obj['points']
106
107
108                 # print("print, ", data)
109                 # print("imgXXX, ", imgXXX)
110                 # print("points, ", points)
111                 # print("imgXXX, ", obj['points'])
112                 tmp = [(pt['x'], pt['y']) for pt in points ] # extract x,y. {'x': 94.377, 'y': 137.39} => (94.377, 137.39)
113                 r = np.array(tmp)
114
115                 print(r) # log
116
117                 xmin, ymin = np.min(r, axis=0)
118                 xmax, ymax = np.max(r, axis=0)
119
120                 print('xmax, ymax', xmax, ymax)
121                 print('xmin, ymin', xmin, ymin)
122
123                 return roundall(xmin, ymin, xmax, ymax)
124
125 def map16(array):# can be useful in future
126         return array * 16
127
128 # def dround(n):
129 #       return d(str(n)).quantize(d('1'), rounding=rhu)# safe round without
130
131 def affine(Mat, ab, cd):
132         """
133                 Affine transformation
134                 ab: the 'from' interval (2, 384) or {begin:2, end:384} begin is 0, and end is 1
135                 cd: the 'to' interval (0, 1024) {begin:0, end:1024}
136         """
137         a, b = ab[0], ab[1]
138         c, d = cd[0], cd[1]
139         
140         with np.nditer(Mat, op_flags=['readwrite']) as M:
141                 for x in M:
142                         x[...] = max( 0, round( (x-a) * (d-c) / (b-a) + c ) ) # could not be negative
143
144
145 def getdir(filepath):
146         return '/'.join(filepath.split('/')[:-1]) + '/'
147
148 def topng(inputfile, outfile=None, overwrite=True, verbose=False):
149         """
150                 (verbose) return (64, 64) : the width and height
151                 (not verbose) return (img, dicimg) : the image and the dicimg objects
152         """
153         try:
154                 dicimg = pydicom.read_file(inputfile) # read dicom image
155         except pydicom.errors.InvalidDicomError as e:
156                 # @TODO: log, i can't read this file
157                 return
158         img = trim(dicimg.pixel_array)# get image array (12bits)
159
160         # test <<
161         # return img.shape # $$ COMMENT OR REMOVE THIS LINE 
162         # print('img', img)
163         # print('img', type(img))
164         # print('min', img.min(), 'max', img.max())
165         # dicimg.convert_pixel_data() # same as using dicimg.pixel_array
166         # pixa = dicimg._pixel_array
167         # print('dicimg._pixel_array', pixa)
168         # print('dicimg.pixel_array==pixa', dicimg.pixel_array==pixa)
169         # test >>
170
171         # affine transfo to png 16 bits, func affects img variable
172         maxdepth = pow(2, dicimg.BitsStored) - 1
173         print('dicimg.BitsStored, (img.min(), img.max())', dicimg.BitsStored, (img.min(), img.max())) # testing..
174         affine(img, 
175                 (0, maxdepth), # img.min() replace 0 may be, but not sure it would be good choice
176                 (0, PNG16_MAX if maxdepth > PNG8_MAX else PNG8_MAX)
177         )
178         
179         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')
180
181
182         savepath = (outfile or inputfile) + '.png'
183         savedir = getdir(savepath)
184         if overwrite and not isdir( savedir ):
185                 pathlib.Path(savedir).mkdir(parents=True, exist_ok=True)
186
187
188         # test <<
189         # tmp = np.array(img) # to get eye on the numpy format of img
190         # tmp = np.array(img) # to get eye on the numpy format of img
191         # print("img[0,0]", img[0,0])
192         # img[0,0] = 0
193         # tmp.dtype = 'uint32'
194         # np.savetxt(savepath + '.npy', img)
195         # test >>
196
197         cv2.imwrite(savepath, img, [cv2.IMWRITE_PNG_COMPRESSION, 0]) # write png image
198
199         # test
200         if verbose:
201                 return img, dicimg
202         else:
203                 return img.shape
204
205 def topngs(inputdir, outdir):
206         """
207                 inputdir : directory which contains directly dicom files
208         """
209         files = [f for f in os.listdir(inputdir)]
210
211         for f in files:
212                 topng( inputdir + f, join(outdir, f) )
213
214 if __name__ == '__main__':
215         # topngs( INPUT_DIR, join(OUT_DIR, INPUT_DIR.split('/')[-2]) )
216         topng(INPUT_DIR+'Image00003', OUT_DIR + INPUT_DIR.split('/')[-2] +'-Image00003')