def undistort(self, rgb=True, day_only=True):    
        """
        Undistort the raw image, set rgb, red, rbr, cos_g
        Input: rgb and day_only flags
        Output: rgb, red, rbr, cos_g will be specified.
        """           
        #####get the image acquisition time, this need to be adjusted whenever the naming convention changes 
        t_cur=datetime.strptime(self.fn[-18:-4],'%Y%m%d%H%M%S');     
        t_std = t_cur-timedelta(hours=5)     #####adjust UTC time into local standard time            
        sz = 90-ps.get_altitude(self.cam.lat,self.cam.lon,t_std); sz*=deg2rad;
        self.sz = sz
        if day_only and sz>85*deg2rad:
            return
             
        saz = 360-ps.get_azimuth(self.cam.lat,self.cam.lon,t_std); saz=(saz%360)*deg2rad;
        self.saz = saz

        try:
            im0=plt.imread(self.fn);
        except:
            print('Cannot read file:', self.fn)
            return None
        im0=im0[self.cam.roi]
        im0[~self.cam.valid0,:]=0

        cos_sz=np.cos(sz)        
        cos_g=cos_sz*np.cos(self.cam.theta0)+np.sin(sz)*np.sin(self.cam.theta0)*np.cos(self.cam.phi0-saz);   
        
        red0=im0[:,:,0].astype(np.float32); red0[red0<=0]=np.nan
        rbr0=(red0-im0[:,:,2])/(im0[:,:,2]+red0)        

        if np.nanmean(red0[(cos_g>0.995) & (red0>=1)])>230: 
            mk=cos_g>0.98
            red0[mk]=np.nan 
            rbr0[mk]=np.nan 
        
        rbr=st.fast_bin_average2(rbr0,self.cam.weights); 
        rbr=st.fill_by_mean2(rbr,7, mask=(np.isnan(rbr)) & self.cam.valid) 
        self.rbr=rbr
        
        red0-=st.rolling_mean2(red0,300,ignore=np.nan)
        red=st.fast_bin_average2(red0,self.cam.weights); 
        red=st.fill_by_mean2(red,7, mask=(np.isnan(red)) & self.cam.valid)
        red[red>50]=50; red[red<-50]=-50
        red=(red+51)*2.5+0.5;       
        self.red=red.astype(np.uint8)
                
        if rgb:             
            im=np.zeros((self.cam.ny,self.cam.nx,3),dtype=im0.dtype)   
            for i in range(3):
                im[:,:,i]=st.fast_bin_average2(im0[:,:,i],self.cam.weights); 
                im[:,:,i]=st.fill_by_mean2(im[:,:,i],7, ignore=0, mask=(im[:,:,i]==0) & (self.cam.valid))
#                 im[:,:,i]=st.fill_by_mean2(im[:,:,i],7, ignore=0, mask=np.isnan(red))   
            im[red<=0]=0
            self.rgb=im   
Beispiel #2
0
        def cloud_mask_grow():
            mk_cld = ((mr > 4) & (mr2 > 0.02))
            rbr_t = np.nanmean(self.rbr[mk_cld])
            mk_sky = ((mr < -3.5) & (mr2 < -0.02) & (self.rbr < rbr_t - 0.01))
            for iter in range(6):
                sky = mk_sky
                cld = mk_cld
                if np.sum(sky) > 20:  # or np.nanstd(self.rbr[slc])<-0.01:
                    m1 = st.rolling_mean2(self.rbr,
                                          200,
                                          mask_ignore=~sky,
                                          fill_nan=True)
                    m2 = st.rolling_mean2(red,
                                          200,
                                          mask_ignore=~sky,
                                          fill_nan=True)
                    mk = (self.rbr - m1 <= 0.005) & (red - m2 < 5)
                    mk_sky[mk] = True
#                             print(np.sum(mk))
                if np.sum(cld) > 20:  # or np.nanstd(self.rbr[slc])<-0.01:
                    m1 = st.rolling_mean2(self.rbr,
                                          200,
                                          mask_ignore=~cld,
                                          fill_nan=True)
                    m2 = st.rolling_mean2(red,
                                          200,
                                          mask_ignore=~cld,
                                          fill_nan=True)
                    mk = (self.rbr - m1 >= -0.005) & (red - m2 > -2)
                    mk_cld[mk] = True
#             for iter in range(6):
#                 m1=st.rolling_mean2(self.rbr,400,mask_ignore=~mk_sky,fill_nan=True)
# #                 m2=st.rolling_mean2(red,200,mask_ignore=~mk_sky,fill_nan=True)
#                 mc1=st.rolling_mean2(self.rbr,400,mask_ignore=~mk_cld,fill_nan=True)
# #                 mc2=st.rolling_mean2(red,200,mask_ignore=~mk_cld,fill_nan=True)
#                 mk=~((mk_sky) |(mk_cld))
#                 dist=np.abs(self.rbr[mk]-m1[mk]); distc=np.abs(self.rbr[mk]-mc1[mk])
# #                 dist=np.abs(red-m2); distc=np.abs(red-mc2)
#                 mk_cld[mk]=dist>distc; mk_sky[mk]=dist<=distc;

            return mk_cld, mk_sky
Beispiel #3
0
def cloud_mask(cam, img, img0):
    """
    Set cloud mask
    Input: None
    Output: cloud mask will be specified.
    """
    cos_s = np.cos(img.sz)
    sin_s = np.sin(img.sz)
    cos_sp = np.cos(img.saz)
    sin_sp = np.sin(img.saz)
    cos_th = cam.cos_th
    sin_th = np.sqrt(1 - cos_th**2)
    cos_p = cam.cos_p
    sin_p = cam.sin_p
    cos_g = cos_s * cos_th + sin_s * sin_th * (cos_sp * cos_p + sin_sp * sin_p)
    ###cosine of the angle between illumination and view directions

    r0 = img0.rgb[..., 0].astype(np.float32)
    r0[r0 <= 0] = np.nan
    r1 = img.rgb[..., 0].astype(np.float32)
    r1[r1 <= 0] = np.nan
    rbr_raw = (r1 - img.rgb[:, :, 2]) / (img.rgb[:, :, 2] + r1)
    rbr = rbr_raw.copy()
    rbr -= st.rolling_mean2(rbr, int(img.nx // 6.666))
    rbr[rbr > 0.08] = 0.08
    rbr[rbr < -0.08] = -0.08
    rbr = (rbr + 0.08) * 1587.5 + 1
    ####scale rbr to 0-255
    mblue = np.nanmean(img.rgb[(cos_g < 0.7) & (r1 > 0) & (rbr_raw < -0.01),
                               2].astype(np.float32))
    err = r1 - r0
    err -= np.nanmean(err)
    dif = st.rolling_mean2(abs(err), 100)
    err = st.rolling_mean2(err, 5)
    dif2 = maximum_filter(np.abs(err), 5)

    sky = (rbr < 126) & (dif < 1.2)
    sky |= dif < 0.9
    sky |= (dif < 1.5) & (err < 3) & (rbr < 105)
    sky |= (rbr < 70)
    sky &= (img.red > 0)
    cld = (dif > 2) & (err > 4)
    cld |= (img.red > 150) & (rbr > 160) & (dif > 3)
    cld |= (rbr > 180)
    ####clouds with high rbr
    cld[cos_g > 0.7] |= (img.rgb[cos_g > 0.7, 2] <
                         mblue) & (rbr_raw[cos_g > 0.7] > -0.01)
    #####dark clouds
    cld &= dif > 3
    total_pixel = np.sum(r1 > 0)

    min_size = 50 * img.nx / 1000
    cld = remove_small_objects(cld,
                               min_size=min_size,
                               connectivity=4,
                               in_place=True)
    sky = remove_small_objects(sky,
                               min_size=min_size,
                               connectivity=4,
                               in_place=True)

    ncld = np.sum(cld)
    nsky = np.sum(sky)

    # these threshholds don't strictly need to match those used in forecasting / training
    if (ncld + nsky) <= 1e-2 * total_pixel:
        return
    elif (ncld <
          nsky) and (ncld <= 5e-2 * total_pixel
                     ):  #####shortcut for clear or totally overcast conditions
        img.cm = cld.astype(np.uint8)
        img.layers = 1
        return
    elif (ncld > nsky) and (nsky <= 5e-2 * total_pixel):
        img.cm = ((~sky) & (r1 > 0)).astype(np.uint8)
        img.layers = 1
        return
    max_score = -np.Inf
    x0 = -0.15
    ncld, nsky = 0.25 * nsky + 0.75 * ncld, 0.25 * ncld + 0.75 * nsky
    #     ncld=max(ncld,0.05*total_pixel); nsky=max(nsky,0.05*total_pixel)
    for slp in [0.1, 0.15]:
        offset = np.zeros_like(r1)
        mk = cos_g < x0
        offset[mk] = (x0 - cos_g[mk]) * 0.05
        mk = (cos_g >= x0) & (cos_g < 0.72)
        offset[mk] = (cos_g[mk] - x0) * slp
        mk = (cos_g >= 0.72)
        offset[mk] = slp * (0.72 - x0) + (cos_g[mk] - 0.72) * slp / 3
        rbr2 = rbr_raw - offset
        minr, maxr = st.lower_upper(rbr2[rbr2 > -1], 0.01)
        rbr2 -= minr
        rbr2 /= (maxr - minr)

        lower, upper, step = -0.1, 1.11, 0.2
        max_score_local = -np.Inf
        for iter in range(3):
            for thresh in np.arange(lower, upper, step):
                mk_cld = (rbr2 > thresh)  #& (dif>1) & (rbr>70)
                mk_sky = (rbr2 <= thresh) & (r1 > 0)
                bnd = st.get_border(mk_cld,
                                    10,
                                    thresh=0.2,
                                    ignore=img.red <= 0)
                #                 bnd=st.rolling_mean2(mk_cld.astype(np.float32),10,ignore=img.red<=0)
                #                 bnd=(bnd<0.8) & (bnd>0.2)
                sc=[np.sum(mk_cld & cld)/ncld,np.sum(mk_sky & sky)/nsky,np.sum(dif2[bnd]>4)/np.sum(bnd), \
                    -5*np.sum(mk_cld & sky)/nsky,-5*np.sum(mk_sky & cld)/ncld,-5*np.sum(dif2[bnd]<2)/np.sum(bnd)]
                score = np.nansum(sc)
                if score > max_score_local:
                    max_score_local = score
                    thresh_ref = thresh
                    if score > max_score:
                        max_score = score
                        img.cm = mk_cld.astype(np.uint8)
#                         rbr_ref=rbr2.copy();
#                         sc_ref=sc.copy()
#                 print(slp,iter,lower,upper,step,score)
            lower, upper = thresh_ref - 0.5 * step, thresh_ref + 0.5 * step + 0.001
            step /= 4

#         lower,upper=st.lower_upper(rbr2[img.red>0],0.02)
##         print(lower,upper)
#         for thresh in np.arange(lower-0.02,max(upper,lower+0.1),0.02):
#             mk_cld=(rbr2>thresh) #& (dif>1) & (rbr>70)
#             mk_sky=(rbr2<=thresh) & (r1>0)
#             bnd=st.rolling_mean2(mk_cld.astype(np.float32),10,ignore=img.red<=0)
#             bnd=(bnd<0.8) & (bnd>0.2)
#             sc=[np.sum(mk_cld & cld)/ncld,np.sum(mk_sky & sky)/nsky,np.sum(dif2[bnd]>4)/np.sum(bnd),-5*np.sum(mk_cld & sky)/max(nsky,0.02*total_pixel),-5*np.sum(mk_sky & cld)/max(ncld,0.02*total_pixel),-5*np.sum(dif2[bnd]<2)/np.sum(bnd)]
#             score=np.nansum(sc)
#             if score>max_score:
#                 max_score=score
#                 img.cm=mk_cld.astype(np.uint8);
#                 rbr_ref=rbr2.copy();
#                 sc_ref=sc.copy()
# #             print(slp,score)

    img.layers = 1
Beispiel #4
0
    def undistort(self, cam, rgb=True, day_only=True):
        """
        Undistort the raw image, set rgb, red, rbr, cos_g
        Input: rgb and day_only flags
        Output: rgb, red, rbr, cos_g will be specified.
        """
        #####get the image acquisition time, this need to be adjusted whenever the naming convention changes
        #ts=localToUTCtimestamp(datetime.strptime(self.fn[-18:-4],'%Y%m%d%H%M%S'),cam.cam_tz)    #get UTC timestamp
        #t_std=UTCtimestampTolocal(ts, pytz.timezone("UTC"))                                      #create datetime in UTC
        t_std = localToUTC(datetime.strptime(self.fn[-18:-4], '%Y%m%d%H%M%S'),
                           self.cam_tz)
        #t_std=datetime.strptime(self.fn[-18:-4],'%Y%m%d%H%M%S');
        #t_std = t_local + timedelta(hours=5) #replace(tzinfo=timezone(-timedelta(hours=5)))
        #print("\tUndistortion->t_local=%s\t\tt_std=%s\n" % (str(t_local),str(t_std)))
        print("\tUndistortion->t_std=%s\n" % (str(t_std)))
        gatech = ephem.Observer()
        gatech.date = t_std.strftime('%Y/%m/%d %H:%M:%S')
        gatech.lat, gatech.lon = str(self.lat), str(self.lon)
        sun = ephem.Sun()
        sun.compute(gatech)
        sz = np.pi / 2 - sun.alt
        self.sz = sz
        if day_only and sz > 75 * deg2rad:
            print("Night time (sun angle = %f), skipping\n" % sz)
            return

        saz = 180 + sun.az / deg2rad
        saz = (saz % 360) * deg2rad
        self.saz = saz

        try:
            im0 = plt.imread(self.fn)
        except:
            print('Cannot read file:', self.fn)
            return None
        im0 = im0[cam.roi]

        cos_sz = np.cos(sz)
        cos_g = cos_sz * np.cos(cam.theta0) + np.sin(sz) * np.sin(
            cam.theta0) * np.cos(cam.phi0 - saz)

        red0 = im0[:, :, 0].astype(np.float32)
        red0[red0 <= 0] = np.nan
        #         rbr0=(red0-im0[:,:,2])/(im0[:,:,2]+red0)
        if np.nanmean(red0[(cos_g > 0.995) & (red0 >= 1)]) > 230:
            mk = cos_g > 0.98
            red0[mk] = np.nan

        xsun, ysun = np.tan(sz) * np.sin(saz), np.tan(sz) * np.cos(saz)
        self.sun_x, self.sun_y = int(
            0.5 * self.nx * (1 + xsun / cam.max_tan)), int(
                0.5 * self.ny * (1 + ysun / cam.max_tan))

        invalid = ~cam.valid

        red = st.fast_bin_average2(red0, cam.weights)
        red = st.fill_by_mean2(red, 7, mask=(np.isnan(red)) & cam.valid)
        red[invalid] = np.nan
        #         plt.figure(); plt.imshow(red); plt.show();
        red -= st.rolling_mean2(red, int(self.nx // 6.666))
        red[red > 50] = 50
        red[red < -50] = -50
        red = (red + 50) * 2.54 + 1
        red[invalid] = 0
        self.red = red.astype(np.uint8)
        #         plt.figure(); plt.imshow(self.red); plt.show();

        if rgb:
            im = np.zeros((self.ny, self.nx, 3), dtype=im0.dtype)
            for i in range(3):
                im[:, :, i] = st.fast_bin_average2(im0[:, :, i], cam.weights)
                im[:, :,
                   i] = st.fill_by_mean2(im[:, :, i],
                                         7,
                                         ignore=0,
                                         mask=(im[:, :, i] == 0) & (cam.valid))


#                 im[:,:,i]=st.fill_by_mean2(im[:,:,i],7, ignore=0, mask=np.isnan(red))
            im[self.red <= 0] = 0

            #             plt.figure(); plt.imshow(im); plt.show()
            self.rgb = im
Beispiel #5
0
    def cloud_mask(self):
        """
        Set cloud mask
        Input: None
        Output: cloud mask will be specified.
        """
        def cloud_mask_grow():
            mk_cld = ((mr > 4) & (mr2 > 0.02))
            rbr_t = np.nanmean(self.rbr[mk_cld])
            mk_sky = ((mr < -3.5) & (mr2 < -0.02) & (self.rbr < rbr_t - 0.01))
            for iter in range(6):
                sky = mk_sky
                cld = mk_cld
                if np.sum(sky) > 20:  # or np.nanstd(self.rbr[slc])<-0.01:
                    m1 = st.rolling_mean2(self.rbr,
                                          200,
                                          mask_ignore=~sky,
                                          fill_nan=True)
                    m2 = st.rolling_mean2(red,
                                          200,
                                          mask_ignore=~sky,
                                          fill_nan=True)
                    mk = (self.rbr - m1 <= 0.005) & (red - m2 < 5)
                    mk_sky[mk] = True
#                             print(np.sum(mk))
                if np.sum(cld) > 20:  # or np.nanstd(self.rbr[slc])<-0.01:
                    m1 = st.rolling_mean2(self.rbr,
                                          200,
                                          mask_ignore=~cld,
                                          fill_nan=True)
                    m2 = st.rolling_mean2(red,
                                          200,
                                          mask_ignore=~cld,
                                          fill_nan=True)
                    mk = (self.rbr - m1 >= -0.005) & (red - m2 > -2)
                    mk_cld[mk] = True
#             for iter in range(6):
#                 m1=st.rolling_mean2(self.rbr,400,mask_ignore=~mk_sky,fill_nan=True)
# #                 m2=st.rolling_mean2(red,200,mask_ignore=~mk_sky,fill_nan=True)
#                 mc1=st.rolling_mean2(self.rbr,400,mask_ignore=~mk_cld,fill_nan=True)
# #                 mc2=st.rolling_mean2(red,200,mask_ignore=~mk_cld,fill_nan=True)
#                 mk=~((mk_sky) |(mk_cld))
#                 dist=np.abs(self.rbr[mk]-m1[mk]); distc=np.abs(self.rbr[mk]-mc1[mk])
# #                 dist=np.abs(red-m2); distc=np.abs(red-mc2)
#                 mk_cld[mk]=dist>distc; mk_sky[mk]=dist<=distc;

            return mk_cld, mk_sky

        def cloud_mask_seed():
            edges = [[-1, -0.36, 0.12, 0.52, 0.88, 1.0],
                     [-0.68, -0.12, 0.32, 0.7, 0.94, 1]]
            mk_cld = ((mr > 4) & (mr2 > 0.02))
            rbr_t = np.nanmean(self.rbr[mk_cld])
            mk_sky = ((mr < -3.5) & (mr2 < -0.02) & (self.rbr < rbr_t - 0.01))
            ths = edges[0]
            tmp = self.rbr[red > 0]
            mk = np.abs(tmp - np.nanmean(tmp)) < 3 * np.nanstd(tmp)
            p0 = np.nanstd(tmp[mk])
            tmp = vred[red > 0]
            mk = np.abs(tmp - np.nanmean(tmp)) < 3 * np.nanstd(tmp)
            p00 = np.nanmean(tmp[mk])
            if p0 < 0.027:  #####overcast clouds
                for ith, th in enumerate(ths[:-2]):
                    slc = ((cos_g >= th) & (cos_g < ths[ith + 1])) & (red > 0)
                    if np.sum(slc) <= 1e4: continue
                    slc2 = ((cos_g >= th) & (cos_g < ths[ith + 2]) &
                            (red > 0)) if ith < len(ths) - 2 else (
                                cos_g >= ths[ith - 1]) & (
                                    cos_g < ths[ith + 1]) & (self.rbr > -1)
                    tmp = self.rbr[slc2]
                    mk = np.abs(tmp - np.nanmean(tmp)) < 3 * np.nanstd(tmp)
                    p1 = np.nanstd(tmp[mk])
                    #p2=np.nanmean(tmp[mk])
                    tmp = red[slc]
                    mk = np.abs(tmp - np.nanmean(tmp)) < 3 * np.nanstd(tmp)
                    p3 = np.nanstd(tmp[mk]) / np.nanmean(tmp[mk])
                    if p1 < 0.01 or (p1 < 0.02 and p3 < 0.2 - 5 *
                                     (p1 - 0.01)):  # or (p1<0.02 and p3<0.15):
                        mk_cld[slc] = True

            elif p00 < 1.5:  ####likely clear
                for ith, th in enumerate(ths[:-2]):
                    slc = ((cos_g >= th) & (cos_g < ths[ith + 1])) & (red > 0)
                    if np.sum(slc) <= 1e4: continue
                    slc2 = ((cos_g >= th) & (cos_g < ths[ith + 2]) &
                            (red > 0)) if ith < len(ths) - 2 else (
                                cos_g >= ths[ith - 1]) & (
                                    cos_g < ths[ith + 1]) & (self.rbr > -1)
                    tmp = self.rbr[slc2]
                    mk = np.abs(tmp - np.nanmean(tmp)) < 3 * np.nanstd(tmp)
                    p1 = np.nanstd(tmp[mk])
                    #p2=np.nanmean(tmp[mk])
                    tmp = red[slc]
                    mk = np.abs(tmp - np.nanmean(tmp)) < 3 * np.nanstd(tmp)
                    p3 = np.nanstd(tmp[mk]) / np.nanmean(tmp[mk])
                    tmp = vred[slc]
                    mk = np.abs(tmp - np.nanmean(tmp)) < 3 * np.nanstd(tmp)
                    p4 = np.nanmean(tmp[mk])
                    if (p4 < 1.0) or (p4 < 2 and p1 > 0.015 + 0.01 *
                                      (p4 - 1.0)) or (p4 < 2.5 and p1 > 0.03
                                                      and p3 > 0.2):
                        mk_sky[slc] = True

            elif np.sum(mk_cld) > 100 and np.sum(
                    mk_sky) > 100:  #####mixture of sky and clouds
                for ith, th in enumerate(ths[:-2]):
                    slc = ((cos_g >= th) & (cos_g < ths[ith + 1])) & (red > 0)
                    if np.sum(slc) <= 1e4 or np.sum(
                            mk_cld[slc]) < 20 or np.sum(mk_sky[slc]) < 20:
                        continue
                    slc2 = ((cos_g >= th) & (cos_g < ths[ith + 2]) &
                            (red > 0)) if ith < len(ths) - 2 else (
                                cos_g >= ths[ith - 1]) & (
                                    cos_g < ths[ith + 1]) & (self.rbr > -1)
                    tmp = self.rbr[slc2]
                    mk = np.abs(tmp - np.nanmean(tmp)) < 3 * np.nanstd(tmp)
                    p1 = np.nanstd(tmp[mk])
                    #p2=np.nanmean(tmp[mk])
                    tmp = red[slc]
                    mk = np.abs(tmp - np.nanmean(tmp)) < 3 * np.nanstd(tmp)
                    p3 = np.nanstd(tmp[mk]) / np.nanmean(tmp[mk])
                    tmp = vred[slc]
                    mk = np.abs(tmp - np.nanmean(tmp)) < 3 * np.nanstd(tmp)
                    p4 = np.nanmean(tmp[mk])

                    rbr_c = np.nanmean(self.rbr[slc][mk_cld[slc]])
                    rbr_s = np.nanmean(self.rbr[slc][mk_sky[slc]])
                    mk_sky[slc] = np.abs(self.rbr[slc] -
                                         rbr_c) > 1.2 * np.abs(self.rbr[slc] -
                                                               rbr_s)
                    mk_cld[slc] = 1.2 * np.abs(self.rbr[slc] - rbr_c) < np.abs(
                        self.rbr[slc] - rbr_s)

#                     mkc=(p1<0.01) or (p1<0.02 and p3<0.2-5*(p1-0.01))
#                     if mkc:
#                         tmp=np.nanmean(self.rbr[slc]);
#                         if np.abs(tmp-rbr_c)<np.abs(tmp-rbr_s):
#                             mk_cld[slc]=True
#                     mks=(p4<1.0) or (p4<2 and p1>0.015+0.01*(p4-1.0))
#                     if mks:
#                         tmp=np.nanmean(self.rbr[slc]);
#                         print(th,p1,p3,p4,rbr_c,rbr_s,tmp)
#                         if np.abs(tmp-rbr_c)>np.abs(tmp-rbr_s):
#                             mk_sky[slc]=True

            for iter in range(0):
                #                 for iy in np.arange(200*(iter%2),2001,400):
                #                     for ix in np.arange(200*(iter%2),2001,400):
                #                         slc=np.s_[iy:iy+400,ix:ix+400];
                ths = edges[iter % 2]
                for ith, th in enumerate(ths[:-2]):
                    slc = ((cos_g >= th) & (cos_g < ths[ith + 1]))
                    sky = mk_sky[slc]
                    cld = mk_cld[slc]
                    if np.sum(mk_sky[slc]
                              ) > 20:  # or np.nanstd(self.rbr[slc])<-0.01:
                        m1 = np.nanmean(self.rbr[slc][sky])
                        m2 = np.nanmean(red[slc][sky])
                        mk = (self.rbr[slc] - m1 <= 0.005) & (red[slc] - m2 <
                                                              5) & (~cld)
                        sky[mk] = True
                        mk_sky[slc] = sky
                    if np.sum(mk_cld[slc]
                              ) > 20:  # or np.nanstd(self.rbr[slc])<-0.01:
                        m1 = np.nanmean(self.rbr[slc][cld])
                        m2 = np.nanmean(red[slc][cld])
                        mk = (self.rbr[slc] - m1 >= -0.005) & (red[slc] - m2 >
                                                               -2) & (~sky)
                        cld[mk] = True
                        mk_cld[slc] = cld
            return mk_cld, mk_sky

        if self.rbr is None or self.sz > 85 * deg2rad:
            return

        cos_s = np.cos(self.sz)
        sin_s = np.sin(self.sz)
        cos_sp = np.cos(self.saz)
        sin_sp = np.sin(self.saz)
        cos_th = self.cam.cos_th
        sin_th = np.sqrt(1 - cos_th**2)
        cos_p = self.cam.cos_p
        sin_p = self.cam.sin_p
        cos_g = cos_s * cos_th + sin_s * sin_th * (cos_sp * cos_p +
                                                   sin_sp * sin_p)
        ###cosine of the angle between illumination and view directions
        #         self.cos_g=((1+cos_g)*127.5).astype(np.uint8);

        red = self.rgb[:, :, 1].astype(np.float32)
        mr = red - st.rolling_mean2(red, 5, ignore=0)
        mr2 = self.rbr - st.rolling_mean2(self.rbr, 25, ignore=np.nan)
        mred = st.rolling_mean2(red, 25, ignore=0)
        vred = st.rolling_mean2(red**2, 25, ignore=0) - mred**2
        vred[vred > 50] = 50
        #         mrbr=st.rolling_mean2(self.rbr,25,ignore=np.nan)
        #         vrbr=st.rolling_mean2(self.rbr**2,25,ignore=np.nan)-mrbr**2;
        mk_cld, mk_sky = cloud_mask_seed()

        m1 = st.rolling_mean2(self.rbr,
                              400,
                              mask_ignore=~mk_sky,
                              fill_nan=True)
        #                     m2=st.rolling_mean2(red,200,mask_ignore=~mk+sky,fill_nan=True)
        mc1 = st.rolling_mean2(self.rbr,
                               400,
                               mask_ignore=~mk_cld,
                               fill_nan=True)
        #                     mc2=st.rolling_mean2(red,200,mask_ignore=~mk_cld,fill_nan=True)
        dist = np.abs(self.rbr - m1)
        distc = np.abs(self.rbr - mc1)
        self.cm = mk_cld.copy()
        mk = ~(mk_cld | mk_sky)
        self.cm[mk] = dist[mk] > distc[mk]
        # #         cm2=morphology.binary_opening(cm2,np.ones((4,4))); cm2= remove_small_objects(cm2, min_size=20, connectivity=4);  #mag[~cm2]=np.nan
        #         fig,ax=plt.subplots(1,3,sharex=True,sharey=True);
        #         ax[0].imshow(self.rgb); ax[1].imshow(cm2); ax[2].imshow(mr,vmin=-10,vmax=10)
        # #         plt.hist(self.rbr[(self.rbr>-0.75) & (cm2)],bins=50)
        #         plt.show()

        #         xp=np.array([-1,-0.1, 0.5, 0.82, 1.0]);
        #         xc=np.array([0.5*(xp[i]+xp[i+1]) for i in range(len(xp)-1)])
        #         dx=np.diff(xp)
        #         thr=np.zeros_like(xc)-1; thr2=np.zeros_like(xc);
        #
        #         self.cm=np.zeros(self.rbr.shape,dtype=np.uint8);

        #         for i in range(len(xc)):
        #             slc = (cos_g>=xp[i]) & (cos_g<xp[i+1]);
        # #             print('std:',xc[i],np.nanstd(self.rbr[slc]),np.sum(np.abs(mred[slc]-self.rgb[slc,0].astype(np.float32)>3)))
        #             print('std:',xc[i],np.nanstd(self.rbr[slc]),np.nanmean(vred[slc]))
        #             if np.nanstd(self.rbr[slc])<0.02: ###overcast clouds
        #                 thr[i]=np.nanmean(self.rbr[slc][mk_sky[slc]])+0.01
        #                 thr2[i]=np.nanmean(self.rgb[slc,0][mk_sky[slc]])+2
        #                 tmp=mk_cld[slc]; tmp[self.rbr[slc]>np.nanmean(self.rbr[slc])-0.02]=True; mk_cld[slc]=tmp;
        #                 continue
        #
        #             if np.sum(mk_sky[slc])>200:
        #                 a=self.rbr[slc][mk_cld[slc]];   am=np.nanmean(a[a>-0.99])
        #                 b=self.rbr[slc][mk_sky[slc]];   bm=np.nanmean(b[b>-0.99])
        #                 a2=self.rgb[slc,0][mk_cld[slc]];   am2=np.nanmean(a2[a2>0])
        #                 b2=self.rgb[slc,0][mk_sky[slc]];   bm2=np.nanmean(b2[b2>0])
        # #                 thr[i]=max(am-0.05, 0.5*(am+bm)-0.005)
        # #                 thr2[i]=max(am2-5, 0.5*(am2+bm2)-2)
        #                 thr[i]=bm+0.02
        #                 thr2[i]=bm2+5
        # #                 if xc[i]>0.5: thr2+=7;
        #                 print(xc[i],np.sum(mk_cld[slc]),am, bm,am2,bm2)
        #             elif np.nanmean(self.rbr[slc])>0.05:
        #                 thr[i]=np.nanmean(self.rbr[slc])
        #                 thr2[i]=np.nanmean(self.rgb[slc,0])
        #
        # #         thr[thr>-0.03]=-0.03
        #         print(thr, thr2)
        # #         for i in range(1,len(xc)):
        # #             if thr[i]<=thr[i-1]:
        # #                 thr[i]=thr[i-1]+0.02;
        # #             if thr2[i]<=thr2[i-1]:
        # #                 thr2[i]=thr2[i-1]+10;
        #         nthr=np.sum(thr>-0.99)
        #         if nthr<=0: return
        #         if nthr>=2:
        #             mk=thr>-0.99
        #             f = interpolate.interp1d(xc[mk],thr[mk],fill_value='extrapolate')
        #             thresh=f(cos_g); thresh[cos_g<-0.55]=f(-0.55); thresh[cos_g>.95]=f(0.95)
        #             f2 = interpolate.interp1d(xc[mk],thr2[mk],fill_value='extrapolate')
        #             thresh2=f2(cos_g); thresh2[cos_g<-0.55]=f2(-0.55); thresh2[cos_g>.95]=f2(0.95)
        #         elif nthr==1:
        #             ithr=np.nonzero(thr>-0.99)[0][0]
        #             mk=(cos_g>xc[ithr]-0.5*dx[ithr]) & (cos_g<xc[ithr]+0.5*dx[ithr])
        #             thresh=thr[ithr]+0.5*(cos_g-xc[ithr]);
        #             thresh2=thr2[ithr]+100*(cos_g-xc[ithr]);
        #         self.cm=(self.rbr>thresh ) | ((self.rgb[:,:,0]>thresh2) & (self.rbr>thresh-0.05))
        #         self.cm[mk_sky]=0; self.cm[mk_cld]=1;
        self.cm[self.rgb[:, :, 0] <= 0] = 0

        fig, ax = plt.subplots(2, 3, sharex=True, sharey=True)
        ax[0, 0].imshow(self.rgb)
        ax[0, 1].imshow(np.sqrt(vred) * 100 / mred > 2)
        ax[0, 2].imshow(mr, vmin=-2, vmax=2)
        ax[1, 0].imshow(mr2, vmin=-0.02, vmax=0.02)
        ax[1, 1].imshow(self.rbr, vmin=-0.2, vmax=0.1)
        ax[1, 2].imshow(mk_sky)
        plt.show()
Beispiel #6
0
    def cloud_mask(self, cam):
        """
        Set cloud mask
        Input: None
        Output: cloud mask will be specified.
        """
        cos_s = np.cos(self.sz)
        sin_s = np.sin(self.sz)
        cos_sp = np.cos(self.saz)
        sin_sp = np.sin(self.saz)
        cos_th = cam.cos_th
        sin_th = np.sqrt(1 - cos_th**2)
        cos_p = cam.cos_p
        sin_p = cam.sin_p
        cos_g = cos_s * cos_th + sin_s * sin_th * (cos_sp * cos_p +
                                                   sin_sp * sin_p)
        ###cosine of the angle between illumination and view directions
        #         self.cos_g=((1+cos_g)*127.5).astype(np.uint8);

        #####determine the cloud edges
        red0 = self.rgb[:, :, 1].astype(np.float32)
        red0[cos_g > 0.98] = 0
        rbr0 = (self.rgb[:, :, 0].astype(np.float32) - self.rgb[:, :, 2]) / (
            self.rgb[:, :, 2] + self.rgb[:, :, 0].astype(np.float32))
        red = self.red.astype(np.float32)
        red[cos_g > 0.98] = 0
        rbr = self.rbr.astype(np.float32)
        rbr[(rbr <= 0) | (cos_g > 0.98)] = np.nan

        BND_WIN = 10 if self.nx <= 1000 else 15
        mred = st.rolling_mean2(red0, BND_WIN, ignore=0)
        mred[cos_g > 0.95] = np.nan
        vred = st.rolling_mean2(red0**2, BND_WIN, ignore=0) - mred**2
        #vred[vred>50]=50
        mrbr = st.rolling_mean2(rbr0, BND_WIN, ignore=0)
        vrbr = st.rolling_mean2(rbr0**2, BND_WIN, ignore=0) - mrbr**2
        #vrbr[vrbr>50]=50

        total_pixel = np.sum(red > 0)
        #         bnd = (vred>BND_RED_THRESH)
        for factor in range(1, 5):
            bnd = ((100*np.sqrt(vred)/mred>factor*BND_RED_THRESH) & (np.sqrt(vrbr)>BND_RBR_THRESH/3))  \
                  | ((np.sqrt(vrbr)>BND_RBR_THRESH) & (100*np.sqrt(vred)/mred>BND_RED_THRESH/3))
            #             print(factor,np.sum(bnd), 0.1*np.sum(red>0))
            bnd1 = ((100 * np.sqrt(vred) / mred > factor * BND_RED_THRESH / 2)
                    & (np.sqrt(vrbr) > BND_RBR_THRESH))
            if np.sum(bnd) <= 0.1 * total_pixel:
                break

        ####classify the cloud boundary pixels into cld or sky, which will serve as seeds for further growth
        mk_cld = (red >= DRED_THRESH) | (rbr >= DRBR_THRESH) | (
            (red + rbr > DRED_THRESH + DRBR_THRESH - 20) &
            (red > DRED_THRESH - 5))
        mk_sky = (rbr <= 255 - DRBR_THRESH + 5) & (rbr > 0)
        mk_cld = remove_small_objects(mk_cld,
                                      min_size=500 * self.nx / 2000,
                                      connectivity=4)
        mk_sky = remove_small_objects(mk_sky,
                                      min_size=500 * self.nx / 2000,
                                      connectivity=4)
        #         mk_sky=morphology.binary_dilation(mk_sky,np.ones((3,3)));  mk_sky[mk_cld]=False;
        #         mk_cld=morphology.binary_dilation(mk_cld,np.ones((3,3)));  mk_cld[mk_sky]=False;

        if np.sum(mk_sky) <= 3e-4 * total_pixel:
            self.cm = (red > 0).astype(np.uint8)
            self.layers = 1
            return

        if np.sum(mk_cld) <= 3e-4 * total_pixel:
            self.cm = (red > -1).astype(np.uint8)
            return

        bins = np.arange(50, 251, 5)
        bcs = 0.5 * (bins[:-1] + bins[1:])
        mk = (mk_sky) & (red > 0)
        sky_rbr = st.bin_average(rbr0[mk], red0[mk], bins)
        if np.sum(~np.isnan(sky_rbr)) <= 1:
            self.cm = (red > 0).astype(np.uint8)
            self.layers = 1
            return
        sky_rbr = st.rolling_mean(sky_rbr, 20, fill_nan=True)
        coeff = np.polyfit(bcs[sky_rbr > -1], sky_rbr[sky_rbr > -1], 1)
        #         print('rbr-red fitting:',coeff, red0.shape)
        if coeff[0] > 2e-4:
            rbr2 = rbr0 - np.polyval(coeff, red0)
        else:
            self.cm = (red > 0).astype(np.uint8)
            self.layers = 1
            return
#             f_sky = interpolate.interp1d(bcs,sky_rbr,fill_value='extrapolate')
#             rbr2=rbr0-f_sky(red0)

#         bins=np.arange(-0.1,0.951,0.03);  bcs=0.5*(bins[:-1]+bins[1:])
#         mk=(mk_sky) & (red>0);
#         sky_rbr = st.bin_average(rbr2[mk],cos_g[mk],bins);
#         if np.sum(~np.isnan(sky_rbr))<=1:
#             thr_sky=np.zeros_like(red)+np.nanmean(rbr2[mk]);
#         else:
#             sky_rbr=st.rolling_mean(sky_rbr,10,fill_nan=True)
#             coeff=np.polyfit(bcs[sky_rbr>-1],sky_rbr[sky_rbr>-1],1)
#             print('sky coef:',coeff)
#             if (coeff[0]<=0):
#                 thr_sky=np.zeros_like(red)+np.nanmean(rbr2[mk]);
#             else:
#                 thr_sky=np.polyval(coeff,cos_g)
#                 thr_sky[cos_g>0.95]=np.polyval(coeff,0.95)
#                 thr_sky[cos_g<-0.1]=np.polyval(coeff,-0.1)
#
#         mk=(mk_cld) & (red>0);
#         thr_cld=np.zeros_like(red)+np.nanmean(rbr2[mk]);
# #         sky_rbr = st.bin_average(rbr2[mk],cos_g[mk],bins);
# #         sky_rbr=st.rolling_mean(sky_rbr,10,fill_nan=True)
# #         coeff=np.polyfit(bcs[sky_rbr>-1],sky_rbr[sky_rbr>-1],1)
# #         print('cloud coef:',coeff)
# #         if (coeff[0]<=0):
# #             thr_cld=np.zeros_like(red)+np.nanmean(rbr2[mk]);
# #         else:
# #             thr_cld=np.polyval(coeff,cos_g)
#
# #         mk_cld[rbr2>0.4*thr_cld+0.6*thr_sky]=True; mk_cld[red<=0]=False

        mk = (~mk_cld) & (red > 0)
        hist, bins = np.histogram(rbr2[mk], bins=100, range=(-0.1, 0.1))
        bcs = 0.5 * (bins[:-1] + bins[1:])
        total = np.sum(hist)
        cumhist = np.cumsum(hist)
        min_rbr = bcs[np.argmax(cumhist > 0.02 * total)]
        max_rbr = bcs[100 - np.argmax(cumhist[::-1] <= 0.97 * total)]
        #         print('min, max:', min_rbr,max_rbr,np.nanmean(rbr2))
        self.cm = mk_cld.astype(np.uint8)
        max_score = 0
        for w in np.arange(-0.1, 1.51, 0.1):
            cld = mk_cld.copy()
            cld[rbr2 > min_rbr + (max_rbr - min_rbr) * (w + 0.1) / 1.6] = True
            cld[red <= 0] = False
            #             cld[rbr2>w*thr_cld+(1-w)*thr_sky]=True; cld[red<=0]=False
            mcld = st.rolling_mean2(cld.astype(np.float32),
                                    3,
                                    mask_ignore=red <= 0,
                                    fill_nan=True)
            bnd_e = ((mcld > 0.2) & (mcld < 0.95))
            bnd_e = remove_small_objects(bnd_e,
                                         min_size=150 * self.nx / 2000,
                                         connectivity=4)
            nvalid = np.sum(bnd_e & bnd1)
            score = nvalid**2 / np.sum(bnd_e)
            #             print(w,nvalid, score/nvalid)
            if score > max_score:
                max_score = score
                self.cm = cld.astype(np.uint8)

#         self.cm=mk_cld;
        self.layers = 1
    def cloud_mask(self):
        """
        Set cloud mask
        Input: None
        Output: cloud mask will be specified.
        """
        if self.rbr is None or self.sz > 85 * deg2rad:
            return

        d_rbr = self.rbr - st.rolling_mean2(self.rbr, 50)

        cos_s = np.cos(self.sz)
        sin_s = np.sin(self.sz)
        cos_sp = np.cos(self.saz)
        sin_sp = np.sin(self.saz)
        cos_th = self.cam.cos_th
        sin_th = np.sqrt(1 - cos_th**2)
        cos_p = self.cam.cos_p
        sin_p = self.cam.sin_p
        cos_g = cos_s * cos_th + sin_s * sin_th * (cos_sp * cos_p +
                                                   sin_sp * sin_p)
        ###cosine of the angle between illumination and view directions
        #         self.cos_g=((1+cos_g)*127.5).astype(np.uint8);
        thresh_max1 = 0.3 * (1 - np.cos(self.sz)) - 0.2
        thresh_max2 = 0.3 * (1 - np.cos(self.sz)) - 0.2
        thresh_max2 = 0.5 * thresh_max2 + 0.5 * min(
            0.1, np.nanmean(self.rbr[(cos_g > 0.97) & (d_rbr > 0.0)]))
        thresh1 = np.nan + cos_g
        thresh2 = np.nan + cos_g
        thresh1[cos_g > 0] = thresh_max1 + 0.2 * cos_g[cos_g > 0]**2 - 0.2
        thresh1[cos_g <= 0] = thresh_max1 - 0.2
        #         thresh2[cos_g>0]=thresh_max2+0.15*cos_g[cos_g>0]**2-0.15;  thresh2[cos_g<=0]=thresh_max2-0.15
        thresh2 = thresh_max2 + 0.15 * cos_g**2 - 0.15
        thresh2[cos_g <= 0] = 0.7 * (thresh_max2 -
                                     0.15) + 0.3 * thresh2[cos_g <= 0]

        mask1 = ((d_rbr > 0.02) & (self.rbr > thresh1 - 0.0) &
                 (self.rbr < 0.25))
        ####cloud
        mask2 = ((d_rbr < -0.02) & (self.rbr > -0.6) &
                 (self.rbr < thresh2 + 0.0))
        #####clear
        mask1 = remove_small_objects(mask1, min_size=100, connectivity=4)
        mask2 = remove_small_objects(mask2, min_size=100, connectivity=4)

        if np.sum(mask1) > 1e3 and np.sum(mask2) > 1e3:
            xp = np.array([0.58, 0.85, 1.0])
            xc = np.array(
                [-1, 0.2] +
                [0.5 * (xp[i] + xp[i + 1]) for i in range(len(xp) - 1)])
            cloud_thresh = xc + np.nan
            clear_thresh = xc + np.nan
            for i in range(len(xp)):
                mka = cos_g < xp[0] if i == 0 else ((cos_g >= xp[i - 1]) &
                                                    (cos_g < xp[i]))
                mk1 = mask1 & mka
                mk2 = mask2 & mka
                mrbr = np.nanmean(self.rbr[mka])
                if np.sum(mk1) > 5e2 and np.sum(mk2) > 5e2:
                    clear_thresh[i + 1] = np.nanmean(self.rbr[mk2])
                    cloud_thresh[i + 1] = min(mrbr + 0.2,
                                              np.nanmean(self.rbr[mk1]))
                else:
                    if mrbr > np.nanmean(thresh2[mka]):
                        cloud_thresh[i + 1] = mrbr
                    else:
                        clear_thresh[i + 1] = mrbr

#             print(clear_thresh, cloud_thresh)
            if any(cloud_thresh > -1) and any(
                    clear_thresh > -1
            ) and np.nanmean(cloud_thresh[1:] - clear_thresh[1:]) > 0.035:
                if any(np.isnan(cloud_thresh[1:])) or any(
                        np.isnan(clear_thresh[1:])):
                    fill_gaps_thresh(cloud_thresh, clear_thresh, xc)
#                 print(clear_thresh, cloud_thresh)
                if cloud_thresh[-1] - clear_thresh[-1] < 0.12:
                    mrbr = np.nanmean(self.rgb[cos_g > xp[-2]])
                    if mrbr > thresh_max2:
                        clear_thresh[-1] -= 0.1
                    elif mrbr < thresh_max1:
                        cloud_thresh[-1] += 0.1
                clear_thresh[0] = clear_thresh[1]
                cloud_thresh[0] = cloud_thresh[1]
                if np.sum(clear_thresh > -1) >= 2 and np.sum(
                        cloud_thresh > -1) >= 2:
                    f = interpolate.interp1d(xc[cloud_thresh > -1],
                                             cloud_thresh[cloud_thresh > -1],
                                             fill_value='extrapolate')
                    cloud = f(cos_g)
                    f = interpolate.interp1d(xc[clear_thresh > -1],
                                             clear_thresh[clear_thresh > -1],
                                             fill_value='extrapolate')
                    clear = f(cos_g)
                    d1 = np.abs(self.rbr - cloud)
                    d2 = np.abs(self.rbr - clear)
                    #                 fig,ax=plt.subplots(1,2,sharex=True,sharey=True);
                    #                 ax[0].imshow(clear); ax[0].axis('off') #####original
                    #                 ax[1].imshow(cloud); ax[1].axis('off')
                    self.cm = (0.6 * d1 <= d2).astype(np.uint8)
                    self.layers = 1
                    return

        if np.nanmean(self.rbr[500:-500, 500:-500]) > -0.15:
            self.cm = self.cam.valid
            self.layers = 1
        else:
            self.cm = np.zeros(mask1.shape, dtype=np.uint8)
Beispiel #8
0
    #     ####the next two lines are for parameter tuning purpose only, you can comment them out once you finished tuning;
    #     ####if you set the rotation, center, and shifting parameters correctly the black dot will coincide with the sun.
    im0[cos_g > 0.997, :] = 0
    fig, ax = plt.subplots(1, 1, sharex=True, sharey=True)
    ax.imshow(im0 / 255)
    if cnt > 1: break
    #     continue

    #####sun glare removal
    glare = rad > (np.nanmean(rad) + np.nanstd(rad) * 3)
    im0[glare, :] = 0

    ######cloud masking
    invalid = im0[:, :, 2] < dark_threshold
    im0[invalid, :] = np.nan
    mn = st.rolling_mean2(im0[:, :, 0], ndilate)
    var = st.rolling_mean2(im0[:, :, 0]**2, ndilate) - mn**2
    var[var < 0] = 0
    var = np.sqrt(var)
    rbr = (im0[:, :, 0] - im0[:, :, 2]) / (im0[:, :, 0] + im0[:, :, 2])
    if np.sum(var > var_threshold) > 1e3:
        rbr_threshold = max(
            rbr_clear, min(rbr_cloud, np.nanmean(rbr[var > var_threshold])))

    ####cloud mask (cmask) is the 10-pixel dilated region where var>threshold or rbr>threshold
    coef = np.sqrt(np.minimum(1,
                              np.nanmean(rad) / rad))
    cmask = (var * coef > var_threshold) | (rbr > rbr_threshold)

    ####perform undistortion
    im = np.zeros((ny, nx, 3), dtype=np.float32)
Beispiel #9
0
def cloud_mask(cam,img,img0):
    """
    Set cloud mask
    Input: None
    Output: cloud mask will be specified.
    """            
    cos_s=np.cos(img.sz); sin_s=np.sin(img.sz)
    cos_sp=np.cos(img.saz); sin_sp=np.sin(img.saz)
    cos_th=cam.cos_th; sin_th=np.sqrt(1-cos_th**2)
    cos_p=cam.cos_p; sin_p=cam.sin_p
    cos_g=cos_s*cos_th+sin_s*sin_th*(cos_sp*cos_p+sin_sp*sin_p);  ###cosine of the angle between illumination and view directions    
    
    #####determine the cloud edges
    red0=img.rgb[:,:,1].astype(np.float32); #red0[cos_g>0.98]=0   #####many cameras have artifacts in red channnel, therefore use green here 
    semi_static=red0<=0;
    rbr0=(img.rgb[:,:,0].astype(np.float32)-img.rgb[:,:,2])/(img.rgb[:,:,2]+img.rgb[:,:,0].astype(np.float32));  
    red=img.red.astype(np.float32); red[semi_static]=0
    rbr=img.rbr.astype(np.float32); rbr[semi_static]=np.nan; #rbr[(rbr<=0) | (cos_g>0.98)]=np.nan; 
    
#     bf = gaussian_filter(rbr0, 3)
#     filter_bf = gaussian_filter(bf, 1)                
#     alpha = 30
#     rbr0 = bf + alpha * (bf - filter_bf)
#     fig,ax=plt.subplots(1,2,sharex=True,sharey=True);
#     ax[0].imshow(rbr0,vmin=-0.2,vmax=0.1); ax[1].imshow(rbr1,vmin=-0.2,vmax=0.1); 
#     plt.tight_layout(); plt.show();     
    
    r1=img0.red.astype(np.float32); r1[semi_static]=0;
    sun_region_mk= (cos_g>0.75) & (red>0)
    sun_region_clear=False
    vy,vx,max_corr = cloud_motion(r1,red,mask1=r1>0,mask2=sun_region_mk, ratio=0.7, threads=4);
    if np.abs(vy)+np.abs(vx)<=1.5:
        sun_region_clear=True

    BND_WIN=10 if img.nx<=1000 else 15;            
    mred=st.rolling_mean2(red0,BND_WIN,ignore=0); #mred[cos_g>0.95]=np.nan
    vred=st.rolling_mean2(red0**2,BND_WIN,ignore=0)-mred**2; vred=np.sqrt(vred); #vred[vred>50]=50
    mrbr=st.rolling_mean2(rbr0,BND_WIN,ignore=0)
    vrbr=st.rolling_mean2(rbr0**2,BND_WIN,ignore=0)-mrbr**2; vrbr=np.sqrt(vrbr); #vrbr[vrbr>50]=50
    
    total_pixel=np.sum(red>0)
#         bnd = (vred>BND_RED_THRESH)  
    for factor in range(1,5):
        bnd = ((100*vred/mred>factor*BND_RED_THRESH/2) & (vrbr>BND_RBR_THRESH))   
        if np.sum(bnd)<=0.15*total_pixel:
            break;
    min_size = 500*img.nx/2000     
    bnd=remove_small_objects(bnd, min_size=min_size, connectivity=4, in_place=True)
    
    ####classify the cloud boundary pixels into cld or sky, which will serve as seeds for further growth
    mk_cld=(red>=DRED_THRESH) | (rbr>=DRBR_THRESH) | ((red+rbr>DRED_THRESH+DRBR_THRESH-20) & (red>DRED_THRESH-5));
    mk_sky=(rbr<=255-DRBR_THRESH+5) & (rbr>0) & (red0<=250);
    mk_cld=remove_small_objects(mk_cld, min_size=min_size, connectivity=4, in_place=True)
    mk_sky=remove_small_objects(mk_sky, min_size=min_size, connectivity=4, in_place=True)

#     print(np.sum(mk_sky)/total_pixel,np.sum(mk_cld)/total_pixel);    
#     fig,ax=plt.subplots(2,2,figsize=(9,9),sharex=True,sharey=True);
#     ax[0,0].imshow(img.rgb); ax[0,1].imshow(img0.rgb); 
#     ax[1,0].imshow(mk_cld); ax[1,1].imshow(mk_sky);
#     plt.tight_layout(); plt.show();     

    if np.sum(mk_cld | mk_sky)<=2e-2*total_pixel:   #####shortcut for clear or totally overcast conditions
        vy,vx,max_corr = cloud_motion(r1,red,mask1=r1>0,mask2=red>0, ratio=0.7, threads=4);
        if np.abs(vy)+np.abs(vx)<2.5:
            img.cm=np.zeros_like(r1,dtype=np.uint8)
        else:    
            img.cm=(red>0).astype(np.uint8)
            img.layers=1
        return
    
    bins=np.arange(50,251,5);  bcs=0.5*(bins[:-1]+bins[1:])
    mk=(mk_sky) & (red0>0); 
    sky_rbr = st.bin_average(rbr0[mk],red0[mk],bins);
    if np.sum(~np.isnan(sky_rbr))<=1:  #####only one point, cannot perform regression
        vy,vx,max_corr = cloud_motion(r1,red,mask1=r1>0,mask2=red>0, ratio=0.7, threads=4);
        if np.abs(vy)+np.abs(vx)<2.5:
            img.cm=mk_cld
        else:
            img.cm=((~mk_sky) & (red>0)).astype(np.uint8)
        img.layers=1
        return                
    sky_rbr=st.rolling_mean(sky_rbr,20,fill_nan=True)
    coeff=np.polyfit(bcs[sky_rbr>-1],sky_rbr[sky_rbr>-1],1)
#         print('rbr-red fitting:',coeff, red0.shape)
    if coeff[0]>2e-4:  ####rbr should increase with red, otherwise overcast condition
        rbr2=rbr0-np.polyval(coeff,red0);
        rbr2[rbr2>0.15]=0.15;
    else:
        img.cm=((~mk_sky) & (red>0)).astype(np.uint8)
        img.layers=1
        return
    
    mk=(~mk_cld) & (red0>0)
    hist,bins=np.histogram(rbr2[mk],bins=100,range=(-0.1,0.155))
    bcs=0.5*(bins[:-1]+bins[1:])
    total=np.sum(hist);  cumhist=np.cumsum(hist);
    min_rbr=bcs[np.argmax(cumhist>0.02*total)];
    max_rbr=bcs[100-np.argmax(cumhist[::-1]<=0.97*total)];
#         print('min, max:', min_rbr,max_rbr,np.nanmean(rbr2))
    img.cm=mk_cld.astype(np.uint8);
    max_score=0;
    for w in np.arange(-0.1,1.71,0.1):
        cld=mk_cld.copy()
        cld[rbr2>min_rbr+(max_rbr-min_rbr)*w/1.6]=True; cld[red<=0]=False
#         cld[rbr2>w*max_rbr+(1-w)*min_rbr]=True; cld[red<=0]=False
        mcld=st.rolling_mean2(cld.astype(np.float32),3,mask_ignore=red<=0,fill_nan=True);
        bnd_e=((mcld>0.2) & (mcld<0.95))
        bnd_e=remove_small_objects(bnd_e, min_size=150*img.nx/2000, connectivity=4)
        nvalid=np.sum(bnd_e & bnd)
        score=nvalid**2/np.sum(bnd_e)
#         print(w,nvalid,np.sum(bnd_e), score)
        if score>max_score:
            max_score=score
            img.cm=cld.astype(np.uint8);
    
    if sun_region_clear:
        img.cm[sun_region_mk]=mk_cld[sun_region_mk];
    img.layers=1;
Beispiel #10
0
def preprocess(camera,fn,outpath):
    if not os.path.isdir(outpath+fn[-18:-10]):
        os.makedirs(outpath+fn[-18:-10])
    t=datetime.strptime(fn[-18:-4],'%Y%m%d%H%M%S'); 
    t_prev=t-timedelta(seconds=30);
    t_prev=t_prev.strftime('%Y%m%d%H%M%S');
    fn_prev=fn.replace(fn[-18:-4],t_prev);
    if len(glob.glob(fn_prev))<=0:
        return None

    flist=[fn_prev,fn]
    q=deque();      
    for f in flist:
        img=image(camera,f);  ###img object contains four data fields: rgb, red, rbr, and cm 
        img.undistort(camera,rgb=True);  ###undistortion
        if img.rgb is None:
            return None
        q.append(img)  

        if len(q)<=1: 
            continue
        ####len(q) is always 2 beyond this point
        
        r1=q[-2].red.astype(np.float32); r1[r1<=0]=np.nan
        r2=q[-1].red.astype(np.float32); r2[r2<=0]=np.nan
        err0 = r2-r1;
       
        dif=np.abs(err0); 
        dif=st.rolling_mean2(dif,20)
        semi_static=(abs(dif)<10) & (r1-127>100)
        semi_static=morphology.binary_closing(semi_static,np.ones((10,10)))
        semi_static=remove_small_objects(semi_static,min_size=200, in_place=True)
        q[-1].rgb[semi_static]=0;
        r2[semi_static]=np.nan

        cloud_mask(camera,q[-1],q[-2]); ###one-layer cloud masking        
        
        dilated_cm=morphology.binary_dilation(q[-1].cm,np.ones((15,15))); dilated_cm &= (r2>0)
        vy,vx,max_corr = cloud_motion(r1,r2,mask1=r1>0,mask2=dilated_cm, ratio=0.7, threads=4);
        q[-1].v += [[vy,vx]]; q[-1].layers+=1;        
        
        err = r2-st.shift2(r1,-vx,-vy); err[(r2+st.shift2(r1,-vx,-vy)==0)]=np.nan;  

        mask2=st.rolling_mean2(np.abs(err)-np.abs(err0),40)<-2
        mask2=remove_small_objects(mask2,min_size=300, in_place=True)
        mask2=morphology.binary_dilation(mask2,np.ones((15,15)))
        mask2 = (~mask2) & (r2>0) & (np.abs(r2-127)<30) & (err>-100) #& (q[-1].cm>0)
        if np.sum(mask2 & (q[-1].cm>0))>2e-2*img.nx*img.ny:
            vy,vx,max_corr = cloud_motion(r1,r2,mask1=r1>0,mask2=mask2, ratio=0.7, threads=4);
            if vy is None:
                q.popleft(); 
                continue
            vdist = np.sqrt((vy-q[-1].v[-1][0])**2+(vx-q[-1].v[-1][1])**2)
            if vdist>=5 and np.abs(vy)+np.abs(vx)>2.5 and vdist>0.3*np.sqrt(q[-1].v[-1][0]**2+q[-1].v[-1][1]**2):
                score1=np.nanmean(np.abs(err[mask2])); 
                err2=r2-st.shift2(r1,-vx,-vy); err2[(r2==0) | (st.shift2(r1,-vx,-vy)==0)]=np.nan;  
                score2=np.nanmean(np.abs(err2[mask2]));
                if score2<score1:
                    q[-1].v += [[vy,vx]]; q[-1].layers=2;
                    dif=st.rolling_mean2(np.abs(err)-np.abs(err2),40)>0
                    dif=remove_small_objects(dif,min_size=300, in_place=True)
                    q[-1].cm[dif & (q[-1].cm>0)]=q[-1].layers; 
       
        q[-1].dump_img(outpath+f[-18:-10]+'/'+f[-23:-4]+'.pkl');

        q.popleft();             

    return q[-1]   
Beispiel #11
0
    def undistort(self, cam, rgb=True, day_only=True):    
        """
        Undistort the raw image, set rgb, red, rbr, cos_g
        Input: rgb and day_only flags
        Output: rgb, red, rbr, cos_g will be specified.
        """           
        #####get the image acquisition time, this need to be adjusted whenever the naming convention changes 
        self.time=datetime.strptime(self.fn[-18:-4],'%Y%m%d%H%M%S');     
        gatech = ephem.Observer(); 
        gatech.date = self.time.strftime('%Y/%m/%d %H:%M:%S')
        gatech.lat, gatech.lon = str(self.lat),str(self.lon)
        sun=ephem.Sun()  ; sun.compute(gatech);        
        sz = np.pi/2-sun.alt; 
        self.sz = sz
        if day_only and sz>75*deg2rad:
            return
             
        saz = 180+sun.az/deg2rad; saz=(saz%360)*deg2rad;
        self.saz = saz

        try:
            im0=plt.imread(self.fn);
        except:
            print('Cannot read file:', self.fn)
            return None     
        im0=im0[cam.roi]

        cos_sz=np.cos(sz)        
        cos_g=cos_sz*np.cos(cam.theta0)+np.sin(sz)*np.sin(cam.theta0)*np.cos(cam.phi0-saz);   
        
        red0=im0[:,:,0].astype(np.float32); red0[red0<=0]=np.nan
        rbr0=(red0-im0[:,:,2])/(im0[:,:,2]+red0)        
        if np.nanmean(red0[(cos_g>0.995) & (red0>=1)])>30: 
            mk=cos_g>0.98
            red0[mk]=np.nan 
            rbr0[mk]=np.nan 
        
        xsun, ysun = np.tan(sz)*np.sin(saz), np.tan(sz)*np.cos(saz)
        self.sun_x,self.sun_y = int(0.5*self.nx*(1+xsun/cam.max_tan)), int(0.5*self.ny*(1+ysun/cam.max_tan))

        invalid=~cam.valid
        rbr=st.fast_bin_average2(rbr0,cam.weights); 
        rbr=st.fill_by_mean2(rbr,7, mask=(np.isnan(rbr)) & cam.valid) 
        rbr[invalid]=np.nan              
        rbr -= st.rolling_mean2(rbr,int(self.nx//6.666),ignore=np.nan)
        rbr[rbr>0.08]=0.08; rbr[rbr<-0.08]=-0.08;
        rbr=(rbr+0.08)*1587.5+1;
        rbr[invalid]=0              
        self.rbr=rbr.astype(np.uint8)
        
        red=st.fast_bin_average2(red0,cam.weights); 
        red=st.fill_by_mean2(red,7, mask=(np.isnan(red)) & cam.valid)
        red[invalid]=np.nan;
        red -= st.rolling_mean2(red,int(self.nx//6.666))
        red[red>50]=50; red[red<-50]=-50
        red=(red+50)*2.54+1; 
        red[invalid]=0;
        self.red=red.astype(np.uint8)

        if rgb:             
            im=np.zeros((self.ny,self.nx,3),dtype=im0.dtype)   
            for i in range(3):
                im[:,:,i]=st.fast_bin_average2(im0[:,:,i],cam.weights); 
                im[:,:,i]=st.fill_by_mean2(im[:,:,i],7, ignore=0, mask=(im[:,:,i]==0) & (cam.valid))
#                 im[:,:,i]=st.fill_by_mean2(im[:,:,i],7, ignore=0, mask=np.isnan(red))   
            im[self.red<=0]=0
            self.rgb=im   
Beispiel #12
0
def motion(args):
    camera,day=args  
    
    ymd=day[:8]
    flist = sorted(glob.glob(inpath+camera.camID+'/'+ymd+'/'+camera.camID+'_'+day+'*jpg'))
    if len(flist)<=0:
        return None

    q=deque();      
    for f in flist:
#         print("Start preprocessing ", f[-23:])
        img=cam.image(camera,f);  ###img object contains four data fields: rgb, red, rbr, and cm 
        img.undistort(camera,rgb=True);  ###undistortion
#         print("Undistortion completed ", f[-23:])
        if img.rgb is None:
            continue
        q.append(img)  
#         gray_img = cv2.cvtColor(img.rgb, cv2.COLOR_BGR2GRAY)
#         cv2.imwrite(tmpfs+f[-23:],gray_img);

        if len(q)<=1: 
            continue
        ####len(q) is always 2 beyond this point
        if (q[-1].time-q[-2].time).seconds>=MAX_INTERVAL:
            q.popleft(); q.popleft();
            continue;
        
        cam.cloud_mask(camera,q[-1],q[-2]); ###one-layer cloud masking        
        
        r1=q[-2].red.astype(np.float32); r1[r1<=0]=np.nan
        r2=q[-1].red.astype(np.float32); r2[r2<=0]=np.nan
        err0 = r2-r1;
        
        dilated_cm=morphology.binary_dilation(q[-1].cm,np.ones((15,15))); dilated_cm &= (r2>0)
        vy,vx,max_corr = cam.cloud_motion(r1,r2,mask1=r1>0,mask2=dilated_cm, ratio=0.7, threads=4);
        if vy is None:
            q.popleft(); 
            continue
        q[-1].v += [[vy,vx]]; q[-1].layers+=1;        
        
        err = r2-st.shift2(r1,-vx,-vy);  err[(r2==0) | (st.shift2(r1,-vx,-vy)==0)]=np.nan; 
        print(f[-23:],', first layer:',vy,vx,max_corr)

        mask2=st.rolling_mean2(np.abs(err)-np.abs(err0),40)<0
#         mask2 = (np.abs(err)-np.abs(err0)<0) #| (np.abs(err)<1);
        mask2=remove_small_objects(mask2,min_size=900, in_place=True)
        mask2=morphology.binary_dilation(mask2,np.ones((15,15)))
        mask2 = (~mask2) & (r2>0) & (np.abs(r2-127)<30) & (np.abs(err)>=1) #& (q[-1].cm>0)
#         print(np.sum(mask2 & (q[-1].cm>0))/(img.nx*img.ny))
        if np.sum(mask2 & (q[-1].cm>0))>2e-2*img.nx*img.ny:
            vy,vx,max_corr = cam.cloud_motion(r1,r2,mask1=r1>0,mask2=mask2, ratio=0.7, threads=4);
            if vy is None:
                q.popleft(); 
                continue
            vdist = np.sqrt((vy-q[-1].v[-1][0])**2+(vx-q[-1].v[-1][1])**2)
            if vdist>=5 and np.abs(vy)+np.abs(vx)>2.5 and vdist>0.3*np.sqrt(q[-1].v[-1][0]**2+q[-1].v[-1][1]**2):
                score1=np.nanmean(np.abs(err[mask2])); 
                err2=r2-st.shift2(r1,-vx,-vy); err2[(r2==0) | (st.shift2(r1,-vx,-vy)==0)]=np.nan;  
                score2=np.nanmean(np.abs(err2[mask2]));
                print("Score 1 and score 2: ", score1,score2);
                if score2<score1:
                    q[-1].v += [[vy,vx]]; q[-1].layers=2;
                    dif=st.rolling_mean2(np.abs(err)-np.abs(err2),40)>0
                    dif=remove_small_objects(dif,min_size=300, in_place=True)
                    q[-1].cm[dif & (q[-1].cm>0)]=q[-1].layers; 
                    print(f[-23:],', second layer:',vy,vx,max_corr)
       
        q[-1].dump_img(tmpfs+f[-18:-10]+'/'+f[-23:-4]+'.pkl');

        if SAVE_FIG:
            fig,ax=plt.subplots(2,2,figsize=(9,9),sharex=True,sharey=True);
            ax[0,0].imshow(mask2); ax[0,1].imshow(q[-1].red); 
            ax[1,0].imshow(q[-1].cm); ax[1,1].imshow(q[-1].rgb);
            plt.tight_layout(); 
	    plt.show();     
           # fig.savefig(outpath+ymdhms); 
        q.popleft();             
Beispiel #13
0
    theta_filter = (theta > max_theta) | (theta <= 0)
    theta[theta_filter] = np.nan

    #####coordinate system for the undistorted space
    r = np.tan(theta)
    x, y = r * np.sin(phi), r * np.cos(phi)
    for f in sorted(glob.glob(inpath + camera + '*npy')):

        #         ######read the image to array
        im0 = np.load(f)
        #         im0=plt.imread(f).astype(np.float32);
        im0 = im0[ystart:ystart + ny0, xstart:xstart + nx0, :]
        im0[theta_filter, :] = np.nan

        im0_m = st.rolling_mean2(im0[:, :, 0], 100, fill=np.nan)
        im0[:, :, 0] -= im0_m

        for i in range(1):
            im[cnt, :, :, i] = st.bin_average2_reg(im0[:, :, i],
                                                   x,
                                                   y,
                                                   xbin,
                                                   ybin,
                                                   mask=valid)
            im[cnt, :, :,
               i] = st.fill_by_mean2(im[cnt, :, :, i],
                                     7,
                                     mask=(np.isnan(im[cnt, :, :, i])) & valid)
    cnt += 1
Beispiel #14
0
def preprocess(cam, fn, outpath):
    if not os.path.isdir(outpath + fn[-18:-10]):
        os.makedirs(outpath + fn[-18:-10])
    t = localToUTC(datetime.strptime(fn[-18:-4], '%Y%m%d%H%M%S'), cam.cam_tz)
    t_prev = t - timedelta(seconds=30)
    t_prev = t_prev.strftime('%Y%m%d%H%M%S')
    fn_prev = fn.replace(fn[-18:-4], t_prev)
    if len(glob.glob(fn_prev)) <= 0:
        return None

    print("\tpreprocess->fn=%s\n\t\tt=%s\t\tt_prev=%s\n" %
          (fn, str(t), str(t_prev)))
    flist = [fn_prev, fn]
    q = deque()
    for f in flist:
        img = image(cam, f)
        ###img object contains four data fields: rgb, red, rbr, and cm
        img.undistort(cam, rgb=True)
        ###undistortion
        if img.rgb is None:
            return None
        q.append(img)

        if len(q) <= 1:
            continue
        ####len(q) is always 2 beyond this point

        r1 = q[-2].red.astype(np.float32)
        r1[r1 <= 0] = np.nan
        r2 = q[-1].red.astype(np.float32)
        r2[r2 <= 0] = np.nan
        err0 = r2 - r1

        dif = np.abs(err0)
        dif = st.rolling_mean2(dif, 20)
        semi_static = (abs(dif) < 10) & (r1 - 127 > 100)
        semi_static = morphology.binary_closing(semi_static, np.ones((10, 10)))
        semi_static = remove_small_objects(semi_static,
                                           min_size=200,
                                           in_place=True)
        q[-1].rgb[semi_static] = 0
        r2[semi_static] = np.nan

        cloud_mask(cam, q[-1], q[-2])
        ###one-layer cloud masking
        if (q[-1].cm is None):
            q.popleft()
            continue
        if (np.sum(
            (q[-1].cm > 0)) < 2e-2 * img.nx * img.ny):  ######cloud free case
            q[-1].layers = 0
        else:
            dilated_cm = morphology.binary_dilation(q[-1].cm, np.ones(
                (15, 15)))
            dilated_cm &= (r2 > 0)
            vy, vx, max_corr = cloud_motion(r1,
                                            r2,
                                            mask1=r1 > 0,
                                            mask2=dilated_cm,
                                            ratio=0.7,
                                            threads=4)
            if np.isnan(vy):
                q[-1].layers = 0
            else:
                q[-1].v += [[vy, vx]]
                q[-1].layers = 1

    #         err = r2-st.shift2(r1,-vx,-vy); err[(r2+st.shift2(r1,-vx,-vy)==0)]=np.nan;
    #
    #         mask2=st.rolling_mean2(np.abs(err)-np.abs(err0),40)<-2
    #         mask2=remove_small_objects(mask2,min_size=300, in_place=True)
    #         mask2=morphology.binary_dilation(mask2,np.ones((15,15)))
    #         mask2 = (~mask2) & (r2>0) & (np.abs(r2-127)<30) & (err>-100) #& (q[-1].cm>0)
    #         if np.sum(mask2 & (q[-1].cm>0))>200e-2*img.nx*img.ny:
    #             vy,vx,max_corr = cloud_motion(r1,r2,mask1=r1>0,mask2=mask2, ratio=0.7, threads=4);
    #             if np.isnan(vy):
    #                 q.popleft();
    #                 continue
    #             vdist = np.sqrt((vy-q[-1].v[-1][0])**2+(vx-q[-1].v[-1][1])**2)
    #             if vdist>=5 and np.abs(vy)+np.abs(vx)>2.5 and vdist>0.3*np.sqrt(q[-1].v[-1][0]**2+q[-1].v[-1][1]**2):
    #                 score1=np.nanmean(np.abs(err[mask2]));
    #                 err2=r2-st.shift2(r1,-vx,-vy); err2[(r2==0) | (st.shift2(r1,-vx,-vy)==0)]=np.nan;
    #                 score2=np.nanmean(np.abs(err2[mask2]));
    #                 if score2<score1:
    #                     q[-1].v += [[vy,vx]]; q[-1].layers=2;
    #                     dif=st.rolling_mean2(np.abs(err)-np.abs(err2),40)>0
    #                     dif=remove_small_objects(dif,min_size=300, in_place=True)
    #                     q[-1].cm[dif & (q[-1].cm>0)]=q[-1].layers;

        q[-1].dump_img(outpath + f[-18:-10] + '/' + f[-23:-4] + '.pkl')
        q.popleft()

    return q[-1]
def mask_motion(args):
    camera, day = args
    ymd = day[:8]
    flist = sorted(
        glob.glob(inpath + camera.camID + '/' + ymd + '/' + camera.camID +
                  '_' + day + '*jpg'))
    if len(flist) <= 0:
        return

    q = deque()
    for f in flist:
        print('Processing', f)
        if (~REPROCESS) and os.path.isfile(tmpfs + f[-18:-10] + '/' +
                                           f[-23:-4] + '.pkl'):
            continue

        img = cam.image(camera, f)
        ###img object contains four data fields: rgb, red, rbr, and cm
        img.undistort(camera, rgb=True)
        ###undistortion
        if img.rgb is None:
            continue
        q.append(img)

        if len(q) <= 1:
            continue
        ####len(q) is always 2 beyond this point

        if (q[-1].time - q[-2].time).seconds >= MAX_INTERVAL:
            q.popleft()
            q.popleft()
            continue

        r1 = q[-2].red.astype(np.float32)
        r1[r1 <= 0] = np.nan
        r2 = q[-1].red.astype(np.float32)
        r2[r2 <= 0] = np.nan
        err0 = r2 - r1

        dif = np.abs(err0)
        dif = st.rolling_mean2(dif, 20)
        semi_static = (abs(dif) < 10) & (r1 - 127 > 100)
        semi_static = morphology.binary_closing(semi_static, np.ones((10, 10)))
        semi_static = remove_small_objects(semi_static,
                                           min_size=200,
                                           in_place=True)
        q[-1].rgb[semi_static] = 0
        r2[semi_static] = np.nan

        cam.cloud_mask(camera, q[-1], q[-2])
        ###one-layer cloud masking
        if (q[-1].cm is None):
            q.popleft()
            continue
        if (np.sum(
            (q[-1].cm > 0)) < 2e-2 * img.nx * img.ny):  ######cloud free case
            q[-1].layers = 0
        else:
            dilated_cm = morphology.binary_dilation(q[-1].cm, np.ones(
                (15, 15)))
            dilated_cm &= (r2 > 0)
            vy, vx, max_corr = cam.cloud_motion(r1,
                                                r2,
                                                mask1=r1 > 0,
                                                mask2=dilated_cm,
                                                ratio=0.7,
                                                threads=4)
            if np.isnan(vy):
                q[-1].layers = 0
            else:
                q[-1].v += [[vy, vx]]
                q[-1].layers = 1

        q[-1].dump_img(tmpfs + f[-18:-10] + '/' + f[-23:-4] + '.pkl')
        q.popleft()
Beispiel #16
0
    yref = int(yref)

    img = plt.imread(f).astype(np.float32)
    img = img[roi]
    #     plt.figure(); plt.imshow(img/255);
    img = (0.8 * img[:, :, 2] + 0.2 * img[:, :, 0])
    #     img=np.nanmean(img,axis=2); #plt.figure(); plt.imshow(img)

    x1, x2 = max(0, xref - 150), min(nx0, xref + 150)
    y1, y2 = max(0, yref - 150), min(ny0, yref + 150)
    img = img[y1:y2, x1:x2]

    #     img_m=st.rolling_mean2(img,11)
    #     thresh=img_m>200

    img_m = st.rolling_mean2(img, 71, fill=0)
    img_m = img - img_m
    img_m -= np.nanmean(img_m)
    std = np.nanstd(img_m)
    thresh = img_m > 4 * std

    #     t=time.time()
    s = ndimage.generate_binary_structure(2, 2)  # iterate structure
    labeled_mask, cc_num = ndimage.label(thresh, s)
    try:
        thresh = (labeled_mask == (
            np.bincount(labeled_mask.flat)[1:].argmax() + 1))
    except:
        continue
    if np.sum(thresh) <= 9:
        print('Moon not found.')
def preprocess(camera,f,q,err,fft,convolver,flag):    
    img=cam.image(camera,f);  ###img object contains four data fields: rgb, red, rbr, and cm 
    img.undistort(rgb=True);  ###undistortion
    if img.red is None:
        return
#     ims = Image.fromarray(img.rgb); ims.save(outpath+camID+'/'+os.path.basename(f), "PNG"); continue
    img.cloud_mask();    ###one-layer cloud masking
    q.append(img)       
    if len(q)<=1: 
        return
    ####len(q) is always 2 beyond this point
    if (q[-1].time-q[-2].time).seconds>=MAX_INTERVAL:
        q.popleft();
        return;
#####cloud motion for the dominant layer    
#     im1=q[-2].red.copy().astype(np.float32); im2=q[-1].red.copy().astype(np.float32); 
#     vy,vx,max_corr = cam.cloud_motion(im1,im2,mask1=im1>5,mask2=np.abs(im1-im2)>15, ratio=0.7, threads=4) 
#     print(camera.camID+', ', f[-18:-4]+',  first layer2:',max_corr,vy,vx) 
    if convolver is None:
        shape=(camera.nx,camera.ny)
        convolver = mncc.Convolver(shape, shape, threads=4, dtype=np.float32)  # 
    for ii in range(len(fft)-2,0):
        im=q[ii].red.astype(np.float32);
        mask = im>0; #im[~mask]=0        
        fft.append(convolver.FFT(im,mask,reverse=flag[0]>0));
        flag[0] *= -1
    vy,vx,max_corr = cam.cloud_motion_fft(convolver,fft[-2],fft[-1],ratio=0.8); 
    if vx is None or vy is None: #####invalid cloud motion
        q.popleft(); fft.popleft();
        return
    vy*=flag[0]; vx*=flag[0]; 
    fft.popleft();
    print(camera.camID+', ', f[-18:-4]+',  first layer:',max_corr,vy,vx) 
#     plt.figure(); plt.imshow(q[-2].red); plt.colorbar(); plt.show();   
    return;

    q[-2].v+=[[vy,vx]]     
    red1=st.shift_2d(q[-1].rgb[:,:,0].astype(np.float32),-vx,-vy); red1[red1<=0]=np.nan
    red2=q[-2].rgb[:,:,0].astype(np.float32); red2[red2<=0]=np.nan #red2-=np.nanmean(red2-q[-1].rgb[:,:,0])
    er=red2-red1;   ###difference image after cloud motion adjustment
    er[(red1==0)|(red2==0)]=np.nan;
    a=er.copy(); a[a>0]=0; er-=st.rolling_mean2(a,500);
    if len(err) <= 0:
        err += [-st.shift_2d(er,vx,vy)] 
        return
    err_2=err[0].copy();  err[0] = (-st.shift_2d(er,vx,vy))
#     if vy**2+vx**2>=50**2:  ######The motion of the dominant layer is fast, likely low clouds. Do NOT trigger the second layer algorithm 
#        return 

#####process the secondary layer 
    ert=er+err_2;    
#     cm2=(er>15) | (er_p>15); cm2=remove_small_objects(cm2, min_size=500, connectivity=4);  
    scale=red2/np.nanmean(red2); nopen=max(5,int(np.sqrt(vx**2+vy**2)/3))
    cm2=(ert>15*scale) & (q[-2].cm); 
    cm2=morphology.binary_opening(cm2,np.ones((nopen,nopen)))
    cm2=remove_small_objects(cm2, min_size=500, connectivity=4);  
#    sec_layer=np.sum(cm2)/len(cm2.ravel())  ###the amount of clouds in secondary layer
    sec_layer=np.sum(cm2)/np.sum(q[-2].cm)  ###the amount of clouds in secondary layer
    if sec_layer<5e-2:   ###too few pixels in second layer, ignore the second cloud layer
        print('Second layer is small:', sec_layer*100, '%')
        return

#####cloud motion for the secondary layer   
    mask2=np.abs(err_2)>5;
    mask2=remove_small_objects(mask2, min_size=500, connectivity=4)
    mask2=filters.maximum_filter(mask2,20) 
    vy,vx,max_corr = cam.cloud_motion(err[0],err_2,mask1=None,mask2=mask2, ratio=None, threads=4) 
    if vx is None or vy is None:
        return
    q[-2].v+=[[vy,vx]]
    print(camera.camID+', ', f[-18:-4]+',  second layer:',max_corr,vy,vx) 
    
    if np.abs(vy-q[-2].v[0][0])+np.abs(vx-q[-2].v[0][1])>10:   
#     if np.abs(vy)+np.abs(vx)>0:
    #####obtain the mask for secondar cloud layer using a watershed-like algorithm    
        mred=q[-2].rgb[:,:,0].astype(np.float32)-st.fill_by_mean2(q[-2].rgb[:,:,0],200,mask=~cm2)
        mrbr=q[-2].rbr-st.fill_by_mean2(q[-2].rbr,200,mask=~cm2)
        merr=st.rolling_mean2(ert,200,ignore=np.nan); var_err=(st.rolling_mean2(ert**2,200,ignore=np.nan)-merr**2)
    #     mk=(np.abs(q[-2].rgb[:,:,0].astype(np.float32)-mred)<3) & ((total_err)>-2) & (np.abs(q[-2].rbr-mrbr)<0.05)
        mk=(np.abs(mred)<3) & (ert>-15) & (np.abs(mrbr)<0.05) & (var_err>20*20)
        cm2=morphology.binary_opening(mk|cm2,np.ones((nopen,nopen)))  ####remove line objects produced by cloud deformation
        cm2=remove_small_objects(cm2, min_size=500, connectivity=4)
        q[-2].layers=2; q[-2].cm[cm2]=2;  #####update the cloud mask with secondary cloud layer 
                
#         fig,ax=plt.subplots(2,2, sharex=True,sharey=True);  ####visualize the cloud masking results
#         ax[0,0].imshow(q[-2].rgb); ax[0,1].imshow(q[-2].cm)
#         ax[1,0].imshow(st.shift_2d(q[-1].rgb,-vx,-vy))  
#         ax[1,1].imshow(er,vmin=-25,vmax=25); plt.show();          
    return;
Beispiel #18
0
        yref = int(yref)

        img = plt.imread(f).astype(np.float32)
        img = img[roi]
        #     plt.figure(); plt.imshow(img/255);
        img = (0.8 * img[:, :, 2] + 0.2 * img[:, :, 0])
        #     img=np.nanmean(img,axis=2); #plt.figure(); plt.imshow(img)

        x1, x2 = max(0, xref - 150), min(nx0, xref + 150)
        y1, y2 = max(0, yref - 150), min(ny0, yref + 150)
        img = img[y1:y2, x1:x2]

        #     img_m=st.rolling_mean2(img,11)
        #     thresh=img_m>200

        img_m = st.rolling_mean2(img, 71, ignore=0)
        img_m = img - img_m
        img_m -= np.nanmean(img_m)
        std = np.nanstd(img_m)
        thresh = img_m > 4 * std

        #     t=time.time()
        s = ndimage.generate_binary_structure(2, 2)  # iterate structure
        labeled_mask, cc_num = ndimage.label(thresh, s)
        try:
            thresh = (labeled_mask == (
                np.bincount(labeled_mask.flat)[1:].argmax() + 1))
        except:
            continue
        if np.sum(thresh) <= 9:
            print('Moon not found.')
Beispiel #19
0
    def undistort(self, rgb=True, day_only=True):
        """
        Undistort the raw image, set rgb, red, rbr, cos_g
        Input: rgb and day_only flags
        Output: rgb, red, rbr, cos_g will be specified.
        """
        #####get the image acquisition time, this need to be adjusted whenever the naming convention changes
        self.time = datetime.strptime(self.fn[-18:-4], '%Y%m%d%H%M%S')
        t_std = self.time - timedelta(
            hours=5)  #####adjust UTC time into local standard time
        sz = 90 - ps.get_altitude(self.cam.lat, self.cam.lon, t_std)
        sz *= deg2rad
        self.sz = sz
        if day_only and sz > 75 * deg2rad:
            return

        saz = 360 - ps.get_azimuth(self.cam.lat, self.cam.lon, t_std)
        saz = (saz % 360) * deg2rad
        self.saz = saz

        try:
            im0 = plt.imread(self.fn)
        except:
            print('Cannot read file:', self.fn)
            return None
        im0 = im0[self.cam.roi]
        im0[~self.cam.valid0, :] = 0

        cos_sz = np.cos(sz)
        cos_g = cos_sz * np.cos(self.cam.theta0) + np.sin(sz) * np.sin(
            self.cam.theta0) * np.cos(self.cam.phi0 - saz)

        red0 = im0[:, :, 0].astype(np.float32)
        red0[red0 <= 0] = np.nan
        rbr0 = (red0 - im0[:, :, 2]) / (im0[:, :, 2] + red0)

        if np.nanmean(red0[(cos_g > 0.995) & (red0 >= 1)]) > 230:
            mk = cos_g > 0.98
            red0[mk] = np.nan
            rbr0[mk] = np.nan

        rbr = st.fast_bin_average2(rbr0, self.cam.weights)
        rbr = st.fill_by_mean2(rbr, 7, mask=(np.isnan(rbr)) & self.cam.valid)
        rbr[self.cam.invalid] = np.nan
        #         if np.nanmean(rbr[rbr>-0.7])<0:
        #             hist=np.histogram(rbr,bins=100,range=[-0.6,0.15]); bins=(hist[1][:-1]+hist[1][1:])/2
        #             cum=np.cumsum(hist[0]); cumi=np.cumsum(hist[0][::-1])
        #             x1=bins[np.argmax(cum>0.02*cum[-1])]; x2=bins[99-np.argmax(cumi>0.02*cum[-1])]
        #             print(x1,x2,np.nanmean(rbr[rbr>-0.7]))
        #             if (x2-x1)>=0.15 or ((x2-x1)>0.1 and x1<-0.2):
        #                 rbr=-0.6+0.75/(x2-x1)*(rbr-x1);
        self.rbr = rbr

        red0 -= st.rolling_mean2(red0, 300, ignore=np.nan)
        red = st.fast_bin_average2(red0, self.cam.weights)
        red = st.fill_by_mean2(red, 7, mask=(np.isnan(red)) & self.cam.valid)
        red[red > 50] = 50
        red[red < -50] = -50
        red = (red + 51) * 2.5 + 0.5
        red[self.cam.invalid] = 0
        self.red = red.astype(np.uint8)

        if rgb:
            im = np.zeros((self.cam.ny, self.cam.nx, 3), dtype=im0.dtype)
            for i in range(3):
                im[:, :, i] = st.fast_bin_average2(im0[:, :, i],
                                                   self.cam.weights)
                im[:, :, i] = st.fill_by_mean2(im[:, :, i],
                                               7,
                                               ignore=0,
                                               mask=(im[:, :, i] == 0) &
                                               (self.cam.valid))
#                 im[:,:,i]=st.fill_by_mean2(im[:,:,i],7, ignore=0, mask=np.isnan(red))
            im[(red <= 0) | (self.cam.invalid)] = 0
            self.rgb = im
            ResultTable.loc[index - 1]['MaxCorr1'] = max_corr

            ResultTable.to_csv(outpath_DataFrame + CamID + '_' + Date + '_' +
                               'Table.csv')

            #####put the error image into the queue, for use in the multi-layer cloud algorithm
            red1 = st.shift_2d(q[-1].rgb[:, :, 0].astype(np.float32), -vx, -vy)
            red1[red1 <= 0] = np.nan
            red2 = q[-2].rgb[:, :, 0].astype(np.float32)
            red2[red2 <= 0] = np.nan  #red2-=np.nanmean(red2-q[-1].rgb[:,:,0])
            er = red2 - red1
            ###difference image after cloud motion adjustment
            er[(red1 == 0) | (red2 == 0)] = np.nan
            a = er.copy()
            a[a > 0] = 0
            er -= st.rolling_mean2(a, 500)
            err.append(-st.shift_2d(er, vx, vy))

            if len(err
                   ) <= 1:  ####secondar layer processing requires three frames
                continue

            if vy**2 + vx**2 >= 50**2:  ######The motion of the dominant layer is fast, likely low clouds. Do NOT trigger the second layer algorithm
                err.popleft()
                continue

            #####process the secondary layer
            ert = er + err[-2]  ####total error
            scale = red2 / np.nanmean(red2)
            nopen = max(5, int(np.sqrt(vx**2 + vy**2) / 3))
            cm2 = (ert > 15 * scale) & (q[-2].cm)
Beispiel #21
0
        except:
            break
        im0=im0[roi[camera]]
        im0[theta_filter[camera],:]=np.nan   
#         plt.figure(); plt.imshow(im0/255)
         
        cx,cy=params[camera][2:0:-1]
        c1,c2,c3=params[camera][6:9]
        rref=c1*sz+c2*sz**3+c3*sz**5
        xsun,ysun=np.int(cx+nx0[camera]*rref*np.sin(saz+params[camera][3])+0.5),np.int(cy+ny0[camera]*rref*np.cos(saz+params[camera][3])+0.5) ####image coordinates of the sun
        sun_roi=np.s_[max(0,ysun-250):min(ny0[camera],ysun+250),max(0,xsun-250):min(nx0[camera],xsun+250)]
        cos_g=np.cos(sz)*np.cos(theta[camera][sun_roi])+np.sin(sz)*np.sin(theta[camera][sun_roi])*np.cos(phi[camera][sun_roi]-saz); 
        im0[sun_roi][cos_g>0.97]=np.nan
         
#         ###detrend the data
        im0_m=st.rolling_mean2(im0[:,:,0],100,fill=np.nan).astype(np.float32)
        im0[:,:,0]-=im0_m
         
        sun_line=np.abs(x0[camera]*np.cos(saz+params[camera][3] )-y0[camera]*np.sin(saz+params[camera][3] ))<40
        std=np.nanstd(im0[sun_line,0]);
        mk1=(np.abs(im0[:,:,0])>3*std) & sun_line              
        mk2=morphology.remove_small_objects(mk1, min_size=400, connectivity=4)
        im0[mk1!=mk2]=np.nan
                
        for i in range(1):
            im[cnt,:,:,i]=st.bin_average2_reg(im0[:,:,i],x[camera],y[camera],xbin,ybin,mask=valid);    
#             im[cnt,:,:,i]=st.fill_by_mean2(im[cnt,:,:,i],7, mask=(np.isnan(im[cnt,:,:,i])) & valid )  
#         print(time.time()-t0)  
        cnt+=1;  

    if cnt<=1: continue