Coverage for modules/ProjectionProcessor.py: 10%
393 statements
« prev ^ index » next coverage.py v7.0.4, created at 2023-01-10 09:27 -0600
« prev ^ index » next coverage.py v7.0.4, created at 2023-01-10 09:27 -0600
1"""
2Copyright 1999 Illinois Institute of Technology
4Permission is hereby granted, free of charge, to any person obtaining
5a copy of this software and associated documentation files (the
6"Software"), to deal in the Software without restriction, including
7without limitation the rights to use, copy, modify, merge, publish,
8distribute, sublicense, and/or sell copies of the Software, and to
9permit persons to whom the Software is furnished to do so, subject to
10the following conditions:
12The above copyright notice and this permission notice shall be
13included in all copies or substantial portions of the Software.
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18IN NO EVENT SHALL ILLINOIS INSTITUTE OF TECHNOLOGY BE LIABLE FOR ANY
19CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23Except as contained in this notice, the name of Illinois Institute
24of Technology shall not be used in advertising or otherwise to promote
25the sale, use or other dealings in this Software without prior written
26authorization from Illinois Institute of Technology.
27"""
29import copy
30import pickle
31from os.path import exists, isfile
32import numpy as np
33from lmfit import Model, Parameters
34from lmfit.models import GaussianModel, VoigtModel
35from sklearn.metrics import r2_score
36import fabio
37from musclex import __version__
38try:
39 from ..utils.file_manager import fullPath, createFolder, ifHdfReadConvertless
40 from ..utils.histogram_processor import movePeaks, getPeakInformations, convexHull
41 from ..utils.image_processor import *
42except: # for coverage
43 from utils.file_manager import fullPath, createFolder, ifHdfReadConvertless
44 from utils.histogram_processor import movePeaks, getPeakInformations, convexHull
45 from utils.image_processor import *
47class ProjectionProcessor:
48 """
49 A class for Bio-Muscle processing - go to process() to see all processing steps
50 """
51 def __init__(self, dir_path, file_name, file_list=None, extension=''):
52 self.dir_path = dir_path
53 self.filename = file_name
54 if extension in ('.hdf5', '.h5'):
55 index = next((i for i, item in enumerate(file_list[0]) if item == file_name), 0)
56 img = file_list[1][index]
57 else:
58 img = fabio.open(fullPath(dir_path, file_name)).data
59 # if img.shape[1] > img.shape[0]: # image is longer than it is wide
60 # img = cv2.copyMakeBorder(img, top=int((img.shape[1]-img.shape[0])/2), bottom=int((img.shape[1]-img.shape[0])/2), left=0, right=0, borderType=cv2.BORDER_CONSTANT)
61 # else:
62 # img = cv2.copyMakeBorder(img, top=0, bottom=0, left=int((img.shape[0]-img.shape[1])/2), right=int((img.shape[0]-img.shape[1])/2), borderType=cv2.BORDER_CONSTANT)
63 # img -= img.min()
64 self.orig_img = img
65 self.orig_img = ifHdfReadConvertless(self.filename, self.orig_img)
66 if self.orig_img.shape == (1043, 981):
67 self.img_type = "PILATUS"
68 else:
69 self.img_type = "NORMAL"
70 self.rotated_img = None
71 self.rotated = False
72 self.version = __version__
73 cache = self.loadCache()
74 self.rotMat = None # store the rotation matrix used so that any point specified in current co-ordinate system can be transformed to the base (original image) co-ordinate system
75 if cache is None:
76 # info dictionary will save all results
77 self.info = {
78 'box_names' : set(),
79 'boxes' : {},
80 'types' : {},
81 'hists' : {},
82 'peaks' : {},
83 'bgsubs' : {},
84 'hull_ranges':{},
85 'hists2': {},
86 'fit_results':{},
87 'subtracted_hists' : {},
88 'moved_peaks':{},
89 'baselines':{},
90 'centroids':{},
91 'widths': {},
92 'centerx': self.orig_img.shape[0] / 2 - 0.5,
93 'centery': self.orig_img.shape[1] / 2 - 0.5,
94 'rotationAngle' : 0
95 }
96 else:
97 self.info = cache
99 def addBox(self, name, box, typ, bgsub):
100 """
101 Add a box to info. If it exists and it changed, clear all old result
102 :param name: box name
103 :param box: box coordinates
104 :param typ: box typ 'v' ad vertical, 'h' as horizontal
105 :param bgsub: background subtraction method 0 = fitting gaussians, 1 = convex hull
106 :return:
107 """
108 box_names = self.info['box_names']
109 if name in box_names and typ =='oriented' and self.info['boxes'][name][:-1] != box[-1]:
110 self.removeInfo(name)
111 self.addBox(name, box, typ, bgsub)
112 elif name in box_names and self.info['boxes'][name] != box:
113 self.removeInfo(name)
114 self.addBox(name, box, typ, bgsub)
115 else:
116 box_names.add(name)
117 self.info['boxes'][name] = box
118 self.info['types'][name] = typ
119 self.info['bgsubs'][name] = bgsub
121 def addPeaks(self, name, peaks):
122 """
123 Add peaks to a box.
124 :param name: box name
125 :param peaks: peaks
126 :return:
127 """
128 box_names = self.info['box_names']
129 if name in box_names:
130 all_peaks = self.info['peaks']
131 if name in all_peaks and all_peaks[name] == peaks:
132 return
133 all_peaks[name] = peaks
134 skip_list = ['box_names', 'boxes', 'types', 'peaks', 'hists', 'bgsubs']
135 for k in self.info.keys():
136 if k not in skip_list:
137 self.removeInfo(name, k)
138 else:
139 print("Warning : box name is invalid.")
141 def removePeaks(self, name):
142 """
143 Remove all peaks from a box
144 :param name: box name
145 :return:
146 """
147 skip_list = ['box_names', 'boxes', 'types', 'bgsubs']
148 for k in self.info.keys():
149 if k not in skip_list:
150 self.removeInfo(name, k)
152 def process(self, settings={}):
153 """
154 All processing steps - all settings are provided by Projection Traces app as a dictionary
155 """
156 self.updateSettings(settings)
157 self.getHistograms()
158 self.applyConvexhull()
159 self.updateRotationAngle()
160 self.fitModel()
161 # self.getOtherResults()
162 self.getBackgroundSubtractedHistograms()
163 self.getPeakInfos()
164 if 'no_cache' not in settings:
165 self.cacheInfo()
167 def updateSettings(self, settings):
168 """
169 Update info dict using settings
170 :param settings: calibration settings
171 :return: -
172 """
173 if 'boxes' in settings:
174 new_boxes = settings['boxes']
175 types = settings['types']
176 bgsubs = settings['bgsubs']
177 old_boxes = self.info['boxes']
178 all_name = list(new_boxes.keys())
179 all_name.extend(list(old_boxes.keys()))
180 all_name = set(all_name)
181 for name in all_name:
182 if name in new_boxes.keys():
183 if 'refit' in settings:
184 self.removeInfo(name, 'fit_results')
185 self.addBox(name, new_boxes[name], types[name], bgsubs[name])
186 else:
187 self.removeInfo(name)
188 del settings['boxes']
189 del settings['types']
190 del settings['bgsubs']
192 if 'peaks' in settings:
193 new_peaks = settings['peaks']
194 old_peaks = self.info['peaks']
195 all_name = list(new_peaks.keys())
196 all_name.extend(list(old_peaks.keys()))
197 all_name = set(all_name)
198 for name in all_name:
199 if name in new_peaks.keys():
200 self.addPeaks(name, new_peaks[name])
201 else:
202 self.removePeaks(name)
203 del settings['peaks']
205 if 'hull_ranges' in settings:
206 new = settings['hull_ranges']
207 current = self.info['hull_ranges']
208 current.update(new)
209 del settings['hull_ranges']
211 if 'rotated' in settings:
212 self.rotated = settings['rotated']
213 else:
214 self.rotated = False
216 self.info.update(settings)
218 if 'centerx' in self.info and 'centery' in self.info:
219 if self.rotMat is not None:
220 center = (self.info['centerx'], self.info['centery'])
221 center = np.dot(cv2.invertAffineTransform(self.rotMat), [center[0], center[1], 1])
222 self.info['centerx'], self.info['centery'] = center[0], center[1]
223 self.info['orig_center'] = (center[0], center[1])
224 else:
225 self.info['centerx'] = self.orig_img.shape[0] / 2 - 0.5
226 self.info['centery'] = self.orig_img.shape[1] / 2 - 0.5
228 def getHistograms(self):
229 """
230 Obtain projected intensity for each box
231 """
232 box_names = self.info['box_names']
233 if len(box_names) > 0:
234 boxes = self.info['boxes']
235 types = self.info['types']
236 hists = self.info['hists']
237 for name in box_names:
238 t = types[name]
239 if self.rotated:
240 img = self.getRotatedImage()
241 else:
242 img = copy.copy(self.orig_img)
244 if name not in hists:
245 b = boxes[name]
247 if t == 'oriented':
248 # rotate bottom left to new origin, then get top right
249 # the box center
250 cx, cy = b[6]
251 rot_angle = b[5]
252 img = rotateImageAboutPoint(img, (cx, cy), rot_angle, self.img_type)
254 # y is shape[0], x is shape[1]?
255 x1 = np.max((int(b[0][0]), 0))
256 x2 = np.min((int(b[0][1]), img.shape[1]))
257 y1 = np.max((int(b[1][0]), 0))
258 y2 = np.min((int(b[1][1]), img.shape[0]))
260 area = img[y1:y2+1, x1:x2+1]
261 if t in ('h', 'oriented'):
262 hist = np.sum(area, axis=0)
263 else:
264 hist = np.sum(area, axis=1)
266 hists[name] = hist
268 def applyConvexhull(self):
269 """
270 Apply Convex hull to the projected intensity if background subtraction method is 1 (Convex hull)
271 :return:
272 """
273 box_names = self.info['box_names']
274 if len(box_names) > 0:
275 boxes = self.info['boxes']
276 all_peaks = self.info['peaks']
277 hists = self.info['hists']
278 bgsubs = self.info['bgsubs']
279 hists2 = self.info['hists2']
280 types = self.info['types']
281 hull_ranges = self.info['hull_ranges']
282 for name in box_names:
283 if name in hists2:
284 continue
286 if bgsubs[name] == 1 and name in all_peaks and len(all_peaks[name]) > 0:
287 # apply convex hull to the left and right if peaks are specified
288 box = boxes[name]
289 hist = hists[name]
290 peaks = all_peaks[name]
291 start_x = box[0][0]
292 start_y = box[1][0]
293 if types[name] == 'h':
294 centerX = self.info['centerx'] - start_x
295 elif types[name] == 'oriented':
296 centerX = box[6][0] - start_x
297 else:
298 centerX = self.info['centery'] - start_y
299 centerX = int(round(centerX))
300 right_hist = hist[centerX:]
301 left_hist = hist[:centerX][::-1]
302 min_len = min(len(right_hist), len(left_hist))
304 if name not in hull_ranges:
305 start = max(min(peaks) - 15, 10)
306 end = min(max(peaks) + 15, min_len)
307 hull_ranges[name] = (start, end)
309 # find start and end points
310 (start, end) = hull_ranges[name]
312 left_hull = convexHull(left_hist, start, end)[::-1]
313 right_hull = convexHull(right_hist, start, end)
315 hists2[name] = np.append(left_hull, right_hull)
316 else:
317 # use original histogram
318 hists2[name] = copy.copy(hists[name])
320 self.removeInfo(name, 'fit_results')
322 def updateRotationAngle(self):
323 """
324 Find rotation angle of the diffraction. Turn the diffraction equator to be horizontal.
325 The angle will be kept in self.info["rotationAngle"]
326 """
327 if 'rotationAngle' not in self.info:
328 center = (self.info['centerx'], self.info['centery'])
329 img = copy.copy(self.orig_img)
330 self.info['rotationAngle'] = getRotationAngle(img, center)
332 def fitModel(self):
333 """
334 Fit model to histogram
335 Fit results will be kept in self.info["fit_results"].
336 """
337 box_names = self.info['box_names']
338 all_hists = self.info['hists2']
339 bgsubs = self.info['bgsubs']
340 all_peaks = self.info['peaks']
341 all_boxes = self.info['boxes']
342 fit_results = self.info['fit_results']
344 for name in box_names:
345 hist = np.array(all_hists[name])
347 if name not in all_peaks or len(all_peaks[name]) == 0 or name in fit_results:
348 continue
350 peaks = all_peaks[name]
351 box = all_boxes[name]
352 start_x = box[0][0]
353 start_y = box[1][0]
355 x = np.arange(0, len(hist))
357 int_vars = {
358 'x' : x
359 }
361 # Initial Parameters
362 params = Parameters()
364 # Init Center X
365 if self.info['types'][name] == 'h':
366 # init_center = self.orig_img.shape[1] / 2 - 0.5 - start_x
367 init_center = self.info['centerx'] - start_x
368 elif self.info['types'][name] == 'oriented':
369 init_center = box[6][0] - start_x
370 else:
371 # init_center = self.orig_img.shape[0] / 2 - 0.5 - start_y
372 init_center = self.info['centery'] - start_y
374 init_center = int(round(init_center))
375 params.add('centerX', init_center, min=init_center - 1., max=init_center + 1.)
377 if bgsubs[name] == 1:
378 # Convex hull has been applied, so we don't need to fit 3 gaussian anymore
379 int_vars['bg_line'] = 0
380 int_vars['bg_sigma'] = 1
381 int_vars['bg_amplitude'] = 0
382 int_vars['center_sigma1'] = 1
383 int_vars['center_amplitude1'] = 0
384 int_vars['center_sigma2'] = 1
385 int_vars['center_amplitude2'] = 0
386 else:
387 # Init linear background
388 # params.add('bg_line', 0, min=0)
389 int_vars['bg_line'] = 0
391 # Init background params
392 params.add('bg_sigma', len(hist)/3., min=1, max=len(hist)*2+1.)
393 params.add('bg_amplitude', 0, min=-1, max=sum(hist)+1.)
395 # Init Meridian params1
396 params.add('center_sigma1', 15, min=1, max=len(hist)+1.)
397 params.add('center_amplitude1', sum(hist) / 20., min=-1, max=sum(hist) + 1.)
399 # Init Meridian params2
400 params.add('center_sigma2',5 , min=1, max=len(hist)+1.)
401 params.add('center_amplitude2', sum(hist) / 20., min=-1, max=sum(hist)+1.)
403 # Init peaks params
404 for j,p in enumerate(peaks):
405 params.add('p_' + str(j), p, min=p - 10., max=p + 10.)
406 params.add('sigma' + str(j), 10, min=1, max=50.)
407 params.add('amplitude' + str(j), sum(hist)/10., min=-1)
408 # params.add('gamma' + str(j), 0. , min=0., max=30)
410 # Fit model
411 model = Model(layerlineModel, nan_policy='propagate', independent_vars=int_vars.keys())
412 result = model.fit(hist, verbose=False, params=params, **int_vars)
413 if result is not None:
414 result_dict = result.values
415 int_vars.pop('x')
416 result_dict.update(int_vars)
417 result_dict['error'] = 1. - r2_score(hist, layerlineModel(x, **result_dict))
418 self.info['fit_results'][name] = result_dict
419 self.removeInfo(name, 'subtracted_hists')
420 print("Box : "+ str(name))
421 print("Fitting Result : " + str(self.info['fit_results'][name]))
422 print("Fitting Error : " + str(self.info['fit_results'][name]['error']))
423 print("---")
426 def getBackgroundSubtractedHistograms(self):
427 """
428 Get Background Subtracted Histograms by subtract the original histogram by background from fitting model
429 :return:
430 """
431 box_names = self.info['box_names']
432 all_hists = self.info['hists2']
433 fit_results = self.info['fit_results']
434 subt_hists = self.info['subtracted_hists']
435 bgsubs = self.info['bgsubs']
436 for name in box_names:
437 if name in subt_hists or name not in fit_results:
438 continue
439 if bgsubs[name] == 2: # no background, so there should be no subtraction
440 subt_hists[name] = all_hists[name]
441 self.removeInfo(name, 'moved_peaks')
442 else:
443 # Get subtracted histogram if fit result exists
444 fit_result = fit_results[name]
445 hist = all_hists[name]
446 xs = np.arange(0, len(hist))
447 background = layerlineModelBackground(xs, **fit_result)
448 subt_hists[name] = hist-background
449 self.removeInfo(name, 'moved_peaks')
451 def getPeakInfos(self):
452 """
453 Get peaks' infomation including baseline and centroids
454 :return:
455 """
456 box_names = self.info['box_names']
457 all_hists = self.info['subtracted_hists']
458 fit_results = self.info['fit_results']
459 moved_peaks = self.info['moved_peaks']
460 all_baselines = self.info['baselines']
461 all_centroids = self.info['centroids']
462 all_widths = self.info['widths']
464 for name in box_names:
465 if name not in all_hists:
466 continue
468 ### Find real peak locations in the box (not distance from center)
469 model = fit_results[name]
470 hist = all_hists[name]
471 if name not in moved_peaks:
472 peaks = self.info['peaks'][name]
473 moved = []
474 i = 0
475 for p in peaks:
476 globalpeak = int(round(model['centerX']+p))
477 if globalpeak <= len(hist):
478 moved.append(globalpeak)
479 else:
480 moved.append(int(round(model['centerX']-p)))
481 i+=1
482 moved = movePeaks(hist, moved, 10)
483 moved_peaks[name] = moved
484 self.removeInfo(name, 'baselines')
486 peaks = moved_peaks[name]
488 ### Calculate Baselines
489 if name not in all_baselines:
490 baselines = []
491 for p in peaks:
492 baselines.append(hist[p]*0.5)
493 all_baselines[name] = baselines
494 self.removeInfo(name, 'centroids')
496 baselines = all_baselines[name]
498 if name not in all_centroids:
499 results = getPeakInformations(hist, peaks, baselines)
500 all_centroids[name] = results['centroids'] - model['centerX']
501 all_widths[name] = results['widths']
503 def setBaseline(self, box_name, peak_num, new_baseline):
504 """
505 Change baseline and clear centroid and width for the specific box and peak
506 :param box_name: box name (str)
507 :param peak_num: peak name (int)
508 :param new_baseline: new baseline value or percentage (str)
509 :return:
510 """
511 new_baseline = str(new_baseline)
512 baselines = self.info['baselines'][box_name]
513 peak = self.info['moved_peaks'][box_name][peak_num]
514 hist = self.info['subtracted_hists'][box_name]
515 height = hist[peak]
516 if "%" in new_baseline:
517 # if new_baseline contain "%", baseline value will use this as percent of peak height
518 percent = float(new_baseline.rstrip("%"))
519 baseline = height * percent / 100.
520 elif len(new_baseline) == 0:
521 # if new_baseline is empty, baseline will by half-height
522 baseline = float(height * .5)
523 else:
524 baseline = float(new_baseline)
526 if height > baseline:
527 baselines[peak_num] = baseline
528 self.removeInfo(box_name, 'centroids')
529 self.removeInfo(box_name, 'widths')
531 def getRotatedImage(self, img=None, angle=None):
532 """
533 Get rotated image by angle. If the input params are not specified. image = original input image, angle = self.info["rotationAngle"]
534 :param img: input image
535 :param angle: rotation angle
536 :return: rotated image
537 """
538 if img is None:
539 img = copy.copy(self.orig_img)
540 if angle is None:
541 angle = self.info['rotationAngle']
542 if '90rotation' in self.info and self.info['90rotation'] is True:
543 angle = angle - 90 if angle > 90 else angle + 90
545 if self.rotated_img is None or self.rotated_img[0] != (self.info["centerx"], self.info["centery"]) or self.rotated_img[1] != self.info["rotationAngle"] or (self.rotated_img[2] != img).any():
546 # encapsulate rotated image for using later as a list of [center, angle, original image, rotated image[
547 center = (self.info["centerx"], self.info["centery"])
548 if "orig_center" in self.info:
549 center = self.info["orig_center"]
550 else:
551 self.info["orig_center"] = center
553 rotImg, (self.info["centerx"], self.info["centery"]), self.rotMat = rotateImage(img, center, angle, self.img_type)
554 self.rotated_img = [(self.info["centerx"], self.info["centery"]), angle, img, rotImg]
556 return self.rotated_img[3]
558 def removeInfo(self, name, k=None):
559 """
560 Remove information from info dictionary by k as a key. If k is None, remove all information in the dictionary
561 :param name: box name
562 :param k: key of dictionary
563 :return: -
564 """
565 if k is not None and k in self.info:
566 d = self.info[k]
567 if isinstance(d, dict) and name in d:
568 del d[name]
570 if k is None:
571 keys = list(self.info.keys())
572 for key in keys:
573 d = self.info[key]
574 if key == 'box_names':
575 d.remove(name)
576 else:
577 self.removeInfo(name, key)
579 def loadCache(self):
580 """
581 Load info dict from cache. Cache file will be filename.info in folder "pt_cache"
582 :return: cached info (dict)
583 """
584 cache_path = fullPath(self.dir_path, "pt_cache")
585 cache_file = fullPath(cache_path, self.filename + '.info')
586 if exists(cache_path) and isfile(cache_file):
587 cinfo = pickle.load(open(cache_file, "rb"))
588 if cinfo is not None:
589 if cinfo['program_version'] == self.version:
590 return cinfo
591 print("Cache version " + cinfo['program_version'] + " did not match with Program version " + self.version)
592 print("Invalidating cache and reprocessing the image")
593 return None
595 def cacheInfo(self):
596 """
597 Save info dict to cache. Cache file will be save as filename.info in folder "pt_cache"
598 :return: -
599 """
600 cache_path = fullPath(self.dir_path, 'pt_cache')
601 createFolder(cache_path)
602 cache_file = fullPath(cache_path, self.filename + '.info')
604 self.info["program_version"] = self.version
605 pickle.dump(self.info, open(cache_file, "wb"))
608def layerlineModel(x, centerX, bg_line, bg_sigma, bg_amplitude, center_sigma1, center_amplitude1,
609 center_sigma2, center_amplitude2, **kwargs):
610 """
611 Model for fitting layer line pattern
612 :param x: x axis
613 :param centerX: center of x axis
614 :param bg_line: linear background
615 :param bg_sigma: background sigma
616 :param bg_amplitude: background amplitude
617 :param center_sigma1: meridian background sigma
618 :param center_amplitude1: meridian background amplitude
619 :param center_sigma2: meridian sigma
620 :param center_amplitude2: meridian amplitude
621 :param kwargs: other peaks properties
622 :return:
623 """
624 #### Background and Meridian
625 result = layerlineModelBackground(x, centerX, bg_line, bg_sigma, bg_amplitude, center_sigma1, center_amplitude1, center_sigma2, center_amplitude2,**kwargs)
626 #### Other peaks
627 i = 0
628 while 'p_'+str(i) in kwargs:
629 p = kwargs['p_'+str(i)]
630 sigma = kwargs['sigma'+str(i)]
631 amplitude = kwargs['amplitude' + str(i)]
632 if 'gamma' + str(i) in kwargs:
633 gamma = kwargs['gamma' + str(i)]
635 mod = VoigtModel()
636 result += mod.eval(x=x, amplitude=amplitude, center=centerX + p, sigma=sigma, gamma=gamma)
637 result += mod.eval(x=x, amplitude=amplitude, center=centerX - p, sigma=sigma, gamma=-gamma)
638 else:
639 mod = GaussianModel()
640 result += mod.eval(x=x, amplitude=amplitude, center=centerX + p, sigma=sigma)
641 result += mod.eval(x=x, amplitude=amplitude, center=centerX - p, sigma=sigma)
643 i += 1
644 return result
646def layerlineModelBackground(x, centerX, bg_line, bg_sigma, bg_amplitude, center_sigma1, center_amplitude1,
647 center_sigma2, center_amplitude2,**kwargs):
648 """
649 Model for fitting layer line pattern
650 :param x: x axis
651 :param centerX: center of x axis
652 :param bg_line: linear background
653 :param bg_sigma: background sigma
654 :param bg_amplitude: background amplitude
655 :param center_sigma1: meridian background sigma
656 :param center_amplitude1: meridian background amplitude
657 :param center_sigma2: meridian sigma
658 :param center_amplitude2: meridian amplitude
659 :param kwargs: nothing
660 :return:
661 """
662 return layerlineBackground(x, centerX, bg_line, bg_sigma, bg_amplitude) + \
663 meridianBackground(x, centerX, center_sigma1, center_amplitude1) + \
664 meridianGauss(x, centerX, center_sigma2, center_amplitude2)
667def layerlineBackground(x, centerX, bg_line, bg_sigma, bg_amplitude, **kwargs):
668 """
669 Model for largest background of layer line pattern
670 :param x: x axis
671 :param centerX: center of x axis
672 :param bg_line: linear background
673 :param bg_sigma: background sigma
674 :param bg_amplitude: background amplitude
675 :param kwargs: nothing
676 :return:
677 """
678 mod = GaussianModel()
679 return mod.eval(x=x, amplitude=bg_amplitude, center=centerX, sigma=bg_sigma) + bg_line
681def meridianBackground(x, centerX, center_sigma1, center_amplitude1, **kwargs):
682 """
683 Model for background of meridian of layer line pattern
684 :param x: x axis
685 :param centerX: center of x axis
686 :param center_sigma1: meridian background sigma
687 :param center_amplitude1: meridian background amplitude
688 :param kwargs: nothing
689 :return:
690 """
691 mod = GaussianModel()
692 return mod.eval(x=x, amplitude=center_amplitude1, center=centerX, sigma=center_sigma1)
694def meridianGauss(x, centerX, center_sigma2, center_amplitude2, **kwargs):
695 """
696 Model for background of layer line pattern
697 :param x: x axis
698 :param centerX: center of x axis
699 :param center_sigma2: meridian sigma
700 :param center_amplitude2: meridian amplitude
701 :param kwargs:
702 :return:
703 """
704 mod = GaussianModel()
705 return mod.eval(x=x, amplitude=center_amplitude2, center=centerX, sigma=center_sigma2)