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.
@@ -2,8 +2,8 @@
2
2
  """
3
3
 
4
4
  in-situ TEM Toolbox - PreProcess
5
- By: Meng and Michael
6
- Assembles of functions related to movie preprocess
5
+ By: Meng Li and Michael
6
+ Assembles of functions related to movie preprocess
7
7
  Example:
8
8
 
9
9
  import insitu_Preprocess as PP
@@ -18,7 +18,8 @@ import cv2
18
18
  from scipy import signal
19
19
  from PIL import Image
20
20
  import matplotlib.pyplot as plt
21
-
21
+ import tifffile
22
+ import tqdm
22
23
 
23
24
  def estimate_dup(A,B,threshold=1):
24
25
  """
@@ -66,44 +67,76 @@ def median_blur (score_list, i,thrs=150,wid=21):
66
67
  def detect_blur_fft(image, size=20, thresh=15,vis=False):
67
68
  """
68
69
  Function to detect if one frame is blurred using FFT
70
+ Example:
71
+ score,is_blur = PP.detect_blur_fft(image, size=20, thresh=15,vis=False)
72
+ Input:
69
73
  image: grayscale image, default size: 128*128 px
70
- size: filter size to get the background of FFT
74
+ size: filter size to get the background of FFT
71
75
  thresh: threshold value for blur scores, smaller score, more blurry
72
-
76
+ Output:
77
+ mean: mean value of the frame
78
+ is_blur: whether the frame is blur
73
79
  """
80
+ from insituTEM import insitu_DP as DP
74
81
  # grab the dimensions of the image and use the dimensions to derive the center (x, y)-coordinates
75
- (h, w) = image.shape
76
- (cX, cY) = (int(w / 2.0), int(h / 2.0))
77
- # compute the FFT to find the frequency transform, then shift
78
- # the zero frequency component (i.e., DC component located at
79
- # the top-left corner) to the center where it will be more
80
- # easy to analyze
81
- fft = np.fft.fft2(image)
82
- fftShift = np.fft.fftshift(fft)
83
- magnitude = 20 * np.log(np.abs(fftShift))
82
+ # h, w = image.shape
83
+
84
+
85
+ magnitude=DP.getFFT(image)
86
+ h,w = magnitude.shape
87
+ cX, cY = w //2, h//2
88
+ bar=int(h/100)
89
+ center=bar*10
90
+ #use only the center of the FFT
91
+ crop_h,crop_w=(h-cX)//2, (w-cY)//2
92
+
93
+
84
94
  # compute the background of FFT to make the diffraaction spots more obvious
85
95
  bg = cv2.blur(magnitude,(size,size))
86
96
 
87
97
  enhanced =cv2.subtract(magnitude, bg)
98
+ #remove noise by mean
99
+ # enhanced=enhanced[crop_h:(crop_h+cY),crop_w:(crop_w+cX)]
100
+
88
101
  #remove white noise from the substracted image
89
- enhanced[enhanced<30]=0
90
- #remove center spot
91
- enhanced[cY - 10:cY + 10, cX - 10:cX + 10]=0
102
+ enhanced[enhanced<20]=0
103
+
104
+ # Check the data type and convert if necessary
105
+ if enhanced.dtype != np.uint8:
106
+ # Normalize the image to the range [0, 255] if it has a different range
107
+ enhanced = cv2.normalize(enhanced, None, 0, 255, cv2.NORM_MINMAX)
108
+ # Convert the image to uint8
109
+ enhanced = enhanced.astype(np.uint8)
110
+
111
+ # Apply median filter
112
+ enhanced = cv2.medianBlur(enhanced, 3)
113
+
114
+ # enhanced = cv2.medianBlur(enhanced, 3)
115
+ # #remove center spot
116
+ enhanced[(cY - center): (cY + center), cX - center:cX + center] =0
117
+ enhanced[(cY - bar): (cY + bar), :]=0
118
+ enhanced[:, (cX - bar): (cX + bar)]=0
119
+ # enhanced[
120
+
121
+
122
+ croppedFFT=enhanced[crop_h:(crop_h+cY),crop_w:(crop_w+cX)]
92
123
 
93
124
  if vis:
94
- (fig, ax) = plt.subplots(1, 2, )
125
+ (fig, ax) = plt.subplots(1, 2,figsize=(10, 5) )
95
126
  ax[0].imshow(image, cmap="gray")
96
127
  ax[0].set_title("Input")
97
- ax[0].set_xticks([])
98
- ax[0].set_yticks([])
128
+ # ax[0].set_xticks([])
129
+ # ax[0].set_yticks([])
99
130
  # display the magnitude image
100
- ax[1].imshow(enhanced,cmap="viridis")
131
+ ax[1].imshow(croppedFFT,cmap="viridis")
101
132
  ax[1].set_title("Filtered FFT")
102
- ax[1].set_xticks([])
103
- ax[1].set_yticks([])
133
+ # ax[1].set_xticks([])
134
+ # ax[1].set_yticks([])
135
+
104
136
  # show our plots
105
137
  plt.show()
106
- mean = np.mean(enhanced)*1000
138
+ # mean = np.mean(enhanced)*1000
139
+ mean = np.mean(croppedFFT)*1000
107
140
  # print(mean)
108
141
  # the image will be considered "blurry" if the mean value of the magnitudes is less than the threshold value
109
142
  return (mean,mean<thresh)
@@ -198,4 +231,175 @@ def removeDPs(img,DP):
198
231
  else:
199
232
  for j in range(nDP):
200
233
  position=DP[j]
201
- removeDP(img,position)
234
+ removeDP(img,position)
235
+
236
+
237
+ def BlurDetection(path,wid=31):
238
+ """
239
+ Function to remove blurry frames based on the blur score
240
+ Input: tif file path
241
+ Output: deblurred tif stack
242
+ """
243
+ from insituTEM import insitu_IO as IO
244
+
245
+ indexout=path[:-4]+'_DB-index.csv'
246
+ DBout=path[:-4]+'_DB.csv'
247
+ DBout2=path[:-4]+'_Blur.csv'
248
+
249
+ stack = tifffile.imread(path)
250
+ nFrames,h,w = stack.shape #make sure the order of h and w!
251
+ index = []#index of remaining frames
252
+ score = []
253
+
254
+ print("------------------------------------------")
255
+ print("Calculating blur scores!")
256
+
257
+ for i in tqdm.tqdm(range(nFrames)):
258
+ fr=stack[i]
259
+ s = blur_score(fr)
260
+ score.append(s)
261
+ index.append(i)
262
+
263
+ length = len(score)
264
+ Blur=np.zeros((length,3))#[i,blur_score,blur_th]
265
+ Blur[:,0]=index
266
+ Blur[:,1]=score
267
+
268
+ plt.plot(score,'gray')
269
+ plt.show()
270
+
271
+ print("------------------------------------------")
272
+ print("Check blur detection!")
273
+
274
+ thrs=int(input( 'Input blur threshold(default: 70): '))
275
+ while thrs!=0:
276
+ index2=[]
277
+
278
+ for i in tqdm.tqdm(range(len(score))):
279
+ medthres,is_blur=median_blur (score, i,thrs,wid=wid)#wid must be odd
280
+ # DB[index[i],3]=is_blur
281
+ Blur[i,2]=medthres
282
+ if is_blur == 0:
283
+ index2.append(index[i])
284
+
285
+ plt.plot(Blur[:,0],Blur[:,1],'gray',Blur[:,0],Blur[:,2]-thrs,'r',Blur[:,0],Blur[:,2]+thrs,'r')
286
+ plt.show()
287
+ thrs=int(input( 'Press 0 if you are satisfied, press corrected threshold if you want to change: '))
288
+
289
+ IO.writeCSV(DBout2,Blur)
290
+
291
+ result= np.zeros((len(index2),2))
292
+ for i in range(len(index2)):
293
+ result[i,0]=i
294
+ result[i,1]=index2[i]
295
+
296
+ IO.writeCSV(indexout,result)
297
+
298
+ print("------------------------------------------")
299
+ print("Save blur removed file")
300
+ pathout2=path[:-4]+'_DBlur.tif'
301
+
302
+ with tifffile.TiffWriter(pathout2,bigtiff=True) as tif:
303
+ for j in tqdm.tqdm(range(len(index2))):
304
+ i=int(result[j,1])
305
+ fr=stack[i]
306
+
307
+ tif.write(fr, contiguous=True)
308
+ print("------------------------------------------")
309
+ print("Blur removed!")
310
+ print("==========================================")
311
+
312
+
313
+ def movie_preprocess(path,remove_DP=True,DP=[[0, 0, 1, 1],[0,0,2,2]],Crop=True,cropboarder=[0,0,0,0],Trim=False,start_time_mmss="00:00",end_time_mmss="00:00",grayscale=True,exp_time=0):
314
+ """
315
+ Function to preprocess the raw TEM movie to tiff
316
+ Input:
317
+ path: file path of the movie
318
+ remove DP: if there are constant dead point in the movie to remove,
319
+ if so, input the DP value.
320
+ Crop: if crop the movie to remove the boarders
321
+ if so, input the cropboarder: [left, top, right, bottom]
322
+ Trim: if trim the movie length
323
+ if so, input the start and end time in mm:ss
324
+ grayscale: if convert the movie to grayscale
325
+ exp_time: if remove the duplicated frame based on the real exposure time.
326
+ if no need to remove duplicates, put exp_time = 0
327
+ """
328
+ # print("=========================================")
329
+ print("ETEM movie preprocessor start!")
330
+
331
+ import moviepy.editor as mp
332
+ import moviepy.video.fx.all as vfx
333
+ from insituTEM import insitu_IO as IO
334
+
335
+
336
+ video = mp.VideoFileClip(path)
337
+ if Trim == True:
338
+ # Convert mm:ss to seconds
339
+ start_time_seconds = sum(x * int(t) for x, t in zip([60, 1], start_time_mmss.split(":")))
340
+ end_time_seconds = sum(x * int(t) for x, t in zip([60, 1], end_time_mmss.split(":")))
341
+
342
+ video = video.subclip(start_time_seconds, end_time_seconds)# cut the clip between t=0 and 28 secs.
343
+
344
+ fps = int(video.fps)
345
+ # fps= 15
346
+ w = int(video.w)
347
+ h = int(video.h)
348
+ nFrames = int(fps*video.duration)
349
+
350
+ print("fps=", fps, " w =",w, " h=", h, "duration= ",video.duration)
351
+ print("Total number of Frames=", nFrames)
352
+
353
+
354
+
355
+ #Preview first frame
356
+ print("------------------------------------------")
357
+ print("Preview the processed frame: press 0 if you want to continue: ")
358
+
359
+ if Crop == True:
360
+ video = video.fx(vfx.crop, x1=cropboarder[0], y1=cropboarder[1], x2=w-cropboarder[2], y2=h-cropboarder[3])#crop movie snapshot
361
+
362
+ fr = video.get_frame(mp.cvsecs(1/fps))
363
+
364
+ if grayscale==True:
365
+ fr = cv2.cvtColor(fr, cv2.COLOR_BGR2GRAY)
366
+
367
+ if remove_DP==True:
368
+ removeDPs(fr,DP)
369
+
370
+ IO.showFr(fr)
371
+ prompt = input("Input 0 if you want to continue, other keys to break :")
372
+
373
+ if prompt != "0":
374
+ print("Stopped by user. Modify the cropboarder values and restart.")
375
+ return
376
+ else:
377
+ #continue to apply to the full movie
378
+ #remove duplicate frames with known fps conversion
379
+ if exp_time==0:
380
+ dup=1
381
+ else:
382
+ dup= fps*exp_time
383
+
384
+ nFramesOut=int(nFrames/dup)
385
+ print ('nFramesOut= ', nFramesOut)
386
+ print('nFramesIn= ',nFrames)
387
+
388
+
389
+ pathout=path[:-4]+'_CutDB.tif'
390
+
391
+ print("------------------------------------------")
392
+ print("Saving duplicate removed processed frames~")
393
+
394
+
395
+ with tifffile.TiffWriter(pathout,bigtiff=True) as tif:
396
+ for j in tqdm.tqdm(range(nFramesOut)):
397
+ i=j*dup
398
+ fr = video.get_frame(mp.cvsecs(i/fps))
399
+ if grayscale==True:
400
+ fr = cv2.cvtColor(fr, cv2.COLOR_BGR2GRAY)
401
+ if remove_DP==True:
402
+ removeDPs(fr,DP)
403
+ tif.write(fr, contiguous=True)
404
+
405
+ print("Conversion done!")
@@ -10,15 +10,20 @@ Example:
10
10
  Al.get_matrix()
11
11
 
12
12
  Created on Tue Jun 11 17:22:45 2019
13
- By: Michael and Meng
13
+ By: Meng Li and Michel
14
14
  """
15
+
16
+
15
17
  import numpy as np
16
18
  import csv
17
19
  import cv2
18
20
  from skimage import io #package for TIFF stack reading
19
21
  import tifffile
20
22
  from scipy import signal
21
- from tqdm import tqdm
23
+ import tqdm
24
+ import matplotlib.pyplot as plt
25
+ from insituTEM import insitu_IO as IO
26
+
22
27
 
23
28
  def get_path():
24
29
  from tkinter import Tk
@@ -54,6 +59,117 @@ Please choose the csv you want to use
54
59
  return dx, dy, csvpath
55
60
 
56
61
 
62
+ def Adaptive_template_match(path, NOF = 50, csvout=True, TMout=True, TMdenoise=True, TMdenoise_window=5,extend=True, bg = 150):
63
+ '''
64
+ Function to produce adaptive template matching on tiff image stack based on ROI selection
65
+ input:
66
+ path: image path for grayscale Tiff stack
67
+ NOF: number of frames for template to grow
68
+ csvout: whether to write the translation matrix
69
+ TMout: whether to write the template match found feature
70
+ TMdenoise: whether to denoise the measured matrix to remove sudden change
71
+ TMdenoise_window: window size for TMdenoise
72
+ bg: background color (0-255)
73
+ extend: whether to extend the image for the translation (avoid crop)
74
+
75
+ output:
76
+ Translated image stack
77
+ Csv file of translation matrix
78
+ Captured ROI location
79
+
80
+ Write by Meng Li (mona.mengli@gmail.com) 2024.02.06
81
+ '''
82
+ import cv2
83
+ import numpy as np
84
+ from matplotlib import pyplot as plt
85
+ import tifffile
86
+ import easygui
87
+ import tqdm
88
+ from insituTEM import insitu_IO as IO
89
+ # from insituTEM import insitu_alignment as AL
90
+
91
+ ###############################################################
92
+ ## 1. Inital settings
93
+
94
+ stack = tifffile.imread(path)
95
+ nFrames, h,w = stack.shape
96
+
97
+ TM = np.zeros((nFrames,3))#frame, TX,TY,max_val
98
+ pathout3 = path[:-4]+'_TM.csv'
99
+ pathout2 = path[:-4]+'_TM.tif'
100
+
101
+ ################################################################
102
+ #2. Open fr0 and select ROI for template matching
103
+ img = stack[0]
104
+ ## Select ROI for template matching
105
+ r = cv2.selectROI("Select ROI, press ENTER to confirm",img,fromCenter=False,showCrosshair=False)
106
+ cv2.destroyWindow("Select ROI, press ENTER to confirm")
107
+ # Crop image
108
+ template = img[int(r[1]):int(r[1]+r[3]), int(r[0]):int(r[0]+r[2])]#opencv coordinate: Y,x , from upper left corner of the image
109
+ # Display cropped image
110
+ cv2.imshow("Template, press ENTER to confirm", template)
111
+ cv2.waitKey(0)
112
+ # cv2.destroyWindow("Template, press ENTER to confirm")
113
+ cv2.destroyAllWindows()
114
+ for _ in range(5):
115
+ cv2.waitKey(1)
116
+
117
+
118
+
119
+ # ################################################################
120
+ #3. Apply template to template matching
121
+ meth='cv2.TM_CCOEFF_NORMED'
122
+ method = eval(meth)
123
+ w, h = template.shape[::-1]
124
+
125
+ print("------------------------------------------")
126
+ print("Calculating drift~")
127
+ with tifffile.TiffWriter(pathout2,bigtiff=True) as tif:
128
+ for i in tqdm.tqdm(range(nFrames)):
129
+ fr=stack[i]
130
+ # Apply template Matching
131
+ res = cv2.matchTemplate(fr,template,method)
132
+ min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
133
+ top_left = max_loc
134
+ TM[i,0]=i
135
+ TM[i,1]=top_left[0]
136
+ TM[i,2]=top_left[1]
137
+ bottom_right = (top_left[0] + w, top_left[1] + h)
138
+ cv2.rectangle(fr,top_left, bottom_right, 255, 2)
139
+
140
+ if i%NOF==NOF-1:
141
+ template = fr[int(top_left[1]):int(top_left[1] + h), int(top_left[0]):int(top_left[0] + w)]#opencv coordinate: Y,x , from upper left corner of the image
142
+ if TMout==True:
143
+ tif.write(fr, contiguous=True)
144
+
145
+
146
+ TM[:,1]=TM[0,1]-TM[:,1]
147
+ TM[:,2]=TM[0,2]-TM[:,2]
148
+
149
+ # ################################################################
150
+ #4. Apply TM to movie
151
+ if TMdenoise==True:
152
+ #Get average to minimize total movement
153
+ TM=denoiseTM(TM,TMdenoise_window)
154
+ Mx=int(np.mean(TM[:,1]))
155
+ My=int(np.mean(TM[:,2]))
156
+ TM[:,1]=TM[:,1]-Mx
157
+ TM[:,2]=TM[:,2]-My
158
+
159
+ print("------------------------------------------")
160
+ print("Saving files~")
161
+ plt.plot(TM[:,0],TM[:,1],'b',TM[:,0],TM[:,2],'r')
162
+
163
+ if csvout==True:
164
+ IO.writeCSV(pathout3,TM,fmt='%1.1d')
165
+
166
+ TranslateStack(path,TM,bg=bg, extend = extend)
167
+ print("Adaptive template matching done!")
168
+ plt.show(block=False)
169
+ plt.pause(0.1)
170
+ plt.close()
171
+
172
+
57
173
 
58
174
 
59
175
  def TranslateStack(movie_path,matrix,bg=150,extend=True):
@@ -90,7 +206,7 @@ def TranslateStack(movie_path,matrix,bg=150,extend=True):
90
206
 
91
207
  #2d matrix flipped order of width and height to work with warpaffine method
92
208
  print("\nApplying translation to stack\n")
93
- with tifffile.TiffWriter(movie_pathout) as tif:
209
+ with tifffile.TiffWriter(movie_pathout,bigtiff=True) as tif:
94
210
 
95
211
  for num in tqdm(range(nframes)):
96
212
  temparray = img[num,:,:]
@@ -100,13 +216,6 @@ def TranslateStack(movie_path,matrix,bg=150,extend=True):
100
216
 
101
217
  extend_img = cv2.copyMakeBorder(temparray, top, bottom, left, right, cv2.BORDER_CONSTANT, value=bg)
102
218
  translated_img = cv2.warpAffine(extend_img,TM,(width,height),borderValue =bg)#fill with gray
103
- #Generates an image translated by dx and dy
104
- # if num == 0:
105
- # tifffile.imwrite(movie_pathout, translated_img, append=False, bigtiff=True)
106
- # #Overrides any previous files saved to the same path
107
- # else:
108
- # tifffile.imwrite(movie_pathout, translated_img, append=True, bigtiff=True)
109
- # #appends onto the tiff stack
110
219
  tif.write(translated_img, contiguous=True)
111
220
 
112
221
 
@@ -246,4 +355,181 @@ def template_match(imgpath, w=24):
246
355
  for num in iterate:
247
356
  TM[num,0] = dx[num]
248
357
  TM[num,1] = dy[num]
249
- IO.writeCSV(csvpathout,TM)
358
+ IO.writeCSV(csvpathout,TM)
359
+
360
+
361
+ def ATM_locglobal(path, NOF=50, csvout=True, TMout=True, TMdenoise=True, TMdenoise_window=5, extend=True, bg=150,search_margin_local=1, match_threshold=0.8):
362
+ '''
363
+ Function to produce adaptive template matching on TIFF image stack based on ROI selection with local and global selections
364
+
365
+ Input:
366
+ path: Image path for grayscale TIFF stack
367
+ NOF: Number of frames for template to grow
368
+ csvout: Whether to write the translation matrix
369
+ TMout: Whether to write the template match found feature
370
+ TMdenoise: Whether to denoise the measured matrix to remove sudden change
371
+ TMdenoise_window: Window size for TMdenoise
372
+ bg: Background color (0-255)
373
+ extend: Whether to extend the image for the translation (avoid crop)
374
+ match_threshold: Threshold for considering the new ROI position close to the previous one
375
+
376
+ Output:
377
+ Translated image stack
378
+ CSV file of translation matrix
379
+ Captured ROI location
380
+
381
+ Written by Meng Li (mona.mengli@gmail.com) 2024.07.06
382
+ '''
383
+
384
+ ###############################################################
385
+ # 1. Initial settings
386
+
387
+
388
+ import sys
389
+
390
+ try:
391
+ stack = tifffile.imread(path)
392
+ except OSError as e:
393
+ print(f"Error reading the TIFF file: {e}")
394
+ sys.exit(1)
395
+
396
+ # stack = tifffile.imread(path)
397
+ nFrames, h, w = stack.shape
398
+
399
+ TM = np.zeros((nFrames, 3)) # frame, TX, TY, max_val
400
+ pathout3 = path[:-4] + '_TM.csv'
401
+ pathout2 = path[:-4] + '_TM.tif'
402
+
403
+ ###############################################################
404
+ # 2. Open the first frame and select ROI for template matching
405
+ img = stack[0]
406
+
407
+ # Select ROI for template matching, returns x1,y1,w,h
408
+ r = cv2.selectROI("Select ROI, press ENTER to confirm", img, fromCenter=False, showCrosshair=False)
409
+ x1,y1,template_w,template_h=int(r[0]),int(r[1]),int(r[2]),int(r[3])
410
+ x2=x1+template_w
411
+ y2=y1+template_h
412
+
413
+ cv2.destroyWindow("Select ROI, press ENTER to confirm")
414
+
415
+ # Crop image to get the template
416
+ # template = img[int(r[1]):int(r[1] + r[3]), int(r[0]):int(r[0] + r[2])]
417
+ template=img[y1:y2,x1:x2]
418
+ # template_h, template_w = template.shape
419
+
420
+ # Display cropped image
421
+ cv2.imshow("Template, press ENTER to confirm", template)
422
+ cv2.waitKey(0)
423
+ cv2.destroyAllWindows()
424
+ cv2.waitKey(1)
425
+
426
+ ###############################################################
427
+ # 3. Apply template matching
428
+ method = cv2.TM_CCOEFF_NORMED
429
+
430
+ print("------------------------------------------")
431
+ print("Calculating drift~")
432
+
433
+ last_top_left = (x1,y1)
434
+
435
+ last_max_val = None
436
+
437
+
438
+
439
+ with tifffile.TiffWriter(pathout2, bigtiff=True) as tif:
440
+ for i in tqdm.tqdm(range(nFrames)):
441
+ fr = stack[i]
442
+
443
+ search_area_global=fr
444
+
445
+ # Apply global template matching
446
+ res_global = cv2.matchTemplate(search_area_global, template, method)
447
+ min_val_global, max_val_global, min_loc_global, max_loc_global = cv2.minMaxLoc(res_global)
448
+
449
+ global_top_left = max_loc_global
450
+
451
+
452
+ # Define the local search area around the last known ROI position
453
+ # search_margin_local = 1 # Local search margin
454
+ x1_local=int(x1-search_margin_local)
455
+ y1_local=int(y1-search_margin_local)
456
+ x2_local=int(x1+template_w+search_margin_local)
457
+ y2_local=int(y1+template_h+search_margin_local)
458
+ search_area_local = fr[y1_local:y2_local, x1_local:x2_local]
459
+ # Apply local template matching
460
+ res_local = cv2.matchTemplate(search_area_local, template, method)
461
+ min_val_local, max_val_local, min_loc_local, max_loc_local = cv2.minMaxLoc(res_local)
462
+
463
+ local_top_left = (x1_local + max_loc_local[0], y1_local + max_loc_local[1])
464
+
465
+
466
+
467
+ # # start_x_local = max(last_top_left[0] - search_margin_local, 0)
468
+ # # start_y_local = max(last_top_left[1] - search_margin_local, 0)
469
+ # # end_x_local=last_top_left[0]+template_w+search_margin_local
470
+ # # end_y_local = last_top_left[1] +template_h + search_margin_local
471
+ # # # end_x_local = min(last_top_left[0]+template_w + search_margin_local, w)
472
+ # # # end_y_local = min(last_top_left[1] +template_h + search_margin_local, h])
473
+
474
+ # # search_area_local = fr[start_y_local:end_y_local, start_x_local:end_x_local]
475
+
476
+ # # Apply local template matching
477
+ # res_local = cv2.matchTemplate(search_area_local, template, method)
478
+ # min_val_local, max_val_local, min_loc_local, max_loc_local = cv2.minMaxLoc(res_local)
479
+
480
+ # local_top_left = (start_x_local + max_loc_local[0], start_y_local + max_loc_local[1])
481
+
482
+ # Use the local match if the match value is within the threshold of the previous match
483
+ if last_max_val is not None and max_val_local >= max_val_global * match_threshold:
484
+ top_left = (local_top_left[0] , local_top_left[1])
485
+ max_val = max_val_local
486
+ else:
487
+ top_left = (global_top_left[0], global_top_left[1])
488
+ max_val = max_val_global
489
+
490
+ TM[i, 0] = i
491
+ TM[i, 1] = top_left[0]
492
+ TM[i, 2] = top_left[1]
493
+
494
+ # Update the last known position and match value
495
+ last_top_left = top_left
496
+ last_max_val = max_val
497
+
498
+ # Draw rectangle for visualization
499
+ bottom_right = (top_left[0] + template_w, top_left[1] + template_h)
500
+ cv2.rectangle(fr, top_left, bottom_right, 255, 2)
501
+
502
+ # Periodically update the template
503
+ if i % NOF == NOF - 1:
504
+ template = fr[top_left[1]:bottom_right[1], top_left[0]:bottom_right[0]]
505
+ template_h, template_w = template.shape
506
+
507
+ if TMout:
508
+ tif.write(fr, contiguous=True)
509
+
510
+ TM[:, 1] = TM[0, 1] - TM[:, 1]
511
+ TM[:, 2] = TM[0, 2] - TM[:, 2]
512
+
513
+ ###############################################################
514
+ # 4. Apply translation matrix to movie
515
+ if TMdenoise:
516
+ TM = denoiseTM(TM, TMdenoise_window)
517
+ Mx = int(np.mean(TM[:, 1]))
518
+ My = int(np.mean(TM[:, 2]))
519
+ TM[:, 1] -= Mx
520
+ TM[:, 2] -= My
521
+
522
+ print("------------------------------------------")
523
+ print("Saving files~")
524
+
525
+ plt.plot(TM[:, 0], TM[:, 1], 'b', TM[:, 0], TM[:, 2], 'r')
526
+
527
+ if csvout:
528
+ IO.writeCSV(pathout3, TM, fmt='%1.1d')
529
+
530
+ TranslateStack(path, TM, bg=bg, extend=extend)
531
+
532
+ print("Adaptive template matching done!")
533
+ plt.show()
534
+
535
+
@@ -0,0 +1,20 @@
1
+ Metadata-Version: 2.4
2
+ Name: insituTEM
3
+ Version: 0.1.7
4
+ Author: Meng Li
5
+ Requires-Python: >=3.9
6
+ Requires-Dist: numpy
7
+ Requires-Dist: scipy
8
+ Requires-Dist: matplotlib
9
+ Requires-Dist: pandas
10
+ Requires-Dist: tifffile
11
+ Requires-Dist: tqdm
12
+ Requires-Dist: opencv-python
13
+ Requires-Dist: pillow
14
+ Requires-Dist: scikit-image
15
+ Requires-Dist: moviepy
16
+ Requires-Dist: ncempy
17
+ Requires-Dist: easygui
18
+ Requires-Dist: pystackreg
19
+ Requires-Dist: pyside6
20
+ Dynamic: author
@@ -0,0 +1,12 @@
1
+ insituTEM/__ init __.py,sha256=L4AFZSmHZkQu6J-tlqBoTJaBFltRFZ5PArhk8pmDmco,283
2
+ insituTEM/insitu_DENS.py,sha256=q2ZGbAoPPfsWbG8XlQqTdJa5_VNUNvjR9FzG2J3KkP4,10865
3
+ insituTEM/insitu_DP.py,sha256=0HMGT7j9ndpYPAgXCNGHkZeg9yJ4KI4SMCim2kiG6C0,10930
4
+ insituTEM/insitu_Diff.py,sha256=EpCMuprigdJKXaFbg9kIGZi_msKRqIDmdqvA1yofTco,11951
5
+ insituTEM/insitu_EMraw.py,sha256=O7rwdQW4STkQlYr3yImnpJX_VqjIExHgFqFIoKblYYE,15347
6
+ insituTEM/insitu_IO.py,sha256=za4ow7DPnv_YgroD_3fH12neXwYjw717w8jPzCRQvqg,25554
7
+ insituTEM/insitu_Preprocess.py,sha256=xKnHnv8dc0gTHzzEPW_DivzzEJHNFSNGRD_r7UM2l6U,12779
8
+ insituTEM/insitu_alignment.py,sha256=duH383I-jSStKhy6l7mzy9yijSl7Elf4JDFfV8ilFzM,19595
9
+ insitutem-0.1.7.dist-info/METADATA,sha256=J88Jc0obYHWJp7-89Xab0ZdsSNkDRvWIc9v-RtKTgbs,438
10
+ insitutem-0.1.7.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
11
+ insitutem-0.1.7.dist-info/top_level.txt,sha256=DEgrwrdz6iV62_cukvjFXu4dnZYupwvS41QyvTfcqjs,10
12
+ insitutem-0.1.7.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.37.1)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,13 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: insituTEM
3
- Version: 0.1.5
4
- Summary: A package of tools for processing in situ TEM data
5
- Author: Meng Li
6
- Requires-Dist: tifffile
7
- Requires-Dist: moviepy
8
- Requires-Dist: tqdm
9
- Requires-Dist: numpy
10
- Requires-Dist: opencv-python
11
- Requires-Dist: scipy
12
- Requires-Dist: matplotlib
13
-