Homework 2 |
bay
Figure 1. Digital elevation map of the San Francisco Bay Area. | |
---|---|
We return the digital elevation map of the San Francisco Bay Area, shown in Figure .
In this exercise, we will separate the data into ``signal'' and ``noise'' by applying running mean and median filters. The result of applying a running median filter is shown in Figure 2. Running median effectively smooths the data by removing local outliers.
ave,res
Figure 2. Data separated into signal (a) and noise (b) by applying a running median filter. |
---|
The algorithm is implemented in programs below.
/* Apply running mean or median filter */ #include <rsf.h> static float slow_median(int n, float* list) /* find median by slow sorting, changes list */ { int k, k2; float item1, item2; for (k=0; k < n; k++) { item1 = list[k]; /* assume everything up to k is sorted */ for (k2=k; k2 > 0; k2-) { item2 = list[k2-1]; if (item1 >= item2) break; list[k2] = item2; } list[k2] = item1; } return list[n/2]; } int main(int argc, char* argv[]) { int w1, w2, nw, s1,s2, j1,j2, i1,i2,i3, n1,n2,n3; char *how; float **data, **signal, **win; sf_file in, out; sf_init (argc,argv); in = sf_input("in"); out = sf_output("out"); /* get data dimensions */ if (!sf_histint(in,"n1",&n1)) sf_error("No n1="); if (!sf_histint(in,"n2",&n2)) sf_error("No n2="); n3 = sf_leftsize(in,2); /* input and output */ data = sf_floatalloc2(n1,n2); signal = sf_floatalloc2(n1,n2); if (!sf_getint("w1",&w1)) w1=5; if (!sf_getint("w2",&w2)) w2=5; /* sliding window width */ nw = w1*w2; win = sf_floatalloc2(w1,w2); how = sf_getstring("how"); /* what to compute (fast median, slow median, mean) */ if (NULL == how) how="fast"; for (i3=0; i3 < n3; i3++) { /* read data plane */ sf_floatread(data[0],n1*n2,in); for (i2=0; i2 < n2; i2++) { s2 = SF_MAX(0,SF_MIN(n2-w2,i2-w2/2-1)); for (i1=0; i1 < n1; i1++) { s1 = SF_MAX(0,SF_MIN(n1-w1,i1-w1/2-1)); /* copy window */ for (j2=0; j2 < w2; j2++) { for (j1=0; j1 < w1; j1++) { win[j2][j1] = data[s2+j2][s1+j1]; } } switch (how[0]) { case 'f': /* fast median */ signal[i2][i1] = sf_quantile(nw/2,nw,win[0]); break; case 's': /* slow median */ signal[i2][i1] = slow_median(nw,win[0]); break; case 'm': /* mean */ /* !!! ADD CODE !!! */ break; default: sf_error("Unknown method "%s"",how); break; } } } /* write out */ sf_floatwrite(signal[0],n1*n2,out); } exit(0); } |
#!/usr/bin/env python import sys import numpy as np import m8r def slow_median(data): 'find median by slow sorting, changes data' n = len(data) for k in range(n): item1 = data[k] # assume everything up to k is sorted for k2 in range(k,-1,-1): item2 = data[k2-1] if item1 >= item2: break data[k2] = item2 data[k2] = item1 return data[n/2] # initialization par = m8r.Par() inp = m8r.Input() out = m8r.Output() # get data dimensions n1 = inp.int('n1') n2 = inp.int('n2') n3 = inp.leftsize(2) # input and output data = np.zeros([n2,n1],'f') signal = np.zeros([n2,n1],'f') # sliding window w1 = par.int('w1',5) w2 = par.int('w2',5) nw = w1*w2 win = np.zeros([w2,w1],'f') how = par.string('how','fast') # what to compute # (fast median, slow median, mean) for i3 in range(n3): # read data plane inp.read(data) for i2 in range(n2): sys.stderr.write("%d of %d" % (i2,n2)) s2 = max(0,min(n2-w2,i2-w2/2-1)) for i1 in range(n1): s1 = max(0,min(n1-w1,i1-w1/2-1)) # copy window win = data[s2:s2+w2,s1:s1+w1] if how[0] == 'f': # fast median signal[i2,i1] = np.median(win) elif how[0] == 's': # slow median signal[i2,i1] = slow_median(win.flatten()) elif how[0] == 'm': # mean # !!! ADD CODE !!! pass else: sys.stderr.write( "Unknown method "%s"" % how) sys.exit(1) sys.stderr.write("") # write out out.write(signal) sys.exit(0) |
scons viewto reproduce the figures on your screen.
scons time.vplto display a figure that compares the efficiency of running median computations using the slow sorting from function median in program run.c (or run.py) and the fast median algorithm. Your goal is to make the algorithm even faster. You may consider parallelization, reusing previous windows, other fast sorting strategies, etc.
from rsf.proj import * # Download data Fetch('bay.h','bay') # Convert format Flow('bay','bay.h', ''' dd form=native | window f2=500 n2=1500 ''') # Display def plot(title): return ''' grey allpos=y title="%s" yreverse=n label1=South-North label2=West-East screenratio=0.8 ''' % title Result('bay',plot('Digital Elevation Map')) # Program for running average run = Program('run.c') # COMMENT ABOVE AND UNCOMMENT BELOW IF YOU WANT TO USE PYTHON # run = Command('run.exe','run.py','cp $SOURCE $TARGET') # AddPostAction(run,Chmod(run,0o755)) w = 30 # !!! CHANGE BELOW !!! Flow('ave','bay %s' % run[0], './${SOURCES[1]} w1=%d w2=%d how=fast' % (w,w)) Result('ave',plot('Signal')) # Difference Flow('res','bay ave','add scale=1,-1 ${SOURCES[1]}') Result('res',plot('Noise') + ' allpos=n') ############################################################# import sys if sys.platform=='darwin': gtime = WhereIs('gtime') if not gtime: print("For computing CPU time, install gtime.") else: gtime = WhereIs('gtime') or WhereIs('time') # slow or fast for case in ('fast','slow'): ts = [] ws = [] time = 'time-' + case wind = 'wind-' + case # loop over window size for w in range(3,16,2): itime = '%s-%d' % (time,w) ts.append(itime) iwind = '%s-%d' % (wind,w) ws.append(iwind) # measure CPU time Flow(iwind,None,'spike n1=1 mag=%d' % (w*w)) Flow(itime,'bay %s' % run[0], ''' ( (%s -f "%%S %%U" ./${SOURCES[1]} < ${SOURCES[0]} w1=%d w2=%d how=%s > /dev/null ) 2>&1 ) > time.out && (tail -1 time.out; echo in=time0.asc n1=2 data_format=ascii_float) > time0.asc && dd form=native < time0.asc | stack axis=1 norm=n > $TARGET && /bin/rm time0.asc time.out ''' % (gtime,w,w,case),stdin=0,stdout=-1) Flow(time,ts,'cat axis=1 ${SOURCES[1:%d]}' % len(ts)) Flow(wind,ws,'cat axis=1 ${SOURCES[1:%d]}' % len(ws)) # complex numbers for plotting Flow('c'+time,[wind,time], ''' cat axis=2 ${SOURCES[1]} | transp | dd type=complex ''') # Display CPU time Plot('time','ctime-fast ctime-slow', ''' cat axis=1 ${SOURCES[1]} | transp | graph dash=0,1 wanttitle=n label2="CPU Time" unit2=s label1="Window Size" unit1= ''',view=1) End() |
Homework 2 |