def getRings(self): """ Returns polygons of rings :returns: List of ring angle with the associated polygon :rtype: List[Tuple[float,List[numpy.ndarray]]] """ tth = self.__geoRef.twoThetaArray(self.__peakPicker.shape) result = collections.OrderedDict() tth_max = tth.max() tth_min = tth.min() if not self.__calibrant: return result angles = [ i for i in self.__calibrant.get_2th() if (i is not None) and (i >= tth_min) and (i <= tth_max) ] if len(angles) == 0: return result ms = marchingsquares.MarchingSquaresMergeImpl(tth, self.__mask, use_minmax_cache=True) rings = [] for angle in angles: polygons = ms.find_contours(angle) rings.append((angle, polygons)) return rings
def update(self, calibration): """Update the state from a current calibration process. :param RingCalibration calibration: A calibration process """ mask = calibration.getMask() self.__geoRef = calibration.getPyfaiGeometry() self.__geometry = None self.__rings = calibration.getRings() self.__previousRms = self.__rms self.__rms = calibration.getRms() tth = calibration.getTwoThetaArray() # Make sure there is no more copy self.__tth = numpy.ascontiguousarray(tth) self.__poni = calibration.getPoni() self.__beamCenter = calibration.getBeamCenter() self.__empty = False ms = marchingsquares.MarchingSquaresMergeImpl(tth, mask, use_minmax_cache=True) self.__ms = ms self.__ringPolygons = {} self.changed.emit()
def extract(self, peaks, method="massif", maxRings=None, pointPerDegree=1.0): """ Performs an automatic keypoint extraction: Can be used in recalib or in calib after a first calibration has been performed. # FIXME pts_per_deg """ fixed = pyFAI.utils.FixedParameters() fixed.add("wavelength") geoRef = self.__createGeoRef(peaks, fixed=fixed) self.__geoRef = geoRef peakPicker = PeakPicker(data=self.__image, mask=self.__mask, calibrant=self.__calibrant, wavelength=self.__wavelength, detector=self.__detector, method=method) peakPicker.reset() peakPicker.init(method, False) # if geoRef: # ai.setPyFAI(**geoRef.getPyFAI()) tth = numpy.array( [i for i in self.__calibrant.get_2th() if i is not None]) tth = numpy.unique(tth) tth_min = numpy.zeros_like(tth) tth_max = numpy.zeros_like(tth) delta = (tth[1:] - tth[:-1]) / 4.0 tth_max[:-1] = delta tth_max[-1] = delta[-1] tth_min[1:] = -delta tth_min[0] = -delta[0] tth_max += tth tth_min += tth ttha = geoRef.get_ttha() chia = geoRef.get_chia() if (ttha is None) or (ttha.shape != peakPicker.data.shape): ttha = geoRef.twoThetaArray(peakPicker.data.shape) if (chia is None) or (chia.shape != peakPicker.data.shape): chia = geoRef.chiArray(peakPicker.data.shape) rings = 0 peakPicker.sync_init() if maxRings is None: maxRings = tth.size ms = marchingsquares.MarchingSquaresMergeImpl(ttha, self.__mask, use_minmax_cache=True) for i in range(tth.size): if rings >= maxRings: break mask = numpy.logical_and(ttha >= tth_min[i], ttha < tth_max[i]) # if self.mask is not None: # mask = numpy.logical_and(mask, numpy.logical_not(self.mask)) size = mask.sum(dtype=int) if (size > 0): rings += 1 peakPicker.massif_contour(mask) # if self.gui: # update_fig(self.peakPicker.fig) sub_data = peakPicker.data.ravel()[numpy.where(mask.ravel())] mean = sub_data.mean(dtype=numpy.float64) std = sub_data.std(dtype=numpy.float64) upper_limit = mean + std mask2 = numpy.logical_and(peakPicker.data > upper_limit, mask) size2 = mask2.sum(dtype=int) if size2 < 1000: upper_limit = mean mask2 = numpy.logical_and(peakPicker.data > upper_limit, mask) size2 = mask2.sum() # length of the arc: # Coords in points are y, x points = ms.find_pixels(tth[i]) seeds = set((i[0], i[1]) for i in points if mask2[i[0], i[1]]) # max number of points: 360 points for a full circle azimuthal = chia[points[:, 0].clip(0, peakPicker.data.shape[0]), points[:, 1].clip(0, peakPicker.data.shape[1])] nb_deg_azim = numpy.unique( numpy.rad2deg(azimuthal).round()).size keep = int(nb_deg_azim * pointPerDegree) if keep == 0: continue dist_min = len(seeds) / 2.0 / keep # why 3.0, why not ? msg = "Extracting datapoint for ring %s (2theta = %.2f deg); "\ "searching for %i pts out of %i with I>%.1f, dmin=%.1f" _logger.info(msg, i, numpy.degrees(tth[i]), keep, size2, upper_limit, dist_min) _res = peakPicker.peaks_from_area(mask=mask2, Imin=upper_limit, keep=keep, method=method, ring=i, dmin=dist_min, seed=seeds) # self.peakPicker.points.save(self.basename + ".npt") # if self.weighted: # self.data = self.peakPicker.points.getWeightedList(self.peakPicker.data) # else: # self.data = peakPicker.points.getList() return peakPicker.points.getList()
def extract_cp(self, max_rings=None, pts_per_deg=1.0, Imin=0): """Performs an automatic keypoint extraction and update the geometry refinement part :param max_ring: extract at most N rings from the image :param pts_per_deg: number of control points per azimuthal degree (increase for better precision) """ if self.massif is None: self.massif = Massif(self.image) tth = numpy.array( [i for i in self.calibrant.get_2th() if i is not None]) tth = numpy.unique(tth) tth_min = numpy.zeros_like(tth) tth_max = numpy.zeros_like(tth) delta = (tth[1:] - tth[:-1]) / 4.0 tth_max[:-1] = delta tth_max[-1] = delta[-1] tth_min[1:] = -delta tth_min[0] = -delta[0] tth_max += tth tth_min += tth shape = self.image.shape ttha = self.geometry_refinement.twoThetaArray(shape) chia = self.geometry_refinement.chiArray(shape) rings = 0 cp = ControlPoints(calibrant=self.calibrant) if max_rings is None: max_rings = tth.size ms = marchingsquares.MarchingSquaresMergeImpl( ttha, mask=self.geometry_refinement.detector.mask, use_minmax_cache=True) for i in range(tth.size): if rings >= max_rings: break mask = numpy.logical_and(ttha >= tth_min[i], ttha < tth_max[i]) if self.detector.mask is not None: mask = numpy.logical_and( mask, numpy.logical_not(self.geometry_refinement.detector.mask)) size = mask.sum(dtype=int) if (size > 0): rings += 1 sub_data = self.image.ravel()[numpy.where(mask.ravel())] mean = sub_data.mean(dtype=numpy.float64) std = sub_data.std(dtype=numpy.float64) upper_limit = mean + std mask2 = numpy.logical_and(self.image > upper_limit, mask) size2 = mask2.sum(dtype=int) if size2 < 1000: upper_limit = mean mask2 = numpy.logical_and(self.image > upper_limit, mask) size2 = mask2.sum() # length of the arc: points = ms.find_pixels(tth[i]) seeds = set((i[0], i[1]) for i in points if mask2[i[0], i[1]]) # max number of points: 360 points for a full circle azimuthal = chia[points[:, 0].clip(0, shape[0]), points[:, 1].clip(0, shape[1])] nb_deg_azim = numpy.unique( numpy.rad2deg(azimuthal).round()).size keep = int(nb_deg_azim * pts_per_deg) if keep == 0: continue dist_min = len(seeds) / 2.0 / keep # why 3.0, why not ? logger.info( "Extracting datapoint for ring %s (2theta = %.2f deg); " + "searching for %i pts out of %i with I>%.1f, dmin=%.1f", i, numpy.degrees(tth[i]), keep, size2, upper_limit, dist_min) res = self.massif.peaks_from_area(mask2, Imin=Imin, keep=keep, dmin=dist_min, seed=seeds, ring=i) cp.append(res, i) self.control_points = cp self.geometry_refinement.data = numpy.asarray(cp.getList(), dtype=numpy.float64) return cp
def _extract(self, peaks=None, geometryModel=None): """ Performs an automatic keypoint extraction: Can be used in recalib or in calib after a first calibration has been performed. :param List[int] ringNumbers: If set, extraction will only be done on rings number contained in this list (the number 0 identify the first ring) """ assert (numpy.logical_xor(peaks is not None, geometryModel is not None)) method = "massif" maxRings = self.__maxRings ringNumbers = self.__ringNumbers pointPerDegree = self.__pointPerDegree if ringNumbers is not None: ringNumbers = set(ringNumbers) if peaks is not None: # Energy from from experiment settings wavelength = self.__wavelength self.__calibrant.setWavelength_change2th(wavelength) geoRef = self.__createGeoRefFromPeaks(peaks) elif geometryModel is not None: # Fitted energy assert (geometryModel.isValid()) wavelength = geometryModel.wavelength().value() self.__calibrant.setWavelength_change2th(wavelength) geoRef = self.__createGeoRefFromGeometry(geometryModel) self.__geoRef = geoRef peakPicker = PeakPicker(data=self.__image, mask=self.__mask, calibrant=self.__calibrant, wavelength=wavelength, detector=self.__detector, method=method) peakPicker.reset() peakPicker.init(method, False) tth = numpy.array( [i for i in self.__calibrant.get_2th() if i is not None]) tth = numpy.unique(tth) tth_min = numpy.zeros_like(tth) tth_max = numpy.zeros_like(tth) delta = (tth[1:] - tth[:-1]) / 4.0 tth_max[:-1] = delta tth_max[-1] = delta[-1] tth_min[1:] = -delta tth_min[0] = -delta[0] tth_max += tth tth_min += tth ttha = geoRef.get_ttha() chia = geoRef.get_chia() if (ttha is None) or (ttha.shape != peakPicker.data.shape): ttha = geoRef.twoThetaArray(peakPicker.data.shape) if (chia is None) or (chia.shape != peakPicker.data.shape): chia = geoRef.chiArray(peakPicker.data.shape) rings = 0 peakPicker.sync_init() if maxRings is None: maxRings = tth.size ms = marchingsquares.MarchingSquaresMergeImpl(ttha, self.__mask, use_minmax_cache=True) for i in range(tth.size): if ringNumbers is not None: if i not in ringNumbers: continue if rings >= maxRings: break mask = numpy.logical_and(ttha >= tth_min[i], ttha < tth_max[i]) size = mask.sum(dtype=int) if (size > 0): rings += 1 self._updateProcessingLocation(mask) sub_data = peakPicker.data.ravel()[numpy.where(mask.ravel())] mean = sub_data.mean(dtype=numpy.float64) std = sub_data.std(dtype=numpy.float64) upper_limit = mean + std mask2 = numpy.logical_and(peakPicker.data > upper_limit, mask) size2 = mask2.sum(dtype=int) if size2 < 1000: upper_limit = mean mask2 = numpy.logical_and(peakPicker.data > upper_limit, mask) size2 = mask2.sum() # Coords in points are y, x points = ms.find_pixels(tth[i]) seeds = set((i[0], i[1]) for i in points if mask2[i[0], i[1]]) # Max number of points: 360 points for a full circle azimuthal = chia[points[:, 0].clip(0, peakPicker.data.shape[0]), points[:, 1].clip(0, peakPicker.data.shape[1])] nb_deg_azim = numpy.unique( numpy.rad2deg(azimuthal).round()).size keep = int(nb_deg_azim * pointPerDegree) if keep == 0: continue dist_min = len(seeds) / 2.0 / keep # why 3.0, why not ? msg = "Extracting datapoint for ring %s (2theta = %.2f deg); "\ "searching for %i pts out of %i with I>%.1f, dmin=%.1f" _logger.info(msg, i, numpy.degrees(tth[i]), keep, size2, upper_limit, dist_min) _res = peakPicker.peaks_from_area(mask=mask2, Imin=upper_limit, keep=keep, method=method, ring=i, dmin=dist_min, seed=seeds) return peakPicker.points.getList()