insituTEM 0.1.6__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 +512 -111
- insituTEM/insitu_Preprocess.py +229 -25
- insituTEM/insitu_alignment.py +219 -44
- insitutem-0.1.7.dist-info/METADATA +20 -0
- insitutem-0.1.7.dist-info/RECORD +12 -0
- {insituTEM-0.1.6.dist-info → insitutem-0.1.7.dist-info}/WHEEL +1 -1
- insituTEM-0.1.6.dist-info/METADATA +0 -13
- insituTEM-0.1.6.dist-info/RECORD +0 -9
- {insituTEM-0.1.6.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,89 +45,133 @@ def tiff2mp4(path):
|
|
|
47
45
|
print("==============================================")
|
|
48
46
|
print("MP4 convertion Done!")
|
|
49
47
|
|
|
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))
|
|
50
76
|
|
|
51
77
|
|
|
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
|
-
# k = input('Input your selection: ')
|
|
91
|
-
# if k == 2:
|
|
92
|
-
# sf = fps/fpsIn
|
|
93
|
-
# video =video.fx(mp.vfx.speedx, sf)
|
|
94
|
-
# elif k == 0:
|
|
95
|
-
# fps = fpsIn
|
|
96
|
-
# video.reader.close()# To fix handel error problem
|
|
97
|
-
# print("---------------------")
|
|
98
|
-
|
|
99
|
-
# print("Save to mp4!")
|
|
100
|
-
# video.write_videofile(pathout, fps=fps,codec='libx264', bitrate='32 M',preset='ultrafast')
|
|
101
|
-
|
|
102
|
-
# print("==============================================")
|
|
103
|
-
# print("MP4 convertion Done!")
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
def f2tif(path,is_gray=1):
|
|
107
|
-
"""
|
|
108
|
-
function to convert any input file to tif stack
|
|
109
|
-
Inputs: filepath, is_gray: 1 for grayscale, 0 for rgb
|
|
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
|
|
110
116
|
|
|
111
117
|
Output: file in the same folder named '..._cv.tif'
|
|
112
118
|
"""
|
|
113
|
-
|
|
119
|
+
import moviepy.editor as mp
|
|
120
|
+
import tifffile
|
|
114
121
|
import tqdm
|
|
115
122
|
print("==============================================")
|
|
116
123
|
print("Convert file to tif stack!")
|
|
117
124
|
pathout = path[:-4]+'_'+str(is_gray)+'.tif'
|
|
118
125
|
video = mp.VideoFileClip(path)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
+
|
|
128
147
|
print("==============================================")
|
|
129
148
|
print("TIF convertion Done!")
|
|
130
|
-
print("nFrames="+str(i))
|
|
131
149
|
video.reader.close()# To fix handel error problem
|
|
132
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)
|
|
133
175
|
|
|
134
176
|
def f2gif(path,fps):
|
|
135
177
|
"""
|
|
@@ -165,8 +207,8 @@ def f2gif(path,fps):
|
|
|
165
207
|
elif k == 0:
|
|
166
208
|
fps = fpsIn
|
|
167
209
|
|
|
168
|
-
|
|
169
|
-
|
|
210
|
+
video.write_gif(pathout,fps=fps)
|
|
211
|
+
video.reader.close()# To fix handel error problem
|
|
170
212
|
# if path.endswith('.gif'):
|
|
171
213
|
# clip.write_videofile(pathout,fps=fps,codec='libx264', bitrate='32 M',preset='ultrafast')
|
|
172
214
|
print("==============================================")
|
|
@@ -295,22 +337,96 @@ def ExtractFrame(path,framelist,is_gray=1):
|
|
|
295
337
|
if path.endswith('.tif')==0:
|
|
296
338
|
video.reader.close()
|
|
297
339
|
|
|
298
|
-
|
|
299
340
|
def writeCSV(pathout,data,fmt='%1.1d'):
|
|
300
341
|
# import csv
|
|
301
342
|
import numpy as np
|
|
302
343
|
# (length,width)=np.shape(data)
|
|
303
344
|
np.savetxt(pathout, data, fmt=fmt, delimiter=",")
|
|
304
|
-
|
|
305
|
-
#
|
|
306
|
-
#def Time2List()
|
|
345
|
+
|
|
307
346
|
def showFr(im):
|
|
308
347
|
from PIL import Image
|
|
309
348
|
img = Image. fromarray(im)
|
|
310
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
|
|
311
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
|
|
312
379
|
|
|
313
|
-
|
|
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
|
|
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
|
|
428
|
+
|
|
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):
|
|
314
430
|
"""
|
|
315
431
|
Function to add scale to image
|
|
316
432
|
Input:
|
|
@@ -322,54 +438,214 @@ def AddScale(img,barLen =2, scale = 34.5, px=0.02,py=0.96, color = 255,thick=5,l
|
|
|
322
438
|
stroke=1: add stroke; stroke=0 No stroke
|
|
323
439
|
|
|
324
440
|
"""
|
|
441
|
+
import cv2
|
|
325
442
|
h,w=img.shape
|
|
326
|
-
|
|
443
|
+
|
|
444
|
+
scalepix, text = getScalePix(barLenPix, scale)
|
|
445
|
+
|
|
446
|
+
# w_scale=int(scale*barLen)
|
|
327
447
|
x1=int(w*px)
|
|
328
448
|
y1=int(h*py)
|
|
329
|
-
x2=x1+
|
|
330
|
-
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
|
+
|
|
331
462
|
|
|
332
463
|
bcolor=255-color
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
text = str(barLen)+' nm'
|
|
464
|
+
|
|
338
465
|
font = cv2.FONT_HERSHEY_SIMPLEX#CV_FONT_HERSHEY_SIMPLEX normal size sans-serif font
|
|
339
|
-
if stroke ==
|
|
340
|
-
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
|
|
341
468
|
cv2.rectangle(img,(x1,y1),(x2,y2),bcolor,2)#boarder color
|
|
342
469
|
|
|
343
470
|
|
|
344
471
|
cv2.rectangle(img,(x1,y1),(x2,y2),color,-1)
|
|
345
472
|
|
|
346
|
-
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
|
|
347
489
|
|
|
348
|
-
|
|
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):
|
|
349
513
|
"""
|
|
350
514
|
Function to add text str to image
|
|
351
515
|
Input:
|
|
352
516
|
img: greyscale image
|
|
353
517
|
text: textstr to display
|
|
354
518
|
(px,py): position of the text: right,middle corner
|
|
355
|
-
|
|
356
|
-
|
|
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
|
|
357
523
|
|
|
358
524
|
"""
|
|
359
525
|
h,w=img.shape
|
|
360
526
|
|
|
361
527
|
font = cv2.FONT_HERSHEY_SIMPLEX#CV_FONT_HERSHEY_SIMPLEX normal size sans-serif font
|
|
362
|
-
D,sd=cv2.getTextSize(text, font,
|
|
528
|
+
D,sd=cv2.getTextSize(text, font, fontScale,thickness)
|
|
363
529
|
wt=int(D[0])
|
|
364
530
|
bcolor=255-color #color of stroke
|
|
365
|
-
bw =lw+1 #stroke thickness
|
|
531
|
+
# bw =lw+1 #stroke thickness
|
|
532
|
+
strokethick=thickness+stroke
|
|
366
533
|
|
|
367
534
|
x=int(w*px-wt)
|
|
368
535
|
y=int(h*py)
|
|
369
|
-
if stroke
|
|
370
|
-
cv2.putText(img,text,(x,y), font,
|
|
371
|
-
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)
|
|
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)
|
|
372
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()
|
|
373
649
|
|
|
374
650
|
def AverageFrame(path,AveN):
|
|
375
651
|
#Average frames by AveN to increase SNR
|
|
@@ -379,14 +655,139 @@ def AverageFrame(path,AveN):
|
|
|
379
655
|
pathout = path[:-4]+'_'+str(AveN)+'ave.tif'
|
|
380
656
|
nFramesOut=math.floor(nFrames/AveN)
|
|
381
657
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
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
|
+
|
|
392
793
|
|