insituTEM 0.1.5__py3-none-any.whl → 0.1.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- insituTEM/__ init __.py +14 -0
- insituTEM/insitu_DENS.py +318 -0
- insituTEM/insitu_DP.py +228 -8
- insituTEM/insitu_Diff.py +359 -0
- insituTEM/insitu_EMraw.py +460 -0
- insituTEM/insitu_IO.py +514 -111
- insituTEM/insitu_Preprocess.py +229 -25
- insituTEM/insitu_alignment.py +297 -11
- insitutem-0.1.7.dist-info/METADATA +20 -0
- insitutem-0.1.7.dist-info/RECORD +12 -0
- {insituTEM-0.1.5.dist-info → insitutem-0.1.7.dist-info}/WHEEL +1 -1
- insituTEM-0.1.5.dist-info/METADATA +0 -13
- insituTEM-0.1.5.dist-info/RECORD +0 -9
- {insituTEM-0.1.5.dist-info → insitutem-0.1.7.dist-info}/top_level.txt +0 -0
insituTEM/insitu_IO.py
CHANGED
|
@@ -15,30 +15,28 @@ Update 20200303:
|
|
|
15
15
|
Add stroke to scalebar and text
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
#from moviepy.editor import concatenate_videoclips,ImageClip,VideoFileClip,vfx
|
|
18
|
+
|
|
20
19
|
import cv2
|
|
21
20
|
import tifffile
|
|
22
21
|
import tqdm #not necessary just provides a progress bar and timer
|
|
23
22
|
import numpy as np
|
|
24
23
|
|
|
25
24
|
|
|
26
|
-
def tiff2mp4(path):
|
|
25
|
+
def tiff2mp4(path,fps):
|
|
27
26
|
"""
|
|
28
27
|
function to convert any input file to H264 High quality mp4 using openCV
|
|
29
28
|
Inputs: filepath
|
|
30
29
|
Output: file in the same folder named '..._fps.mp4'
|
|
31
30
|
"""
|
|
32
31
|
video = tifffile.imread(path)
|
|
33
|
-
nFrames, h,w = video.shape
|
|
34
|
-
fps = int(input('Input desired output fps:'))
|
|
32
|
+
nFrames, h,w = video.shape[:3]
|
|
35
33
|
# dur=1/fps
|
|
36
34
|
pathout =path[:-4]+'_'+str(fps)+'.mp4'
|
|
37
35
|
# pathout2 =path[:-4]+'_St.tif'
|
|
38
36
|
codec = cv2.VideoWriter_fourcc(*'H264')
|
|
39
37
|
out = cv2.VideoWriter(pathout, codec , fps, (w, h))
|
|
40
38
|
print("---------------------------------------------")
|
|
41
|
-
print('Converting Tiff stack to
|
|
39
|
+
print('Converting Tiff stack to mp4')
|
|
42
40
|
for i in tqdm.tqdm(range(nFrames)):
|
|
43
41
|
img=video[i]
|
|
44
42
|
out.write(img)
|
|
@@ -47,87 +45,133 @@ def tiff2mp4(path):
|
|
|
47
45
|
print("==============================================")
|
|
48
46
|
print("MP4 convertion Done!")
|
|
49
47
|
|
|
50
|
-
|
|
51
|
-
#
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
#
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
#
|
|
65
|
-
|
|
66
|
-
#
|
|
67
|
-
#
|
|
68
|
-
#
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
#
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
#
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
#
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
#
|
|
101
|
-
#
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
48
|
+
def tiff2avi(path,fps,is_color=False):
|
|
49
|
+
#convert tiff stack to movie
|
|
50
|
+
import tifffile
|
|
51
|
+
import cv2
|
|
52
|
+
|
|
53
|
+
# path =
|
|
54
|
+
stack = tifffile.imread(path)
|
|
55
|
+
nFrames,h,w = stack.shape[:3]
|
|
56
|
+
|
|
57
|
+
# # fps = int(input('Input desired output fps:'))
|
|
58
|
+
# # dur=1/fps
|
|
59
|
+
# pathout =path[:-4]+'_'+str(fps)+'.avi'
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# codec = cv2.VideoWriter_fourcc(*'MJPG')
|
|
63
|
+
|
|
64
|
+
# video_out = cv2.VideoWriter(pathout, codec , fps, (w, h))
|
|
65
|
+
# print("---------------------------------------------")
|
|
66
|
+
# print('Converting Tiff stack to avi')
|
|
67
|
+
# for i in tqdm.tqdm(range(nFrames)):
|
|
68
|
+
# img=stack[i]
|
|
69
|
+
# video_out.write(img)
|
|
70
|
+
|
|
71
|
+
# video_out.release()
|
|
72
|
+
# cv2.destroyAllWindows()
|
|
73
|
+
# print("==============================================")
|
|
74
|
+
# print("AVI convertion Done!")
|
|
75
|
+
size=(int(w),int(h))
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
pathout =path[:-4]+'_'+str(fps)+'.avi'
|
|
79
|
+
|
|
80
|
+
# # Check if the image stack is grayscale or color
|
|
81
|
+
is_color = len(stack.shape) == 4 and stack.shape[3] == 3
|
|
82
|
+
|
|
83
|
+
codec = cv2.VideoWriter_fourcc(*'MJPG')
|
|
84
|
+
video_out = cv2.VideoWriter(pathout, codec , fps, size,isColor=is_color)
|
|
85
|
+
print("---------------------------------------------")
|
|
86
|
+
print('Converting Tiff stack to avi')
|
|
87
|
+
for i in tqdm.tqdm(range(nFrames)):
|
|
88
|
+
img=stack[i]
|
|
89
|
+
|
|
90
|
+
# Ensure the image is in 8-bit format
|
|
91
|
+
|
|
92
|
+
if img.dtype != np.uint8:
|
|
93
|
+
img = cv2.normalize(img, None, 0, 255, cv2.NORM_MINMAX)
|
|
94
|
+
img = np.uint8(img)
|
|
95
|
+
# Convert RGB to BGR if the image is in color
|
|
96
|
+
if is_color ==True:
|
|
97
|
+
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
|
|
98
|
+
# else:
|
|
99
|
+
# img = cv2.normalize(img, None, 0, 255, cv2.NORM_MINMAX)
|
|
100
|
+
# img = np.uint8(img)
|
|
101
|
+
# Convert RGB to BGR if the image is in color
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
video_out.write(img)
|
|
105
|
+
|
|
106
|
+
video_out.release()
|
|
107
|
+
cv2.destroyAllWindows()
|
|
108
|
+
print("==============================================")
|
|
109
|
+
print("AVI convertion Done!")
|
|
110
|
+
|
|
111
|
+
def movie2tif(path,is_gray=1,exp_time=0.2):
|
|
112
|
+
"""
|
|
113
|
+
function to convert any input movie file to tif stack
|
|
114
|
+
Inputs: filepath of movie, is_gray: 1 for grayscale, 0 for rgb
|
|
115
|
+
exp_time= exposure time of real movie, remove dup frame if fps > exp_time
|
|
108
116
|
|
|
109
117
|
Output: file in the same folder named '..._cv.tif'
|
|
110
118
|
"""
|
|
111
|
-
|
|
119
|
+
import moviepy.editor as mp
|
|
120
|
+
import tifffile
|
|
112
121
|
import tqdm
|
|
113
122
|
print("==============================================")
|
|
114
123
|
print("Convert file to tif stack!")
|
|
115
124
|
pathout = path[:-4]+'_'+str(is_gray)+'.tif'
|
|
116
125
|
video = mp.VideoFileClip(path)
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
+
fps = int(video.fps)
|
|
127
|
+
w = int(video.w)
|
|
128
|
+
h = int(video.h)
|
|
129
|
+
nFrames = int(fps*video.duration)
|
|
130
|
+
dup= fps*exp_time
|
|
131
|
+
nFramesOut=int(nFrames/dup)
|
|
132
|
+
with tifffile.TiffWriter(pathout,bigtiff=True) as tif:
|
|
133
|
+
for j in tqdm.tqdm(range(nFramesOut)):
|
|
134
|
+
i=int(j*dup)
|
|
135
|
+
fr = video.get_frame(mp.cvsecs(i/fps))
|
|
136
|
+
if is_gray==1:
|
|
137
|
+
fr = cv2.cvtColor(fr, cv2.COLOR_BGR2GRAY)
|
|
138
|
+
tif.write(fr, contiguous=True)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
video.reader.close()
|
|
142
|
+
# for fr in tqdm.tqdm(video.iter_frames()):
|
|
143
|
+
# if is_gray==1:
|
|
144
|
+
# fr = cv2.cvtColor(fr, cv2.COLOR_BGR2GRAY)
|
|
145
|
+
# tif.write(fr,continuous=True)
|
|
146
|
+
|
|
126
147
|
print("==============================================")
|
|
127
148
|
print("TIF convertion Done!")
|
|
128
|
-
print("nFrames="+str(i))
|
|
129
149
|
video.reader.close()# To fix handel error problem
|
|
130
150
|
|
|
151
|
+
def folder2tif(path,isGray=True):
|
|
152
|
+
"""
|
|
153
|
+
Function to convert folder of single images into tif stack
|
|
154
|
+
Input: path: folder path
|
|
155
|
+
Output: tif stack with the same name as the folder in the parent folder.
|
|
156
|
+
"""
|
|
157
|
+
import tifffile
|
|
158
|
+
img_name=os.listdir(path)
|
|
159
|
+
nFrames= len(img_name)
|
|
160
|
+
pathout=path+'.tif'
|
|
161
|
+
if movieout == True:
|
|
162
|
+
video_out.write(img)
|
|
163
|
+
|
|
164
|
+
with tifffile.TiffWriter(pathout,bigtiff=True) as tif:
|
|
165
|
+
for i in tqdm.tqdm(range(nFrames)):
|
|
166
|
+
# img_name = f'{i:03d}.tif'
|
|
167
|
+
compare_path=os.path.join(path,f'{i:03d}.tif')
|
|
168
|
+
overlay =cv2.imread(compare_path)
|
|
169
|
+
if isGray==True:
|
|
170
|
+
overlay = cv2.cvtColor(overlay,cv2.COLOR_BGR2GRAY)
|
|
171
|
+
else:
|
|
172
|
+
overlay = cv2.cvtColor(overlay, cv2.COLOR_BGR2RGB) #tifffile usedRGB, cv2 used BGR
|
|
173
|
+
|
|
174
|
+
tif.write(overlay, contiguous=True)
|
|
131
175
|
|
|
132
176
|
def f2gif(path,fps):
|
|
133
177
|
"""
|
|
@@ -163,8 +207,8 @@ def f2gif(path,fps):
|
|
|
163
207
|
elif k == 0:
|
|
164
208
|
fps = fpsIn
|
|
165
209
|
|
|
166
|
-
|
|
167
|
-
|
|
210
|
+
video.write_gif(pathout,fps=fps)
|
|
211
|
+
video.reader.close()# To fix handel error problem
|
|
168
212
|
# if path.endswith('.gif'):
|
|
169
213
|
# clip.write_videofile(pathout,fps=fps,codec='libx264', bitrate='32 M',preset='ultrafast')
|
|
170
214
|
print("==============================================")
|
|
@@ -293,22 +337,96 @@ def ExtractFrame(path,framelist,is_gray=1):
|
|
|
293
337
|
if path.endswith('.tif')==0:
|
|
294
338
|
video.reader.close()
|
|
295
339
|
|
|
296
|
-
|
|
297
340
|
def writeCSV(pathout,data,fmt='%1.1d'):
|
|
298
341
|
# import csv
|
|
299
342
|
import numpy as np
|
|
300
343
|
# (length,width)=np.shape(data)
|
|
301
344
|
np.savetxt(pathout, data, fmt=fmt, delimiter=",")
|
|
302
|
-
|
|
303
|
-
#
|
|
304
|
-
#def Time2List()
|
|
345
|
+
|
|
305
346
|
def showFr(im):
|
|
306
347
|
from PIL import Image
|
|
307
348
|
img = Image. fromarray(im)
|
|
308
349
|
img.show()
|
|
350
|
+
|
|
351
|
+
#functions for scalebar
|
|
352
|
+
def readscale(path,dy=5):
|
|
353
|
+
"""
|
|
354
|
+
Function to measure scale from movie first frame
|
|
355
|
+
Input: path - movie path; dy: shift from the bottom in px
|
|
356
|
+
scalebarcolr- 0 for black, 255 for white
|
|
357
|
+
"""
|
|
358
|
+
import os
|
|
359
|
+
os.environ["IMAGEIO_FFMPEG_EXE"] = "/opt/homebrew/bin/ffmpeg"
|
|
360
|
+
import moviepy.editor as mp
|
|
361
|
+
import cv2
|
|
362
|
+
|
|
363
|
+
video = mp.VideoFileClip(path)
|
|
364
|
+
fr = video.get_frame(mp.cvsecs(0))
|
|
365
|
+
fr = cv2.cvtColor(fr, cv2.COLOR_BGR2GRAY)
|
|
366
|
+
|
|
367
|
+
# Select ROI using cv2.selectROI()
|
|
368
|
+
roi = cv2.selectROI('Select scalebar ROI, quit with SPACE', fr)
|
|
369
|
+
cv2.waitKey(10)
|
|
370
|
+
cv2.destroyWindow('Select scalebar ROI, quit with SPACE')
|
|
371
|
+
|
|
372
|
+
# Crop the image based on the selected ROI
|
|
373
|
+
cropped_image = fr[int(roi[1]):int(roi[1] + roi[3]), int(roi[0]):int(roi[0] + roi[2])]
|
|
374
|
+
|
|
375
|
+
# # # Display the cropped image
|
|
376
|
+
showFr(cropped_image)
|
|
377
|
+
|
|
378
|
+
import numpy as np
|
|
379
|
+
|
|
380
|
+
scalebar_color = int(input("Input the scalebar color, 0-black, 255-white: "))
|
|
381
|
+
dy2=dy
|
|
382
|
+
while dy2 != 0:
|
|
383
|
+
print(cropped_image[-dy,:])
|
|
384
|
+
dy2=int(input("input 0 if the crop is correct, otherwise input the estimated distance from bottom to the scalebar: "))
|
|
385
|
+
if dy2 !=0:
|
|
386
|
+
dy=dy2
|
|
387
|
+
|
|
388
|
+
scalebar_px = np.count_nonzero(cropped_image[-dy,:]==scalebar_color)
|
|
389
|
+
print("scalebar_px=", scalebar_px)
|
|
390
|
+
scale_nm = int(input("Input the scalebar in nm: "))
|
|
391
|
+
scale =scalebar_px/scale_nm
|
|
392
|
+
print("==============")
|
|
393
|
+
print("scale=",scale,"px/nm")
|
|
394
|
+
return scale
|
|
395
|
+
|
|
396
|
+
def getScalePix(scale,barLenPix=250):
|
|
397
|
+
"""
|
|
398
|
+
Function to convert truescale into str with correct format
|
|
399
|
+
Input:
|
|
400
|
+
barLenPix : pixel length of the scalebar region
|
|
401
|
+
scale: scale: px/nm
|
|
402
|
+
Output:
|
|
403
|
+
text: string of the scalebar text, in the format such as 100, 200, 500 nm .
|
|
404
|
+
scalepix: pixel distance of the realoutput scalebar
|
|
405
|
+
"""
|
|
406
|
+
truescale= barLenPix/scale
|
|
309
407
|
|
|
408
|
+
# Find the nearest power of 10 to the truescale
|
|
409
|
+
nearest_power = 10 ** np.floor(np.log10(truescale))
|
|
410
|
+
|
|
411
|
+
# Determine the most appropriate scale bar value
|
|
412
|
+
if truescale >= 5 * nearest_power:
|
|
413
|
+
scalebar = 5 * nearest_power
|
|
414
|
+
elif truescale >= 2 * nearest_power:
|
|
415
|
+
scalebar = 2 * nearest_power
|
|
416
|
+
else:
|
|
417
|
+
scalebar = nearest_power
|
|
418
|
+
|
|
419
|
+
# Calculate the scale in pixels
|
|
420
|
+
scalepix = int(scalebar * scale)
|
|
421
|
+
|
|
422
|
+
# Determine the appropriate unit for the scale bar text
|
|
423
|
+
if scalebar >= 1000:
|
|
424
|
+
text = f"{int(scalebar/1000)} um"
|
|
425
|
+
else:
|
|
426
|
+
text = f"{int(scalebar)} nm"
|
|
427
|
+
return scalepix, text
|
|
310
428
|
|
|
311
|
-
def
|
|
429
|
+
def AddScalePix(img,barLenPix =250, scale = 34.5, px=0.02,py=0.96, barthick=5,lw=1,stroke=True,tscale=1,textThick=4):
|
|
312
430
|
"""
|
|
313
431
|
Function to add scale to image
|
|
314
432
|
Input:
|
|
@@ -320,54 +438,214 @@ def AddScale(img,barLen =2, scale = 34.5, px=0.02,py=0.96, color = 255,thick=5,l
|
|
|
320
438
|
stroke=1: add stroke; stroke=0 No stroke
|
|
321
439
|
|
|
322
440
|
"""
|
|
441
|
+
import cv2
|
|
323
442
|
h,w=img.shape
|
|
324
|
-
|
|
443
|
+
|
|
444
|
+
scalepix, text = getScalePix(barLenPix, scale)
|
|
445
|
+
|
|
446
|
+
# w_scale=int(scale*barLen)
|
|
325
447
|
x1=int(w*px)
|
|
326
448
|
y1=int(h*py)
|
|
327
|
-
x2=x1+
|
|
328
|
-
y2=y1+
|
|
449
|
+
x2=x1+scalepix
|
|
450
|
+
y2=y1+barthick
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
#find bcakground color and make the reverse as scalebar color
|
|
454
|
+
img_bg=img[y1:y2,x1:x2]
|
|
455
|
+
mean_intensity=np.mean(img_bg)
|
|
456
|
+
|
|
457
|
+
if mean_intensity<128:
|
|
458
|
+
color = 255
|
|
459
|
+
else:
|
|
460
|
+
color = 0
|
|
461
|
+
|
|
329
462
|
|
|
330
463
|
bcolor=255-color
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
text = str(barLen)+' nm'
|
|
464
|
+
|
|
336
465
|
font = cv2.FONT_HERSHEY_SIMPLEX#CV_FONT_HERSHEY_SIMPLEX normal size sans-serif font
|
|
337
|
-
if stroke ==
|
|
338
|
-
cv2.putText(img,text,(x1,y1-8), font,
|
|
466
|
+
if stroke == True:
|
|
467
|
+
cv2.putText(img,text,(x1,y1-8), font, tscale, bcolor,int(textThick+lw), cv2.LINE_AA) #Stroke
|
|
339
468
|
cv2.rectangle(img,(x1,y1),(x2,y2),bcolor,2)#boarder color
|
|
340
469
|
|
|
341
470
|
|
|
342
471
|
cv2.rectangle(img,(x1,y1),(x2,y2),color,-1)
|
|
343
472
|
|
|
344
|
-
cv2.putText(img,text,(x1,y1-8), font,
|
|
473
|
+
cv2.putText(img,text,(x1,y1-8), font,tscale, color, textThick, cv2.LINE_AA)
|
|
474
|
+
|
|
475
|
+
def AddScale(img,barLen =2, scale = 34.5, px=0.02,py=0.96, color = 255,fontScale=1.5, barthick=5,textthick=2,stroke=1):
|
|
476
|
+
"""
|
|
477
|
+
Function to add scale to image
|
|
478
|
+
Input:
|
|
479
|
+
img: greyscale image
|
|
480
|
+
barLen: desired scale length
|
|
481
|
+
scale: scale of the image: px/nm: 1000kX- 49.5; 700kX - 34.5
|
|
482
|
+
(px,py): position of the scale bar: r(0-1)
|
|
483
|
+
color: color of the scalebar
|
|
484
|
+
stroke=1: add stroke with thickness, stroke=0 No stroke
|
|
485
|
+
|
|
486
|
+
fontScale: scale of the text, default is 1.
|
|
487
|
+
barthick: scalebar thickness
|
|
488
|
+
textthick: thickness of the text without stroke
|
|
345
489
|
|
|
346
|
-
|
|
490
|
+
"""
|
|
491
|
+
h,w=img.shape
|
|
492
|
+
w_scale=int(scale*barLen)
|
|
493
|
+
x1=int(w*px)
|
|
494
|
+
y1=int(h*py)
|
|
495
|
+
x2=x1+w_scale
|
|
496
|
+
y2=y1+barthick
|
|
497
|
+
|
|
498
|
+
bcolor=255-color
|
|
499
|
+
|
|
500
|
+
text = str(barLen)+' nm'
|
|
501
|
+
font = cv2.FONT_HERSHEY_SIMPLEX#CV_FONT_HERSHEY_SIMPLEX normal size sans-serif font
|
|
502
|
+
shifty=int(8*fontScale)
|
|
503
|
+
if stroke != 0:
|
|
504
|
+
strokethick = int(stroke + textthick)
|
|
505
|
+
rectangle_thickness = max(1, strokethick // 2) # halve it for visual match
|
|
506
|
+
cv2.putText(img, text, (x1, y1 - shifty), font, fontScale, bcolor, strokethick, lineType=cv2.LINE_AA) # Stroke
|
|
507
|
+
cv2.rectangle(img, (x1, y1), (x2, y2), bcolor, rectangle_thickness) # Border color
|
|
508
|
+
|
|
509
|
+
cv2.rectangle(img, (x1, y1), (x2, y2), color, -1)
|
|
510
|
+
cv2.putText(img, text, (x1, y1 - shifty), font, fontScale, color, textthick, cv2.LINE_AA)
|
|
511
|
+
|
|
512
|
+
def AddText(img,text, px=0.98,py=0.96, color = 255,fontScale=0.9,thickness=2,stroke=1):
|
|
347
513
|
"""
|
|
348
514
|
Function to add text str to image
|
|
349
515
|
Input:
|
|
350
516
|
img: greyscale image
|
|
351
517
|
text: textstr to display
|
|
352
518
|
(px,py): position of the text: right,middle corner
|
|
353
|
-
|
|
354
|
-
|
|
519
|
+
fontScale: scale of the text
|
|
520
|
+
thickness: line thickness of the text
|
|
521
|
+
|
|
522
|
+
stroke=1: add stroke width of 1; stroke=0 No stroke
|
|
355
523
|
|
|
356
524
|
"""
|
|
357
525
|
h,w=img.shape
|
|
358
526
|
|
|
359
527
|
font = cv2.FONT_HERSHEY_SIMPLEX#CV_FONT_HERSHEY_SIMPLEX normal size sans-serif font
|
|
360
|
-
D,sd=cv2.getTextSize(text, font,
|
|
528
|
+
D,sd=cv2.getTextSize(text, font, fontScale,thickness)
|
|
361
529
|
wt=int(D[0])
|
|
362
530
|
bcolor=255-color #color of stroke
|
|
363
|
-
bw =lw+1 #stroke thickness
|
|
531
|
+
# bw =lw+1 #stroke thickness
|
|
532
|
+
strokethick=thickness+stroke
|
|
364
533
|
|
|
365
534
|
x=int(w*px-wt)
|
|
366
535
|
y=int(h*py)
|
|
367
|
-
if stroke
|
|
368
|
-
cv2.putText(img,text,(x,y), font,
|
|
369
|
-
cv2.putText(img,text,(x,y), font,
|
|
536
|
+
if stroke !=0:
|
|
537
|
+
cv2.putText(img,text,(x,y), font, fontScale, bcolor, strokethick, cv2.LINE_AA) #Stroke
|
|
538
|
+
cv2.putText(img,text,(x,y), font, fontScale, color, thickness, cv2.LINE_AA)
|
|
539
|
+
|
|
540
|
+
def AddScaleTime2Stack(path,bar,Scale,dt=0.2,fps=15,color=255, time_txt_scale=1.2,textthick=2,stroke=1):
|
|
541
|
+
"""
|
|
542
|
+
Function to add scalebar and timestamp to stack
|
|
543
|
+
Input:
|
|
544
|
+
path: path to tiff stack
|
|
545
|
+
bar: scale bar to show in nm
|
|
546
|
+
Scale: scale for the image stack: px/nm
|
|
547
|
+
dt: time interval of each frame
|
|
548
|
+
others: parameters for adjusting scalebar text size
|
|
549
|
+
Output:
|
|
550
|
+
Tiff stack and avi movie of the added scale&time
|
|
551
|
+
|
|
552
|
+
Example:
|
|
553
|
+
AddScaleTime2Stack(path,bar=20,Scale=22.2,dt=0.5,fps=15,color=255, time_txt_scale=1.2)
|
|
370
554
|
|
|
555
|
+
"""
|
|
556
|
+
stack=tifffile.imread(path)
|
|
557
|
+
nFrames, h,w = stack.shape
|
|
558
|
+
|
|
559
|
+
pathout =path[:-4]+'_St.tif'
|
|
560
|
+
|
|
561
|
+
print("---------------------------------------------")
|
|
562
|
+
print('Testing positions! ')
|
|
563
|
+
fr=stack[0]
|
|
564
|
+
px=0.96
|
|
565
|
+
py=0.96
|
|
566
|
+
|
|
567
|
+
text='0.0 s'
|
|
568
|
+
AddScale(fr,barLen=bar,fontScale=time_txt_scale,scale=Scale,color=color,textthick=textthick,stroke=stroke)
|
|
569
|
+
AddText(fr,text,px=px,py=py,fontScale=time_txt_scale,color=color,thickness=textthick,stroke=stroke)
|
|
570
|
+
showFr(fr)
|
|
571
|
+
|
|
572
|
+
prompt = input("Check the position, press 0 if you are satisfied, any other key to exit: ")
|
|
573
|
+
print("---------------------------------------------")
|
|
574
|
+
|
|
575
|
+
if prompt == "0":
|
|
576
|
+
print("Adding scalebar and timestamp to full stack")
|
|
577
|
+
with tifffile.TiffWriter(pathout,bigtiff=True) as tif:
|
|
578
|
+
|
|
579
|
+
for i in tqdm.tqdm(range(nFrames)):
|
|
580
|
+
img=stack[i]
|
|
581
|
+
time = i * dt
|
|
582
|
+
text=str('%02.1f' %time)+' s'
|
|
583
|
+
AddScale(img,barLen=bar,fontScale=time_txt_scale,scale=Scale,color=color,textthick=textthick,stroke=stroke)
|
|
584
|
+
AddText(img,text,px=px,py=py,fontScale=time_txt_scale,color=color,thickness=textthick,stroke=stroke)
|
|
585
|
+
|
|
586
|
+
tif.write(img, contiguous=True)
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
tiff2avi(pathout,fps=fps)
|
|
590
|
+
print("Done adding scalebar and timestamp to tiff stack! ")
|
|
591
|
+
else:
|
|
592
|
+
print("Exit to change settings")
|
|
593
|
+
|
|
594
|
+
def apply_colormap(image,cmap='viridis'):
|
|
595
|
+
"""
|
|
596
|
+
Function to apply false color to grayscale image
|
|
597
|
+
input:
|
|
598
|
+
Image: grayscale image
|
|
599
|
+
camp: colormap string. such as 'viridis'
|
|
600
|
+
"""
|
|
601
|
+
import matplotlib.pyplot as plt
|
|
602
|
+
colormap = plt.get_cmap(cmap)
|
|
603
|
+
colored_image = colormap(image / 255.0) # Normalize the image and apply colormap
|
|
604
|
+
colored_image = (colored_image[:, :, :3] * 255).astype(np.uint8) # Convert to 8-bit RGB
|
|
605
|
+
return colored_image
|
|
606
|
+
|
|
607
|
+
def tiff2avi_falsecolor(path,cmap='viridis',fps=15):
|
|
608
|
+
"""
|
|
609
|
+
Function to convert tiff to false color avi movie
|
|
610
|
+
input: path : path of tiff stack
|
|
611
|
+
cmap: colormap of the falsecolor
|
|
612
|
+
"""
|
|
613
|
+
|
|
614
|
+
import tifffile
|
|
615
|
+
import numpy as np
|
|
616
|
+
import cv2
|
|
617
|
+
import matplotlib.pyplot as plt
|
|
618
|
+
import tqdm
|
|
619
|
+
|
|
620
|
+
print("------------------------------------------")
|
|
621
|
+
print("Convert stack to faulse color avi")
|
|
622
|
+
stack = tifffile.imread(path)
|
|
623
|
+
nFrames,h,w = stack.shape #make sure the order of h and w!
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
pathout =path[:-4]+'_c_'+str(fps)+'.avi'
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
#Check the colormap effect
|
|
630
|
+
fr = stack[0]
|
|
631
|
+
fr_color=apply_colormap(fr,cmap)
|
|
632
|
+
plt.imshow(fr_color)
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
|
|
636
|
+
|
|
637
|
+
video_writer = cv2.VideoWriter(pathout, fourcc, fps, (w, h),isColor=True)
|
|
638
|
+
|
|
639
|
+
# Process each frame and write to the video
|
|
640
|
+
for i in tqdm.tqdm(range(nFrames)):
|
|
641
|
+
grayscale_image = stack[i]
|
|
642
|
+
colored_image = apply_colormap(grayscale_image,cmap)
|
|
643
|
+
colored_image = cv2.cvtColor(colored_image, cv2.COLOR_RGB2BGR) # Convert RGB to BGR
|
|
644
|
+
|
|
645
|
+
video_writer.write(colored_image)
|
|
646
|
+
|
|
647
|
+
# Release the video writer
|
|
648
|
+
video_writer.release()
|
|
371
649
|
|
|
372
650
|
def AverageFrame(path,AveN):
|
|
373
651
|
#Average frames by AveN to increase SNR
|
|
@@ -377,14 +655,139 @@ def AverageFrame(path,AveN):
|
|
|
377
655
|
pathout = path[:-4]+'_'+str(AveN)+'ave.tif'
|
|
378
656
|
nFramesOut=math.floor(nFrames/AveN)
|
|
379
657
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
658
|
+
with tifffile.TiffWriter(pathout,bigtiff=True) as tif:
|
|
659
|
+
for i in tqdm.tqdm(range(nFramesOut)):
|
|
660
|
+
AveFr= im[i*AveN]-im[i*AveN]
|
|
661
|
+
for m in range(AveN):
|
|
662
|
+
fr=im[i*AveN+m]
|
|
663
|
+
AveFr=AveFr+fr/AveN
|
|
664
|
+
img = AveFr.astype(np.uint8)
|
|
665
|
+
tif.write(fr,continuous=True)
|
|
666
|
+
|
|
667
|
+
def apply_colormap(image,cmap='viridis'):
|
|
668
|
+
"""
|
|
669
|
+
Function to apply false color to grayscale image
|
|
670
|
+
input:
|
|
671
|
+
Image: grayscale image
|
|
672
|
+
camp: colormap string. such as 'viridis'
|
|
673
|
+
"""
|
|
674
|
+
import matplotlib.pyplot as plt
|
|
675
|
+
colormap = plt.get_cmap(cmap)
|
|
676
|
+
colored_image = colormap(image / 255.0) # Normalize the image and apply colormap
|
|
677
|
+
colored_image = (colored_image[:, :, :3] * 255).astype(np.uint8) # Convert to 8-bit RGB
|
|
678
|
+
return colored_image
|
|
679
|
+
|
|
680
|
+
def falsecolorstack(path,cmap='viridis',fps=15):
|
|
681
|
+
import tifffile
|
|
682
|
+
import numpy as np
|
|
683
|
+
import cv2
|
|
684
|
+
import tqdm
|
|
685
|
+
print('Convert tiff stack to false color movie')
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
stack = tifffile.imread(path)
|
|
689
|
+
nFrames,h,w = stack.shape #make sure the order of h and w!
|
|
690
|
+
|
|
691
|
+
pathout =path[:-4]+'_c_'+str(fps)+'.avi'
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
|
|
695
|
+
|
|
696
|
+
video_writer = cv2.VideoWriter(pathout, fourcc, fps, (w, h),isColor=True)
|
|
697
|
+
|
|
698
|
+
# Process each frame and write to the video
|
|
699
|
+
for i in tqdm.tqdm(range(nFrames)):
|
|
700
|
+
grayscale_image = stack[i]
|
|
701
|
+
colored_image = apply_colormap(grayscale_image,cmap)
|
|
702
|
+
colored_image = cv2.cvtColor(colored_image, cv2.COLOR_RGB2BGR) # Convert RGB to BGR
|
|
703
|
+
|
|
704
|
+
video_writer.write(colored_image)
|
|
705
|
+
|
|
706
|
+
# Release the video writer
|
|
707
|
+
video_writer.release()
|
|
708
|
+
print('Convertion done!')
|
|
709
|
+
|
|
710
|
+
def convertAVIcodec(path,fpsout=0,exp_t=0.2,nFrames=None,isColor=False):
|
|
711
|
+
"""
|
|
712
|
+
Function to Directly convert screen recording avi to avi that mac can read
|
|
713
|
+
If fpsout=0, the framerate will not be changed (same as original)
|
|
714
|
+
exp_t: actual exposure time, to remove dupulicate frames
|
|
715
|
+
else fpsout will be changed to set value
|
|
716
|
+
"""
|
|
717
|
+
|
|
718
|
+
import moviepy.editor as mp
|
|
719
|
+
print("======================")
|
|
720
|
+
print("Convert AVI codec!")
|
|
721
|
+
video = mp.VideoFileClip(path)
|
|
722
|
+
fps = int(video.fps)
|
|
723
|
+
w = int(video.w)
|
|
724
|
+
h = int(video.h)
|
|
725
|
+
if nFrames==None:
|
|
726
|
+
nFrames = int(fps*video.duration)
|
|
727
|
+
duration =video.duration
|
|
728
|
+
print("fps=", fps, " w =",w, " h=", h)
|
|
729
|
+
print("Total number of Frames=", nFrames)
|
|
730
|
+
#Remove duplic frames
|
|
731
|
+
if fpsout==0:
|
|
732
|
+
fpsout=fps
|
|
733
|
+
nFramesOut=nFrames
|
|
734
|
+
dup=1
|
|
735
|
+
else:
|
|
736
|
+
dup=fps*exp_t
|
|
737
|
+
nFramesOut=int(nFrames/dup)
|
|
738
|
+
|
|
739
|
+
# Export avi
|
|
740
|
+
if nFrames==None:
|
|
741
|
+
pathout2 =path[:-4]+'_'+str(fpsout)+'.avi'
|
|
742
|
+
pathout= path[:-4]+'_DB.tif'
|
|
743
|
+
else:
|
|
744
|
+
pathout2 =path[:-4]+'_Trim_'+str(fpsout)+'.avi'
|
|
745
|
+
pathout= path[:-4]+'_Trim_DB.tif'
|
|
746
|
+
codec = cv2.VideoWriter_fourcc(*'MJPG')
|
|
747
|
+
video_out = cv2.VideoWriter(pathout2, codec , fpsout, (w, h),isColor=isColor)
|
|
748
|
+
|
|
749
|
+
with tifffile.TiffWriter(pathout,bigtiff=True) as tif:
|
|
750
|
+
for j in tqdm.tqdm(range(nFramesOut)):
|
|
751
|
+
i=j*dup
|
|
752
|
+
fr = video.get_frame(mp.cvsecs(i/fps))
|
|
753
|
+
if isColor==False:
|
|
754
|
+
fr = cv2.cvtColor(fr, cv2.COLOR_BGR2GRAY)
|
|
755
|
+
|
|
756
|
+
tif.write(fr, contiguous=True)
|
|
757
|
+
if isColor== True:
|
|
758
|
+
fr = cv2.cvtColor(fr,cv2.COLOR_BGR2RGB)#since open cv uses different color sequence
|
|
759
|
+
video_out.write(fr)
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
video.reader.close()
|
|
763
|
+
video_out.release()
|
|
764
|
+
print("Conversion done!")
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
def invertLUT(path):
|
|
768
|
+
import tifffile
|
|
769
|
+
import tqdm
|
|
770
|
+
|
|
771
|
+
video = tifffile.imread(path)
|
|
772
|
+
nFrames, h,w = video.shape[:3]
|
|
773
|
+
pathout =path[:-4]+'_Inv.tiff'
|
|
774
|
+
|
|
775
|
+
with tifffile.TiffWriter(pathout,bigtiff=True) as tif:
|
|
776
|
+
|
|
777
|
+
print("---------------------------------------------")
|
|
778
|
+
print('Inverting Tiff stack LUT')
|
|
779
|
+
for i in tqdm.tqdm(range(nFrames)):
|
|
780
|
+
img=video[i]
|
|
781
|
+
img_IV=255-img
|
|
782
|
+
tif.write(img_IV, contiguous=True)
|
|
783
|
+
print("Invert LUT done!")
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
|
|
787
|
+
|
|
788
|
+
|
|
789
|
+
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
|
|
390
793
|
|