def flatFieldFromCalibration(bgImages, images, calcStd=False):
    '''
    returns a flat-field correction map 
    through conditional average of multiple images reduced by a background image
    
    calcStd -> set to True to also return the standard deviation
    '''
    #AVERAGE BACKGROUND IMAGES IF MULTIPLE ARE GIVEN:
    if (type(bgImages) in (tuple, list)
            or type(bgImages) is np.ndarray and bgImages.ndim == 3):
        if len(bgImages) > 1:
            avgBg = averageSameExpTimes(bgImages)
        else:
            avgBg = imread(bgImages[0])
    else:
        avgBg = imread(bgImages)

    i0 = imread(images[0]) - avgBg
    noise_level_function, _ = oneImageNLF(i0)

    m = MaskedMovingAverage(shape=i0.shape, calcVariance=calcStd)
    m.update(i0)

    for i in images[1:]:
        i = imread(i)
        thresh = m.avg - noise_level_function(m.avg) * 3
        m.update(i, i > thresh)

    mx = m.avg.max()
    if calcStd:
        return m.avg / mx, m.var**0.5 / mx
    return m.avg / mx
    def _correctDarkCurrent(self, image, exposuretime, bgImages, date):
        '''
        open OR calculate a background image: f(t)=m*t+n
        '''
        # either exposureTime or bgImages has to be given
        #         if exposuretime is not None or bgImages is not None:
        print('... remove dark current')

        if bgImages is not None:

            if (type(bgImages) in (list, tuple) or
                (isinstance(bgImages, np.ndarray) and bgImages.ndim == 3)):
                if len(bgImages) > 1:
                    # if multiple images are given: do STE removal:
                    nlf = self.noise_level_function
                    bg = SingleTimeEffectDetection(
                        bgImages, nStd=4, noise_level_function=nlf).noSTE
                else:
                    bg = imread(bgImages[0])
            else:
                bg = imread(bgImages)
        else:
            bg = self.calcDarkCurrent(exposuretime, date)
        self.temp['bg'] = bg
        image -= bg
    def __init__(self,
                 images,
                 noise_level_function=None,
                 nStd=4,
                 save_ste_indices=False,
                 calcVariance=False,
                 dtype=float):
        self.save_ste_indices = save_ste_indices

        i1 = imread(images[0], 'gray', dtype=dtype)
        i2 = imread(images[1], 'gray')

        self.mask_STE = None
        if save_ste_indices:
            self.mask_STE = np.zeros(shape=i1.shape, dtype=bool)

        self.mma = MaskedMovingAverage(shape=i1.shape,
                                       calcVariance=calcVariance,
                                       dtype=i1.dtype)

        # MINIMUM OF BOTH IMAGES:
        self.mma.update(np.min((i1, i2), axis=0))

        if noise_level_function is None:
            noise_level_function = oneImageNLF(self.mma.avg)[0]
        self.noise_level_function = noise_level_function
        self.threshold = noise_level_function(self.mma.avg) * nStd

        self.addImage(np.max((i1, i2), axis=0))

        for i in images[2:]:
            self.addImage(imread(i, 'gray'))
def flatFieldFromCalibration(bgImages, images, calcStd=False):
    '''
    returns a flat-field correction map 
    through conditional average of multiple images reduced by a background image
    
    calcStd -> set to True to also return the standard deviation
    '''
    #AVERAGE BACKGROUND IMAGES IF MULTIPLE ARE GIVEN:
    if ( type(bgImages) in (tuple, list) 
            or type(bgImages) is np.ndarray and bgImages.ndim == 3 ) :
        if len(bgImages) > 1:
            avgBg = averageSameExpTimes(bgImages)
        else:
            avgBg = imread(bgImages[0])
    else:
        avgBg = imread(bgImages)

    i0 = imread(images[0]) - avgBg
    noise_level_function,_ = oneImageNLF(i0)

    m = MaskedMovingAverage(shape=i0.shape, calcVariance=calcStd)
    m.update(i0)
    
    for i in images[1:]:
        i = imread(i)
        thresh = m.avg - noise_level_function(m.avg) * 3
        m.update(i, i>thresh)

    mx = m.avg.max()
    if calcStd:
        return m.avg/mx, m.var**0.5/mx
    return m.avg/mx
    def _correctDarkCurrent(self, image, exposuretime, bgImages, date):
        '''
        open OR calculate a background image: f(t)=m*t+n
        '''
        # either exposureTime or bgImages has to be given
#         if exposuretime is not None or bgImages is not None:
        print('... remove dark current')

        if bgImages is not None:

            if (type(bgImages) in (list, tuple) or
                    (isinstance(bgImages, np.ndarray) and
                     bgImages.ndim == 3)):
                if len(bgImages) > 1:
                    # if multiple images are given: do STE removal:
                    nlf = self.noise_level_function
                    bg = SingleTimeEffectDetection(
                        bgImages, nStd=4,
                        noise_level_function=nlf).noSTE
                else:
                    bg = imread(bgImages[0])
            else:
                bg = imread(bgImages)
        else:
            bg = self.calcDarkCurrent(exposuretime, date)
        self.temp['bg'] = bg
        image -= bg
    def __init__(self, images, noise_level_function=None, nStd=4,
                 save_ste_indices=False, calcVariance=False, dtype=float):
        self.save_ste_indices = save_ste_indices

        i1 = imread(images[0], 'gray', dtype=dtype)
        i2 = imread(images[1], 'gray')

        self.mask_STE = None
        if save_ste_indices:
            self.mask_STE = np.zeros(shape=i1.shape, dtype=bool)

        self.mma = MaskedMovingAverage(shape=i1.shape,
                                       calcVariance=calcVariance,
                                       dtype=i1.dtype)

        # MINIMUM OF BOTH IMAGES:
        self.mma.update(np.min((i1, i2), axis=0))

        if noise_level_function is None:
            noise_level_function = oneImageNLF(self.mma.avg)[0]
        self.noise_level_function = noise_level_function
        self.threshold = noise_level_function(self.mma.avg) * nStd

        self.addImage(np.max((i1, i2), axis=0))

        for i in images[2:]:
            self.addImage(imread(i, 'gray'))
    def __init__(self,
                 images,
                 noise_level_function=None,
                 nStd=4,
                 save_ste_indices=False):
        self.save_ste_indices = save_ste_indices
        self.mask_STE = None

        i1 = imread(images[0], 'gray')
        i2 = imread(images[1], 'gray')

        if save_ste_indices:
            self.mask_STE = np.zeros(shape=i1.shape, dtype=bool)

        #MINIMUM OF BOTH IMAGES:
        self.noSTE = m = np.min((i1, i2), axis=0)
        if noise_level_function is None:
            noise_level_function = oneImageNLF(m)[0]
        self.noise_level_function = noise_level_function
        self.threshold = noise_level_function(m) * nStd

        self._c = 2
        self.addImage(np.max((i1, i2), axis=0))

        for i in images[2:]:
            self.addImage(imread(i, 'gray'))
def estimateFromImages(imgs1, imgs2=None, mn_mx=None, nbins=100):
    '''
    estimate the noise level function as stDev over image intensity
    from a set of 2 image groups 
    images at the same position have to show
    the identical setup, so
    imgs1[i] - imgs2[i] = noise
    '''
    if imgs2 is None:
        imgs2 = [None]*len(imgs1)
    else:
        assert len(imgs1)==len(imgs2)
    
    y_vals = np.empty((len(imgs1),nbins))
    w_vals = np.zeros((len(imgs1),nbins))
    
    if mn_mx is None:
        print('estimating min and max image value')
        mn = 1e6
        mx = -1e6
        #get min and max image value checking all first images:         
        for n, i1 in enumerate(imgs1):
            print '%s/%s' %(n+1, len(imgs1))
            i1 = imread(i1)
            mmn, mmx = _getMinMax(i1)
            mn = min(mn, mmn)
            mx = mx = max(mx, mmx)
        print('--> min(%s), max(%s)' %(mn,mx))
    else:
        mn,mx = mn_mx
    
    x = None
    print('get noise level function')
    for n,(i1, i2) in enumerate(zip(imgs1,imgs2)):
        print('%s/%s' %(n+1,len(imgs1)))

        i1 = imread(i1)
        if i2 is not None:
            i2 = imread(i2)
    
        x,y,weights, _ = calcNLF(i1, i2, mn_mx_nbins=(mn, mx, nbins), x=x)
        y_vals[n] = y
        w_vals[n] = weights
        
    #filter empty places:
    filledPos = np.sum(w_vals, axis=0)!=0
    w_vals = w_vals[:,filledPos]
    y_vals = y_vals[:,filledPos]
    x = x[filledPos]

    y_avg = np.average(np.nan_to_num(y_vals), 
                       weights=w_vals,
                        axis=0)
    
    w_vals = np.sum(w_vals, axis=0)
    w_vals /= w_vals.sum()

    fitParams, fn, i = _evaluate(x, y_avg, w_vals)
    return x, fn, y_avg, y_vals, w_vals, fitParams,i
Beispiel #9
0
def estimateFromImages(imgs1, imgs2=None, mn_mx=None, nbins=100):
    '''
    estimate the noise level function as stDev over image intensity
    from a set of 2 image groups 
    images at the same position have to show
    the identical setup, so
    imgs1[i] - imgs2[i] = noise
    '''
    if imgs2 is None:
        imgs2 = [None] * len(imgs1)
    else:
        assert len(imgs1) == len(imgs2)

    y_vals = np.empty((len(imgs1), nbins))
    w_vals = np.zeros((len(imgs1), nbins))

    if mn_mx is None:
        print('estimating min and max image value')
        mn = 1e6
        mx = -1e6
        #get min and max image value checking all first images:
        for n, i1 in enumerate(imgs1):
            print '%s/%s' % (n + 1, len(imgs1))
            i1 = imread(i1)
            mmn, mmx = _getMinMax(i1)
            mn = min(mn, mmn)
            mx = mx = max(mx, mmx)
        print('--> min(%s), max(%s)' % (mn, mx))
    else:
        mn, mx = mn_mx

    x = None
    print('get noise level function')
    for n, (i1, i2) in enumerate(zip(imgs1, imgs2)):
        print('%s/%s' % (n + 1, len(imgs1)))

        i1 = imread(i1)
        if i2 is not None:
            i2 = imread(i2)

        x, y, weights, _ = calcNLF(i1, i2, mn_mx_nbins=(mn, mx, nbins), x=x)
        y_vals[n] = y
        w_vals[n] = weights

    #filter empty places:
    filledPos = np.sum(w_vals, axis=0) != 0
    w_vals = w_vals[:, filledPos]
    y_vals = y_vals[:, filledPos]
    x = x[filledPos]

    y_avg = np.average(np.nan_to_num(y_vals), weights=w_vals, axis=0)

    w_vals = np.sum(w_vals, axis=0)
    w_vals /= w_vals.sum()

    fitParams, fn, i = _evaluate(x, y_avg, w_vals)
    return x, fn, y_avg, y_vals, w_vals, fitParams, i
def flatFieldFromCloseDistance2(images, bgImages=None, calcStd=False,
                                nlf=None, nstd=6):
    '''
    Same as [flatFieldFromCloseDistance]. Differences are:
    ... single-time-effect removal included
    ... returns the standard deviation of the image average [calcStd=True]

    Optional:
    -----------
    calcStd -> set to True to also return the standard deviation
    nlf -> noise level function (callable)
    nstd -> artefact needs to deviate more than [nstd] to be removed
    '''

    if len(images) > 1:

        # start with brightest images
        def fn(img):
            img = imread(img)
            s0, s1 = img.shape[:2]
            # rough approx. of image brightness:
            return -img[::s0 // 10, ::s1 // 10].min()

        images = sorted(images, key=lambda i: fn(i))

        avgBg = getBackground2(bgImages, images[1])

        i0 = imread(images[0], dtype=float) - avgBg
        i1 = imread(images[1], dtype=float) - avgBg

        if nlf is None:
            nlf = oneImageNLF(i0, i1)[0]

        det = SingleTimeEffectDetection(
            (i0, i1), nlf, nStd=nstd, calcVariance=calcStd)

        for i in images[1:]:
            i = imread(i)
            # exclude erroneously darker areas:
            thresh = det.noSTE - nlf(det.noSTE) * nstd
            mask = i > thresh
            # filter STE:
            det.addImage(i, mask)

        ma = det.noSTE

    else:
        ma = imread(images[0], dtype=float) - avgBg

    # fast artifact free maximum:
    mx = median_filter(ma[::10, ::10], 3).max()

    if calcStd:
        return ma / mx, det.mma.var**0.5 / mx

    return ma / mx
Beispiel #11
0
def getBackground(bgImages, **kwargs):
    # AVERAGE BACKGROUND IMAGES IF MULTIPLE ARE GIVEN:
    if bgImages is not None:
        if (type(bgImages) in (tuple, list)
                or isinstance(bgImages, np.ndarray) and bgImages.ndim == 3):
            if len(bgImages) > 1:
                return averageSameExpTimes(bgImages)
            else:
                return imread(bgImages[0], **kwargs)
        else:
            return imread(bgImages, **kwargs)
    else:
        return 0
Beispiel #12
0
def averageSameExpTimes(imgs_path):
    '''
    average background images with same exposure time
    '''
    firsts = imgs_path[:2]
    imgs = imgs_path[2:]
    for n, i in enumerate(firsts):
        firsts[n] = np.asfarray(imread(i))
    d = DarkCurrentMap(firsts)
    for i in imgs:
        i = imread(i)
        d.addImg(i)
    return d.map()
Beispiel #13
0
    def _loadImg(self):
        try:
            ID, meas, cur = self._getIDmeasCur()
            txt = ID.text(0), meas.text(0), cur.text(0)
            root = self.gui.projectFolder()
            p = root.join(*txt)
            if p == self._lastP:
                return
            self._lastP = p

            p0 = p.join("prev_A.jpg")
            p1 = p.join("prev_B.jpg")
            ll = len(root) + 1
            if not p0.exists():
                self.gui.server.download(p0[ll:], root)
            if not p1.exists():
                self.gui.server.download(p1[ll:], root)

            img = imread(p0)
            self._grid.imageview.setImage(img, autoRange=False)

            img = imread(p1)
            self._grid.imageview2.setImage(img, autoRange=False)

            # load/change grid
            cells = ID.data(0, QtCore.Qt.UserRole)['grid']
            nsublines = ID.data(0, QtCore.Qt.UserRole)['nsublines']

            cdata = cur.data(0, QtCore.Qt.UserRole)
            #             print(1111123, self._grid.grid.vertices())
            #             print(cdata['vertices'])
            vertices = cdata['vertices']

            # TODO: remove different conventions
            #             cells = cells[::-1]
            #             nsublines = nsublines[::-1]

            vertices = np.array(vertices)[np.array([0, 3, 2, 1])]
            #             print(vertices, 9898)

            self._grid.grid.setNCells(cells)
            self._grid.grid.setVertices(vertices)
            #             print(self._grid.grid.vertices(), 888888888888888888)

            self._grid.edX.setValue(cells[0])
            self._grid.edY.setValue(cells[1])
            self._grid.edBBX.setValue(nsublines[0])
            self._grid.edBBY.setValue(nsublines[1])
            self._updateBtnVerified(cdata['verified'])
        except AttributeError as e:
            print(e)
 def __init__(self, img):
     self.img = imread(img)
     # Fourier transform giving a complex array
     # with zero frequency component (DC component) will be at top left
     # corner
     self.fourier = np.fft.fft2(self.img)
     self.fshift = np.fft.fftshift(self.fourier)
    def setReference(self, ref):
        '''
        ref  ... either quad, grid, homography or reference image

        quad --> list of four image points(x,y) marking the edges of the quad
               to correct
        homography --> h. matrix to correct perspective distortion
        referenceImage --> image of same object without perspective distortion
        '''
#         self.maps = {}
        self.quad = None
#         self.refQuad = None
        self._camera_position = None
        self._homography = None
        self._homography_is_fixed = True
#         self.tvec, self.rvec = None, None
        self._pose = None

        # evaluate input:
        if isinstance(ref, np.ndarray) and ref.shape == (3, 3):
            # REF IS HOMOGRAPHY
            self._homography = ref
            # REF IS QUAD
        elif len(ref) == 4:
            self.quad = sortCorners(ref)

            # TODO: cleanup # only need to call once - here
            o = self.obj_points  # no property any more

            # REF IS IMAGE
        else:
            self.ref = imread(ref)
#             self._refshape = ref.shape[:2]
            self.pattern = PatternRecognition(self.ref)
            self._homography_is_fixed = False
Beispiel #16
0
 def drawChessboard(self, img=None):
     '''
     draw a grid fitting to the last added image
     on this one or an extra image
     img == None
         ==False -> draw chessbord on empty image
         ==img
     '''
     assert self.findCount > 0, 'cannot draw chessboard if nothing found'
     if img is None:
         img = self.img
     elif isinstance(img, bool) and not img:
         img = np.zeros(shape=(self.img.shape), dtype=self.img.dtype)
     else:
         img = imread(img, dtype='uint8')
     gray = False
     if img.ndim == 2:
         gray = True
         # need a color 8 bit image
         img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
     # Draw and display the corners
     cv2.drawChessboardCorners(img, self.opts['size'],
                               self.opts['imgPoints'][-1],
                               self.opts['foundPattern'][-1])
     if gray:
         img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
     return img
Beispiel #17
0
 def __init__(self, img):
     self.img = imread(img)
     # Fourier transform giving a complex array
     # with zero frequency component (DC component) will be at top left
     # corner
     self.fourier = np.fft.fft2(self.img)
     self.fshift = np.fft.fftshift(self.fourier)
    def correctGrid(self, img, grid):
        '''
        grid -> array of polylines=((p0x,p0y),(p1x,p1y),,,)
        '''

        self.img = imread(img)
        h = self.homography  #TODO: cleanup only needed to get newBorder attr.

        if self.opts['do_correctIntensity']:
            self.img = self.img / self._getTiltFactor(self.img)

        snew = self._newBorders
        warped = np.empty(snew[::-1], dtype=self.img.dtype)
        s0, s1 = grid.shape[:2]
        nx, ny = s0 - 1, s1 - 1
        sy, sx = snew[0] / nx, snew[1] / ny

        objP = np.array([[0, 0], [sx, 0], [sx, sy], [0, sy]], dtype=np.float32)

        for ix in xrange(nx):
            for iy in xrange(ny):
                quad = grid[ix:ix + 2,
                            iy:iy + 2].reshape(4, 2)[np.array([0, 2, 3, 1])]
                hcell = cv2.getPerspectiveTransform(quad.astype(np.float32),
                                                    objP)

                cv2.warpPerspective(self.img,
                                    hcell, (sx, sy),
                                    warped[iy * sy:(iy + 1) * sy,
                                           ix * sx:(ix + 1) * sx],
                                    flags=cv2.INTER_LANCZOS4,
                                    **self.opts['cv2_opts'])
        return warped
Beispiel #19
0
def imgAverage(images, copy=True):
    '''
    returns an image average

    works on many, also unloaded images
    minimises RAM usage
    '''
    i0 = images[0]
    out = imread(i0, dtype='float')
    if copy and id(i0) == id(out):
        out = out.copy()

    for i in images[1:]:
        out += imread(i, dtype='float')
    out /= len(images)
    return out
Beispiel #20
0
 def drawChessboard(self, img=None):
     '''
     draw a grid fitting to the last added image 
     on this one or an extra image
     img == None
         ==False -> draw chessbord on empty image
         ==img
     ''' 
     if img is None:
         img = self.img
     elif type(img) == bool and img == False:
         img = np.zeros(shape=(self.img.shape), dtype=self.img.dtype)
     else:
         img = imread(img, dtype='uint8')
     gray = False  
     if img.ndim == 2:
         gray=True
         #need a color 8 bit image
         img = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
     # Draw and display the corners
     cv2.drawChessboardCorners(img, self.opts['size'], 
                               self.opts['imgPoints'][-1], 
                               self.opts['foundPattern'][-1])
     if gray:
         img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 
     return img
Beispiel #21
0
def scaleSignal(img, fitParams=None, backgroundToZero=False, reference=None):
    '''
    scale the image between...
    
    backgroundToZero=True -> 0 (average background) and 1 (maximum signal)
    backgroundToZero=False -> signal+-3std
    
    reference -> reference image -- scale image to fit this one
    
    returns:
    scaled image
    '''
    img = imread(img)
    if reference is not None:
        low, high = signalRange(img, fitParams)
        low2, high2 = signalRange(reference)
        img = np.asfarray(img)
        ampl = (high2 - low2) / (high - low)
        img -= low
        img *= ampl
        img += low2
        return img
    else:
        offs, div = scaleParams(img, fitParams, backgroundToZero)
        img = np.asfarray(img) - offs
        img /= div
        print 'offset: %s, divident: %s' % (offs, div)
        return img
    def correct(self, img):
        '''
        ...from perspective distortion:
         --> perspective transformation
         --> apply tilt factor (view factor) correction 
        '''
        print("CORRECT PERSPECTIVE ...")
        self.img = imread(img)

        if not self._homography_is_fixed:
            self._homography = None
        h = self.homography

        if self.opts['do_correctIntensity']:
            tf = self.tiltFactor()
            self.img = np.asfarray(self.img)
            if self.img.ndim == 3:
                for col in range(self.img.shape[2]):
                    self.img[..., col] /= tf
            else:
                self.img = self.img / tf
        warped = cv2.warpPerspective(self.img,
                                     h,
                                     self._newBorders[::-1],
                                     flags=cv2.INTER_LANCZOS4,
                                     **self.opts['cv2_opts'])
        return warped
    def draw3dCoordAxis(self, img=None, thickness=8):
        '''
        draw the 3d coordinate axes into given image
        if image == False:
            create an empty image
        '''
        if img is None:
            img = self.img
        elif img is False:
            img = np.zeros(shape=self.img.shape, dtype=self.img.dtype)
        else:
            img = imread(img)
        # project 3D points to image plane:
        # self.opts['obj_width_mm'], self.opts['obj_height_mm']
        w, h = self.opts['new_size']
        axis = np.float32([[0.5 * w, 0.5 * h, 0],
                           [w, 0.5 * h, 0],
                           [0.5 * w, h, 0],
                           [0.5 * w, 0.5 * h, -0.5 * w]])
        t, r = self.pose()
        imgpts = cv2.projectPoints(axis, r, t,
                                   self.opts['cameraMatrix'],
                                   self.opts['distCoeffs'])[0]

        mx = int(img.max())
        origin = tuple(imgpts[0].ravel())
        cv2.line(img, origin, tuple(imgpts[1].ravel()), (0, 0, mx), thickness)
        cv2.line(img, origin, tuple(imgpts[2].ravel()), (0, mx, 0), thickness)
        cv2.line(
            img, origin, tuple(imgpts[3].ravel()), (mx, 0, 0), thickness * 2)
        return img
Beispiel #24
0
 def __init__(self, img):
     '''
     Find the Overlap between image parts and stitch them at a given edge together.
     There is no perspective correction.
     @param img: the base image
     '''
     self.base_img_rgb = imread(img)
Beispiel #25
0
def scaleSignal(img, fitParams=None, backgroundToZero=False, reference=None):
    '''
    scale the image between...
    
    backgroundToZero=True -> 0 (average background) and 1 (maximum signal)
    backgroundToZero=False -> signal+-3std
    
    reference -> reference image -- scale image to fit this one
    
    returns:
    scaled image
    '''
    img = imread(img)
    if reference is not None: 
        low, high = signalRange(img, fitParams)
        low2, high2 = signalRange(reference)
        img = np.asfarray(img)
        ampl = (high2-low2)/(high-low)
        img-=low
        img *= ampl
        img += low2
        return img
    else:
        offs, div = scaleParams(img, fitParams, backgroundToZero)
        img = np.asfarray(img)  - offs 
        img /= div 
        print 'offset: %s, divident: %s' %(offs, div)
        return img
Beispiel #26
0
    def __init__(self, imagepath, *args, **kwargs):
        super().__init__()
        self.setWindowTitle('Set grid manual')
        flags = self.windowFlags()
        self.setWindowFlags(flags | QtCore.Qt.WindowMaximizeButtonHint)

        self.editor = GridEditor(*args, **kwargs)
        # set image
        img = imread(imagepath, 'gray')
        self.editor.imageview.setImage(img)

        if 'vertices' not in kwargs:
            # set vertices
            sy, sx = img.shape[:2]
            px, py = sx * 0.2, sy * 0.2

            self.editor.grid.setVertices(
                np.array([[px, py], [px, sy - py], [sx - px, sy - py],
                          [sx - px, py]]))

        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(self.editor)
        self.setLayout(layout)

        btn_done = QtWidgets.QPushButton("Done")
        btn_done.clicked.connect(self.accept)
        self.editor.bottomLayout.addWidget(btn_done, 0, 0)
        self.values = None
    def addImg(self,
               img,
               side='bottom',
               overlap=50,
               overlapDeviation=0,
               rotation=0,
               rotationDeviation=0,
               backgroundColor=None,
               params=None):
        '''
        @param side: 'left', 'right', 'top', 'bottom', default side is 'bottom'
        @param overlap: overlap guess in pixels of both images
        @param overLapDeviation uncertainty of overlap -> overlap in range(ov-deviation, ov+deviation)
        @param rotation: max. rotational error between images [DEG]
        @param rotationDeviation: same as overLapDeviation, but for rotation [DEG]
        @param backgroundColor: if not None, treat this value as transparent within the stitching area
        '''
        img_rgb = imread(img)

        #         if iP.ARRAYS_ORDER_IS_XY:
        #             side = {'left': 'top',
        #                     'right': 'bottom',
        #                     'top': 'left',
        #                     'bottom': 'right'}[side]

        # the following algorithm is based on side = 'bottom', so
        if side in ('top', 'left'):
            img_rgb, self.base_img_rgb = self.base_img_rgb, img_rgb

        # rotate images if to be stitched 'left' or 'right'
        if side in ('left', 'right'):
            self.base_img_rgb = np.rot90(self.base_img_rgb, -1)
            img_rgb = np.rot90(img_rgb, -1)
        # check image shape
        assert img_rgb.shape[1] == self.base_img_rgb.shape[
            1], 'image size must be identical in stitch-direction'

        if params is None:
            # find overlap
            params = (offsx, offsy,
                      rot) = self._findOverlap(img_rgb, overlap,
                                               overlapDeviation, rotation,
                                               rotationDeviation)
        else:
            offsx, offsy, rot = params
        img_rgb = self._rotate(img_rgb, rot)

        self._lastParams = params

        # move values in x axis:
        img_rgb = np.roll(img_rgb, offsx)
        # melt both images together
        self.base_img_rgb = linearBlend(self.base_img_rgb, img_rgb, offsy,
                                        backgroundColor)
        # rotate back if side='left' or 'right'
        if side in ('left', 'right'):
            # self.rotateImage(self.base_img_rgb,-90)
            self.base_img_rgb = np.rot90(self.base_img_rgb, 1)
        return self.base_img_rgb
Beispiel #28
0
 def distortImage(self, image):
     '''
     opposite of 'correct'
     '''
     image = imread(image)
     (imgHeight, imgWidth) = image.shape[:2]
     mapx, mapy = self.getDistortRectifyMap(imgWidth, imgHeight)
     return cv2.remap(image, mapx, mapy, cv2.INTER_LINEAR, borderValue=(0,0,0))
Beispiel #29
0
 def distortImage(self, image):
     '''
     opposite of 'correct'
     '''
     image = imread(image)
     (imgHeight, imgWidth) = image.shape[:2]
     mapx, mapy = self.getDistortRectifyMap(imgWidth, imgHeight)
     return cv2.remap(image, mapx, mapy, cv2.INTER_LINEAR,
                      borderValue=(0, 0, 0))
Beispiel #30
0
 def ff(arr):
     arr = imread(arr, 'gray')
     if arr.size > 300000:
         arr = arr[::10,::10]        
     m = np.nanmean(arr)
     s = np.nanstd(arr)
     r = m-3*s,m+3*s
     b = (r[1]-r[0])/5
     return arr, r,b
 def __init__(self, img):
     '''
     Find the Overlap between image parts and stitch them at a given edge together.
     There is no perspective correction.
     @param img: the base image
     @param gradient: whether to use image gradient for fitting
     '''
     # TODO: does not work with nan in img. so far
     self.base_img_rgb = imread(img)
Beispiel #32
0
 def ff(arr):
     arr = imread(arr, 'gray')
     if arr.size > 300000:
         arr = arr[::10, ::10]
     m = np.nanmean(arr)
     s = np.nanstd(arr)
     r = m - 3 * s, m + 3 * s
     b = (r[1] - r[0]) / 5
     return arr, r, b
Beispiel #33
0
def imgAverage(images, copy=True):
    '''
    returns an image average
    
    works on many, also unloaded images
    minimises RAM usage
    '''
    i0 = images[0]
    out = imread(i0, dtype='noUint')
    
    if copy and id(i0)==id(out):
        out = out.copy()
    
    #moving average:
    c = 2
    for i in images[1:]:
        i = imread(i, dtype='noUint')
        out += (i-out) / c
        c += 1
    
    return out
Beispiel #34
0
def imgAverage(images, copy=True):
    '''
    returns an image average
    
    works on many, also unloaded images
    minimises RAM usage
    '''
    i0 = images[0]
    out = imread(i0, dtype='noUint')

    if copy and id(i0) == id(out):
        out = out.copy()

    #moving average:
    c = 2
    for i in images[1:]:
        i = imread(i, dtype='noUint')
        out += (i - out) / c
        c += 1

    return out
    def __init__(self, img, bg=None, maxDev=1e-4, maxIter=10, remove_border_size=0,
                 # feature_size=5,
                 cameraMatrix=None, distortionCoeffs=None):  # 20
        """
        Args:
            img (path or array): Reference image
        Kwargs:
            bg (path or array): background image - same for all given images
            maxDev (float): Relative deviation between the last two iteration steps
                            Stop iterative refinement, if deviation is smaller
            maxIter (int): Stop iterative refinement after maxIter steps
        """
        self.lens = None
        if cameraMatrix is not None:
            self.lens = LensDistortion()
            self.lens._coeffs['distortionCoeffs'] = distortionCoeffs
            self.lens._coeffs['cameraMatrix'] = cameraMatrix

        self.maxDev = maxDev
        self.maxIter = maxIter
        self.remove_border_size = remove_border_size
        #self.feature_size = feature_size
        img = imread(img, 'gray')

        self.bg = bg
        if bg is not None:
            self.bg = getBackground(bg)
            if not isinstance(self.bg, np.ndarray):
                self.bg = np.full_like(img, self.bg, dtype=img.dtype)
            else:
                self.bg = self.bg.astype(img.dtype)
            img = cv2.subtract(img, self.bg)

        if self.lens is not None:
            img = self.lens.correct(img, keepSize=True)
        # CREATE TEMPLATE FOR PATTERN COMPARISON:
        pos = self._findObject(img)
        self.obj_shape = img[pos].shape

        PatternRecognition.__init__(self, img[pos])

        self._ff_mma = MaskedMovingAverage(shape=img.shape,
                                           dtype=np.float64)

        self.object = None

        self.Hs = []    # Homography matrices of all fitted images
        self.Hinvs = []  # same, but inverse
        self.fits = []  # all imaged, fitted to reference
        self._fit_masks = []

        self._refined = False
 def _correctDarkCurrent(self, image, exposuretime, bgImages, date):
     '''
     open OR calculate a background image: f(t)=m*t+n
     '''
     if bgImages is not None:
         if ( type(bgImages) in (list, tuple) or 
             (isinstance(bgImages, np.ndarray) and bgImages.ndim==3) ):
             #if multiple images are given: do STE removal:
             bg = SingleTimeEffectDetection(
                 (imread(bgImages[0]),imread(bgImages[1])), nStd=4).noSTE
         else:
             bg = imread(bgImages)
     else:
         d = self.coeffs['dark current']
         d = _getFromDate(d, date)
         #calculate bg image:
         offs,ascent = d[2]
         bg = offs + ascent*exposuretime
         mx = self.coeffs['max value']
         with np.errstate(invalid='ignore'):
             bg[bg>mx] = mx    
     image-=bg
Beispiel #37
0
 def _correctDarkCurrent(self, image, exposuretime, bgImages, date):
     '''
     open OR calculate a background image: f(t)=m*t+n
     '''
     if bgImages is not None:
         if (type(bgImages) in (list, tuple) or
             (isinstance(bgImages, np.ndarray) and bgImages.ndim == 3)):
             #if multiple images are given: do STE removal:
             bg = SingleTimeEffectDetection(
                 (imread(bgImages[0]), imread(bgImages[1])), nStd=4).noSTE
         else:
             bg = imread(bgImages)
     else:
         d = self.coeffs['dark current']
         d = _getFromDate(d, date)
         #calculate bg image:
         offs, ascent = d[2]
         bg = offs + ascent * exposuretime
         mx = self.coeffs['max value']
         with np.errstate(invalid='ignore'):
             bg[bg > mx] = mx
     image -= bg
    def __init__(self, images, noise_level_function=None, nStd=4, 
                 save_ste_indices=False):
        self.save_ste_indices = save_ste_indices
        self.mask_STE = None
        
        i1 = imread(images[0], 'gray')
        i2 = imread(images[1], 'gray')
        
        if save_ste_indices:
            self.mask_STE = np.zeros(shape=i1.shape, dtype=bool)
        
        #MINIMUM OF BOTH IMAGES:  
        self.noSTE = m = np.min((i1,i2),axis=0)
        if noise_level_function is None:
            noise_level_function = oneImageNLF(m)[0]
        self.noise_level_function = noise_level_function        
        self.threshold = noise_level_function(m)*nStd
        
        self._c = 2
        self.addImage(np.max((i1,i2),axis=0))

        for i in images[2:]:
            self.addImage(imread(i, 'gray'))
Beispiel #39
0
def SNR_hinken(imgs, bg=0, roi=None):
    '''
    signal-to-noise ratio (SNR) as mean(images) / std(images)
    as defined in Hinken et.al. 2011 (DOI: 10.1063/1.3541766)
    
    works on unloaded images
    no memory overload if too many images are given
    '''
    mean = None
    M = len(imgs)
    if bg is not 0:
        bg = imread(bg)[roi]
        if roi is not None:
            bg = bg[roi]
    #calc mean:
    for i in imgs:
        img = imread(i).asfarray()
        if roi is not None:
            img = img[roi]
        img -= bg
        if mean is None:
            #init
            mean = np.zeros_like(img)
            std = np.zeros_like(img)
        mean += img
        del img
    mean /= M
    #calc std of mean:
    for i in imgs:
        img = imread(i).asfarray()
        if roi is not None:
            img = img[roi]
        img -= bg
        std += (mean - img)**2
        del img
    std = (std / M)**0.5
    return mean.mean() / std.mean()
Beispiel #40
0
def SNR_hinken(imgs, bg=0, roi=None):
    '''
    signal-to-noise ratio (SNR) as mean(images) / std(images)
    as defined in Hinken et.al. 2011 (DOI: 10.1063/1.3541766)
    
    works on unloaded images
    no memory overload if too many images are given
    '''
    mean = None
    M = len(imgs)
    if bg is not 0:
        bg = imread(bg)[roi]
        if roi is not None:
            bg = bg[roi]
    #calc mean:
    for i in imgs:
        img = imread(i).asfarray()
        if roi is not None:
            img = img[roi]
        img -= bg
        if mean is None:
            #init
            mean = np.zeros_like(img)
            std = np.zeros_like(img)
        mean += img
        del img
    mean /= M
    #calc std of mean:
    for i in imgs:
        img = imread(i).asfarray()
        if roi is not None:
            img = img[roi]
        img -= bg
        std += (mean - img)**2
        del img
    std = (std / M)**0.5
    return mean.mean() / std.mean()
Beispiel #41
0
 def correct(self, image, keepSize=False, borderValue=0):
     '''
     remove lens distortion from given image
     '''
     image = imread(image)
     (h, w) = image.shape[:2]
     mapx, mapy = self.getUndistortRectifyMap(w, h)
     self.img = cv2.remap(image, mapx, mapy, cv2.INTER_LINEAR,
                          borderMode=cv2.BORDER_CONSTANT,
                          borderValue=borderValue
                          )
     if not keepSize:
         xx, yy, ww, hh = self.roi
         self.img = self.img[yy: yy + hh, xx: xx + ww]
     return self.img
Beispiel #42
0
    def addImg(self, img):
        '''
        add one chessboard image for detection lens distortion
        '''
        # self.opts['imgs'].append(img)

        self.img = imread(img, 'gray', 'uint8')

        didFindCorners, corners = self.method()
        self.opts['foundPattern'].append(didFindCorners)

        if didFindCorners:
            self.findCount += 1
            self.objpoints.append(self.objp)
            self.opts['imgPoints'].append(corners)
        return didFindCorners
Beispiel #43
0
 def __init__(self, img=None, vertices=None, refinePositions=True):
     '''
     @param img -> input image
     @paramn vertices -> routh estimate of corner positions
     @refinePositions -> whether to refine (found) corner positions
     '''
     self.img = imread(img, 'gray')
     self.vertices = vertices
     
     self._pc = None
     
     if self.vertices is None:
         lines = self._findQuadLines()
         if refinePositions:
             lines = self._refineLines(lines)
         self.vertices = self._verticesFromLines(lines)
Beispiel #44
0
    def addImg(self, img):
        '''
        add one chessboard image for detection lens distortion
        '''
        #self.opts['imgs'].append(img)

        self.img = imread(img, 'gray', 'uint8')

        didFindCorners, corners = self.method()
        self.opts['foundPattern'].append(didFindCorners)
        
        if didFindCorners:
            self.findCount += 1
            self.objpoints.append(self.objp)
            self.opts['imgPoints'].append(corners) 
        return didFindCorners
    def _fitImg(self, img):
        '''
        fit perspective and size of the input image to the reference image
        '''
        img = imread(img, 'gray')
        if self.bg is not None:
            img = cv2.subtract(img, self.bg)

        if self.lens is not None:
            img = self.lens.correct(img, keepSize=True)

        (H, _, _, _, _, _, _, n_matches) = self.findHomography(img)
        H_inv = self.invertHomography(H)

        s = self.obj_shape
        fit = cv2.warpPerspective(img, H_inv, (s[1], s[0]))
        return fit, img, H, H_inv, n_matches
    def addImg(self, i):
        img = imread(i, 'gray', dtype=float)
        img -= self.bg
        self._orig_shape = img.shape

        if self.scale_factor is None:
                # determine so that smaller image size has 50 px
            self.scale_factor = 100.0 / min(img.shape)
        s = [int(s * self.scale_factor) for s in img.shape]

        img = resize(img, s)

        if self._m is None:
            self._m = MaskedMovingAverage(shape=img.shape)
            if self.ksize is None:
                self.ksize = max(3, int(min(img.shape) / 10))

        f = FitHistogramPeaks(img)
        sp = getSignalPeak(f.fitParams)

        # non-backround indices:
        ind = img > sp[1] - self.nstd * sp[2]
        # blur:
        blurred = minimum_filter(img, 3)
        blurred = maximum_filter(blurred, self.ksize)
        gblurred = gaussian_filter(blurred, self.ksize)
        blurred[ind] = gblurred[ind]

        # scale [0-1]:
        mn = img[~ind].mean()
        if np.isnan(mn):
            mn = 0
        mx = blurred.max()
        blurred -= mn
        blurred /= (mx - mn)

        ind = blurred > self._m.avg

        self._m.update(blurred, ind)
        self.bglevel += mn
        self._mx += mx

        self._n += 1
Beispiel #47
0
def sensitivity(imgs, bg=None):
    '''
    Extract pixel sensitivity from a set of homogeneously illuminated images

    This method is detailed in Section 5 of:
    ---
    K.Bedrich, M.Bokalic et al.:
    ELECTROLUMINESCENCE IMAGING OF PV DEVICES:
    ADVANCED FLAT FIELD CALIBRATION,2017
    ---

    '''
    bg = getBackground(bg)
    for n, i in enumerate(imgs):
        i = imread(i, dtype=float)
        i -= bg
        smooth = fastMean(median_filter(i, 3))
        i /= smooth
        if n == 0:
            out = i
        else:
            out += i
    out /= (n + 1)
    return out
Beispiel #48
0
        mx = mn
    img /= mx
    img = exposure.equalize_hist(img, nbins=nBins)
    
    img *= mx
    
    if intType:
        img = img.astype(intType)
    return img



if __name__ == '__main__':
    import sys
    import pylab as plt
    import imgProcessor
    from imgProcessor.imgIO import imread

    img = imread(PathStr(imgProcessor.__file__).dirname().join(
                'media', 'electroluminescence', 'EL_module_orig.PNG'))
    
    eq = equalizeImage(img.copy())
    
    if 'no_window' not in sys.argv:
        plt.figure('original')
        plt.imshow(img)
    
        plt.figure('equalised histogram')
        plt.imshow(eq)
    
        plt.show()
        cv2.circle(new_img, end1, r, c, thickness)
        cv2.circle(new_img, end2, r, c, thickness)
    return new_img


if __name__ == '__main__':
    import sys
    from fancytools.os.PathStr import PathStr
    import imgProcessor
    from imgProcessor.imgIO import imread
    import pylab as plt

    # 1. LOAD TEST IMAGE
    path = PathStr(imgProcessor.__file__).dirname().join(
        'media', 'electroluminescence', 'EL_cell_cracked.png')
    orig = imread(path)

    # 2. DISTORT REFERENCE IMAGE RANDOMLY:
    rows, cols = orig.shape
    # rescale
    r0 = 1 + 0.2 * (np.random.rand() - 1)
    r1 = 1 + 0.2 * (np.random.rand() - 1)
    dst = cv2.resize(orig, None, fx=r0, fy=r1, interpolation=cv2.INTER_CUBIC)
    # translate
    M = np.float32([[1, 0, np.random.randint(-20, 20)],
                    [0, 1, np.random.randint(-20, 20)]])
    dst = cv2.warpAffine(dst, M, (cols, rows))
    # rotate:
    M = cv2.getRotationMatrix2D((cols / 2, rows / 2),
                                np.random.randint(0, 90), 1)
    dst = cv2.warpAffine(dst, M, (cols, rows))
    def __init__(self, img,
                 #                  binEveryNPxVals=10,
                 fitFunction=gaussian,
                 bins=None,
                 bins2=None,
                 minNPeaks=2,
                 maxNPeaks=4,
                 debug=False):
        '''
        :param binEveryNPxVals: how many intensities should be represented by one histogram bin
        :param fitFunction: function to fit the histogram (currently only gaussian)
        :param maxNPeaks: limit number of found peaks (biggest to smallest)
        :param debug: whether to print error messages

        public attributes:
        .fitParams -> list of fit parameters (for gaussian: (intensity, position, standard deviation))
        '''
        if bins is None:
            bins = 100  # 200
        # import here to decrease startup time
        from scipy.optimize import curve_fit

        self.fitFunction = fitFunction
        self.fitParams = []
        ind = None
        self.img = imread(img, 'gray')

        if self.img.size > 25000:
            # img is big enough: dot need to analyse full img
            self.img = self.img[::10, ::10]
        try:
            self.yvals, bin_edges = np.histogram(self.img, bins=bins)
        except:
            ind = np.isfinite(self.img)
            self.yvals, bin_edges = np.histogram(self.img[ind],
                                                 bins=bins)

        self.yvals = self.yvals.astype(np.float32)
        # move histogram range to representative area:
        cdf = np.cumsum(self.yvals) / self.yvals.sum()

        i0 = np.argmax(cdf > 0.01)
        i1 = np.argmax(cdf > 0.99)
        mnImg = bin_edges[i0]
        mxImg = bin_edges[i1]
        if bins2 is None:
            bins2 = 50
        if self.img.dtype.kind != 'f' or abs(mxImg - mnImg) > 10:
            binEveryNPxVals = 5
            # one bin for every  N pixelvalues
            bins2 = np.clip(int((mxImg - mnImg) /
                                binEveryNPxVals), 25, 100)
        if ind is not None:
            img = self.img[ind]
        else:
            img = self.img

        self.yvals, bin_edges = np.histogram(img, bins=bins2,
                                             range=(mnImg, mxImg))

        # bin edges give start and end of an area-> move that to the middle:
        self.xvals = bin_edges[:-1] + np.diff(bin_edges) * 0.5

        # in the (quite unlikely) event of two yvals being identical in sequence
        # peak detection wont work there, so remove these vals before:
        valid = np.append(
            np.logical_and(self.yvals[:-1] != 0, np.diff(self.yvals) != 0), True)
        self.yvals = self.yvals[valid]
        self.xvals = self.xvals[valid]

        yvals = self.yvals.copy()
        xvals = self.xvals
        s0, s1 = self.img.shape
        minY = max(10, float(s0 * s1) / bins2 / 50)
        mindist = int(5 * 100 / bins2)

        peaks = self._findPeaks(yvals, mindist, maxNPeaks, minY)
        valleys = self._findValleys(yvals, peaks)
        positions = self._sortPositions(peaks, valleys)
        d = minNPeaks - len(positions)
        if d > 0:
            positions.extend([(0, None, -1)] * d)
        # FIT FUNCTION TO EACH PEAK:
        for il, i, ir in positions:
            # peak position/value:
            if i is None:
                i = np.argmax(yvals)
            xp = xvals[i]
            yp = yvals[i]

            xcut = xvals[il:ir]
            ycut = yvals[il:ir]
            # approximate standard deviation from FHWM:
            #ymean = 0.5* (yp + ycut[-1])
            #sigma = abs(xp - findXAt(xcut,ycut,ymean) )
            sigma = 0.5 * abs(xvals[ir] - xvals[il])

            init_guess = (yp, xp, sigma)
            # FIT
            try:
                # fitting procedure using initial guess
                params, _ = curve_fit(self.fitFunction, xcut, ycut,
                                      p0=init_guess,
                                      sigma=np.ones(shape=xcut.shape) * 1e-8)
            except (RuntimeError, TypeError):
                # TypeError: not enough values given (when peaks and valleys to
                # close to each other)
                if debug:
                    print(
                        "couln't fit gaussians -> result will will inaccurate")
                # stay with initial guess:
                params = init_guess
#             except TypeError, err:
#                 print err
#                 #couldn't fit maybe because to less values were given
#                 continue
            if (params[0] > 0):  # has height
                #                  and #has height
                # peak is within the image histogram
                params = list(params)
                params[2] = np.abs(params[2])

                self.fitParams.append(params)

            y = self.fitFunction(self.xvals, *params).astype(yvals.dtype)
            yvals -= y  # peaks add up
            yvals[yvals < 0] = 0  # can't be negative

        # sort for increasing x positions
        self.fitParams = sorted(self.fitParams, key=lambda p: p[1])