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].cm[cm2] = 2 #####update the cloud mask with secondary cloud layer #####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[-1], err[-2], mask1=None, mask2=mask2, ratio=None, threads=4) ResultTable.loc[index - 1]['LayerNum'] = 2 ResultTable.loc[index - 1]['V2'] = (vy, vx) ResultTable.loc[index - 1]['MaxCorr2'] = max_corr ResultTable.to_csv(outpath_DataFrame + CamID + '_' + Date + '_' + 'Table.csv') err.popleft() except Exception as e: TxtFile = open(TxtFileName, 'a') TxtFile.write(TimeStamp)
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()
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;
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();