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
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(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
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
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()
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)
# ####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)
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;
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]
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
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();
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
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()
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;
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.')
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)
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