From 6283abbc560baa89d34c73aa2a98524c7403caac Mon Sep 17 00:00:00 2001 From: arsadri Date: Tue, 1 Aug 2023 13:48:26 +1000 Subject: [PATCH] image_by_windows for fitBackground --- RobustGaussianFittingLibrary/basic.py | 118 ++++++++++++++++---------- RobustGaussianFittingLibrary/misc.py | 108 +++++++++++++++++++++++ setup.cfg | 2 +- setup.py | 2 +- 4 files changed, 181 insertions(+), 49 deletions(-) diff --git a/RobustGaussianFittingLibrary/basic.py b/RobustGaussianFittingLibrary/basic.py index a61fceb..6f4c4ef 100644 --- a/RobustGaussianFittingLibrary/basic.py +++ b/RobustGaussianFittingLibrary/basic.py @@ -449,7 +449,8 @@ def fitBackground(inImage, stretch2CornersOpt = 0, numModelParams = 4, optIters = 12, - numStrides = 0, + numStrides = None, + skip = (1, 1), minimumResidual = 0): """ fit a plane to the background of the image uainf convolving the window by number of strides and calculate the value of the background plane and STD at the location of each pixel. @@ -498,56 +499,80 @@ def fitBackground(inImage, if(inMask is None): inMask = np.ones((inImage.shape[0], inImage.shape[1]), dtype='int8') - if(winX is None): + n_R = inImage.shape[0] + n_C = inImage.shape[1] + + if ((winX is None) & (winY is None)): winX = inImage.shape[0] - if(winY is None): winY = inImage.shape[1] + bckParam = np.zeros((2, n_R, n_C), dtype='float32') + RGFCLib.RSGImage(inImage.astype('float32'), + inMask, + bckParam, + winX, + winY, + inImage.shape[0], + inImage.shape[1], + likelyRatio, + certainRatio, + MSSE_LAMBDA, + stretch2CornersOpt, + numModelParams, + optIters, + minimumResidual) + return(bckParam) + else: + if(winX is None): + winX = inImage.shape[0] + if(winY is None): + winY = inImage.shape[1] - n_R = inImage.shape[0] - n_C = inImage.shape[1] + if(numStrides is None): + skip = skip + else: + numStrides = int(numStrides) + if(numStrides<=0): + skip = (winX, winY) + else: + skip = (winX // numStrides, winY // numStrides) - bckParam = np.zeros((2, n_R, n_C), dtype='float32') - RGFCLib.RSGImage(inImage.astype('float32'), - inMask, - bckParam, - winX, - winY, - inImage.shape[0], - inImage.shape[1], - likelyRatio, - certainRatio, - MSSE_LAMBDA, - stretch2CornersOpt, - numModelParams, - optIters, - minimumResidual) + from .misc import image_by_windows + imbywin = image_by_windows(inImage.shape, (winX, winY), skip) + inImage_Tensor = imbywin.image2views(inImage) + inMask_Tensor = imbywin.image2views(inMask) + + winX = inImage_Tensor.shape[1] + winY = inImage_Tensor.shape[2] + + n_F = inImage_Tensor.shape[0] + n_R = inImage_Tensor.shape[1] + n_C = inImage_Tensor.shape[2] + + model_mean = np.zeros(inImage_Tensor.shape, dtype='float32') + model_std = np.zeros(inImage_Tensor.shape, dtype='float32') + RGFCLib.RSGImage_by_Image_Tensor(inImage_Tensor.astype('float32'), + inMask_Tensor.astype('int8'), + model_mean, + model_std, + winX, + winY, + inImage_Tensor.shape[0], + inImage_Tensor.shape[1], + inImage_Tensor.shape[2], + likelyRatio, + certainRatio, + MSSE_LAMBDA, + stretch2CornersOpt, + numModelParams, + optIters, + minimumResidual) - _sums = np.ones((2, n_R, n_C), dtype='int8') - if(numStrides>1): - wSDListRows = np.linspace(0, winX, numStrides+2, dtype='int8')[1:-1] - wSDListClms = np.linspace(0, winY, numStrides+2, dtype='int8')[1:-1] - for wSDRow in wSDListRows: - for wSDClm in wSDListClms: - _inImage = inImage[wSDRow:n_R-winX+wSDRow ,wSDClm:n_C-winY+wSDClm].copy() - _inMask = inMask[wSDRow:n_R-winX+wSDRow ,wSDClm:n_C-winY+wSDClm].copy() - modelParamsMap = np.zeros((2, _inImage.shape[0], _inImage.shape[1]), dtype='float32') - RGFCLib.RSGImage(_inImage.astype('float32'), - _inMask, - modelParamsMap, - winX, - winY, - _inImage.shape[0], - _inImage.shape[1], - likelyRatio, - certainRatio, - MSSE_LAMBDA, - stretch2CornersOpt, - numModelParams, - optIters, - minimumResidual) - bckParam[:,wSDRow:n_R-winX+wSDRow ,wSDClm:n_C-winY+wSDClm] += modelParamsMap - _sums[:,wSDRow:n_R-winX+wSDRow ,wSDClm:n_C-winY+wSDClm] += 1 - return(bckParam / _sums) + model_mean = imbywin.views2image(model_mean) + model_std = imbywin.views2image(model_std) + bckParam = np.concatenate((np.array([model_mean]), + np.array([model_std])), axis = 0) + + return(bckParam) def fitBackgroundTensor(inImage_Tensor, inMask_Tensor = None, @@ -885,7 +910,6 @@ def fitBackgroundCylindrically(inTensor, else: return(bckParam/_sums) - def fitValue_by_meanShift(inVec, minSNR = 3.0, MS_numIter = 8): MS_mu = inVec.mean() MS_std = inVec.std() diff --git a/RobustGaussianFittingLibrary/misc.py b/RobustGaussianFittingLibrary/misc.py index 8d2acf5..f59b113 100644 --- a/RobustGaussianFittingLibrary/misc.py +++ b/RobustGaussianFittingLibrary/misc.py @@ -406,6 +406,114 @@ def getTriangularVertices(n, return(triVecs) +class image_by_windows: + def __init__(self, + img_shape: tuple[int, int], + win_shape: tuple[int, int], + skip: tuple[int, int] = (1, 1), + method = 'linear'): + """image by windows + + I am using OOP here because the user pretty much always wants to + transform results back to the original shape. It is different + from typical transforms, where the processing ends at the other + space. + + Parameters + ---------- + :param img_shape: + pass your_data.shape. First two dimensions should be for the + image to be cropped. + :param win_shape: + the cropping windows shape + :param skip: + The skipping length of windows + :param method: + default is linear, it means that if it cannot preserve the skip + it will not, but the grid will be spread evenly among windows. + If you wish to keep the skip exact, choose fixed. If the size + of the image is not dividable by the skip, it will have to + change the location of last window such that the entire image + is covered. This emans that the location of the grid will be + moved to the left. + """ + self.img_shape = img_shape + self.win_shape = win_shape + self.skip = skip + + n_r, n_c = img_shape[:2] + + if(method == 'fixed'): + rows = np.arange(0, n_r - win_shape[0] + 1, skip[0]) + clms = np.arange(0, n_c - win_shape[1] + 1, skip[1]) + if rows[-1] < n_r - win_shape[0]: + rows = np.concatenate((rows, np.array([n_r - win_shape[0]]))) + if clms[-1] < n_c - win_shape[1]: + clms = np.concatenate((clms, np.array([n_c - win_shape[1]]))) + if(method == 'linear'): + rows = np.linspace( + 0, n_r - win_shape[0],n_r // skip[0], dtype = 'int') + rows = np.unique(rows) + clms = np.linspace( + 0, n_c - win_shape[1],n_r // skip[1], dtype = 'int') + clms = np.unique(clms) + + grid_clms, grid_rows = np.meshgrid(clms, rows) + + self.grid = np.array([grid_rows.ravel(), grid_clms.ravel()]).T + self.visited = np.zeros(self.img_shape, dtype='int') + for grc in self.grid: + self.visited[grc[0]:grc[0] + self.win_shape[0], + grc[1]:grc[1] + self.win_shape[1]] += 1 + self.n_pts = self.grid.shape[0] + + def image2views(self, img): + all_other_dims = () + if (len(self.img_shape)>2): + all_other_dims = self.img_shape[2:] + + viewed = np.zeros( + (self.grid.shape[0], self.win_shape[0], + self.win_shape[1]) + all_other_dims, + dtype = img.dtype) + for gcnt, grc in enumerate(self.grid): + gr, gc = grc + viewed[gcnt] = img[ + gr:gr + self.win_shape[0], gc:gc + self.win_shape[1]] + return viewed + + def views2image(self, viewed, method = 'linear'): + if(method == 'linear'): + img = np.zeros(self.img_shape, dtype = 'float') + for gcnt, grc in enumerate(self.grid): + gr, gc = grc + img[gr:gr + self.win_shape[0], gc:gc + self.win_shape[1]] += \ + viewed[gcnt] + img[self.visited>0, ...] = \ + img[self.visited>0, ...] / self.visited[self.visited>0] + img = img.astype(viewed.dtype) + else: + img = np.zeros( + (self.win_shape[0]*self.win_shape[1],) + self.img_shape, + viewed.dtype) + visited = np.zeros( + (self.win_shape[0] * self.win_shape[1], + self.img_shape[0], self.img_shape[1]), dtype='int') + for gcnt, grc in enumerate(self.grid): + gr, gc = grc + + level2use = visited[ + :, gr:gr + self.win_shape[0], + gc:gc + self.win_shape[1]].max(2).max(1) + level = np.where(level2use == 0)[0][0] + + img[level, gr:gr + self.win_shape[0], gc:gc + self.win_shape[1]] += \ + viewed[gcnt] + visited[level, + gr:gr + self.win_shape[0], gc:gc + self.win_shape[1]] = 1 + if(method == 'max'): + img = img.max(0).squeeze() + return img ################# #TO DOL diff --git a/setup.cfg b/setup.cfg index 995245e..052bddf 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,7 +2,7 @@ description-file = README.md [bumpversion] -current_version = 0.1.35 +current_version = 0.2.4 commit = True tag = True diff --git a/setup.py b/setup.py index 4e3876d..d998aca 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ from setuptools import setup from setuptools import Extension from platform import system as platform_system -_version = '0.2.4' +_version = '0.2.5' with open('README.md') as readme_file: readme = readme_file.read()