Пример #1
0
 def find_matching_labels(self,goodness_threshold=0.6,rad=3):
     modeldb = H5(ocfg.model_database)
     print modeldb.h5.keys()
     guess_dicts = [{}]
     goodnesses = [-np.inf]
     for key in modeldb.h5.keys():
         guess_dict = {}
         test = modeldb.get(key)['profile'][:]
         if len(test)>len(self.profile):
             test_profile = test[:len(self.profile)]
         elif len(test)<len(self.profile):
             test_profile = np.zeros(len(self.profile))
             test_profile[:len(test)] = test
         else:
             test_profile = test
         offset,goodness = translation1(test_profile,self.profile,debug=False)
         self.logger.info('Comparing with model labels from %s: goodness %0.3f.'%(key,goodness))
         if goodness>goodness_threshold:
             test_labels = modeldb.get(key)['labels'].keys()
             if len(test_labels)>0:
                 for test_label in test_labels:
                     search_position = modeldb.get(key)['labels'][test_label].value - offset
                     temp = np.zeros(self.profile.shape)
                     temp[search_position-rad:search_position+rad+1] = self.profile[search_position-rad:search_position+rad+1]
                     guess_dict[test_label] = np.argmax(temp)
                 guess_dicts.append(guess_dict)
                 goodnesses.append(goodness)
     
     return guess_dicts[np.argmax(goodnesses)]
Пример #2
0
 def plot_at(x):
     global current_label,bscanindex
     
     if x in label_dict.values():
         existing_label = [key for key, value in label_dict.items() if value == x][0]
     else:
         existing_label = ''
     
     plt.axes([l1,b2,hw,hh])
     plt.cla()
     bscan = np.abs(self.h5.h5[self.data_block][0,bscanindex,:,:])
     #bscan = shear(bscan,1)
     try:
         test = np.mean(bscan[:,-20:],axis=1)
     except:
         test = np.mean(bscan,axis=1)
     offset,goodness = translation1(test,working_profile,xlims=10,equalize=True)
     
     cmin = np.median(bscan)
     cmax = np.percentile(bscan,99.95) # saturate 0.05% of pixels
     plt.imshow(bscan,interpolation='none',clim=(cmin,cmax),cmap='gray')
     for label in label_dict.keys():
         print label,label_dict[label]
         label_z = z[label_dict[label]]
         th = plt.text(bscan.shape[1],label_z-offset,label,ha='left',va='center',fontsize=8)
     try:
         plt.ylim((np.max(label_dict.values())+10,np.min(label_dict.values())-10))
     except:
         pass
         
     plt.axes([l1,b1,fw,hh])
     plt.cla()
     plt.plot(z,working_profile)
     plt.plot(z[x],working_profile[x],'ks')
     valid = np.where(working_profile)[0]
     plt.xlim((valid[0],valid[-1]))
     plt.autoscale(False)
     for label in label_dict.keys():
         label_z = z[label_dict[label]]
         th = plt.text(label_z,working_profile[label_z],label,ha='center',va='bottom')
         
     plt.axes([l2,b2,hw,hh])
     plt.cla()
     plt.plot(z,working_profile)
     plt.plot(z[x],working_profile[x],'ks')
     plt.xlim((z[x]-10,z[x]+10))
     z1 = max(0,x-10)
     z2 = min(len(z),x+10)
     ymin = np.min(working_profile[z1:z2])
     ymax = np.max(working_profile[z1:z2])*1.25
     plt.text(z[x],working_profile[x],existing_label,ha='center',va='bottom')
     plt.ylim((ymin,ymax))
     plt.title(current_label)
     plt.draw()
Пример #3
0
    def align_volume(self,vidx=0,rad=5):
        self.logger.info('align_volume: Starting')
        self.logger.info('align_volume: Getting volume from data store.')
        avol = np.abs(self.h5.get(self.data_block)[vidx,:,:,:])
        avol = np.swapaxes(avol,0,1)

        

        self.logger.info('align_volume: Smoothing volume with smoothing kernel of size %d pixels.'%rad)
        if rad:
            print time.time()
            avol = lateral_smooth_3d(avol,rad)
            print time.time()
            sys.exit()
            
        ndepth,nslow,nfast = avol.shape
        offset_submatrix = np.zeros((nslow,nfast))
        goodness_submatrix = np.zeros((nslow,nfast))
        profile = self.profile
        
        if len(profile)>ndepth:
            profile = profile[:ndepth]
        if ndepth>len(profile):
            avol = avol[:len(profile),:,:]
            ndepth,nslow,nfast = avol.shape

        x = []
        y = []
        z = []
        w = []
        for islow in range(nslow):
            pct_done = int(round(100*float(islow)/float(nslow)))
            if islow%10==0:
                self.logger.info('align_volume: Aligning A-scans, volume %d is %d percent done.'%(vidx,pct_done))
            for ifast in range(nfast):
                test = avol[:,islow,ifast]
                offset,goodness = translation1(profile,test,debug=False)
                x.append(ifast)
                y.append(islow)
                z.append(offset)
                w.append(goodness)
            
                offset_submatrix[islow,ifast] = offset
                goodness_submatrix[islow,ifast] = goodness

        fitting = True
        if fitting: # revisit this later; may be of use
            ptile = 75
            goodness_threshold=np.percentile(w,ptile)
            self.logger.info('align_volume: Goodness %dth percentile %0.3f used as threshold.'%(ptile,goodness_threshold))
            valid = np.where(w>goodness_threshold)[0]
            x0 = x
            y0 = y
            self.logger.info('align_volume: Using %d of %d points (%d percent) for fit.'%(len(valid),len(w),float(len(valid))/float(len(w))*100))
            x = np.array(x)
            y = np.array(y)
            z = np.array(z)
            w = np.array(w)

            x = x[valid]
            y = y[valid]
            z = z[valid]
            w = w[valid]


            mode='median_filter'
            
            if mode=='spline':
                self.logger.info('Spline fitting surface to A-line axial positions.')
                tck = bisplrep(x,y,z,w=w,xb=0,xe=nfast-1,yb=0,ye=nslow-1)
                self.logger.info('Evaluating spline function at A-line coordinates.')
                fit_surface = bisplev(np.arange(nslow),np.arange(nfast),tck)

            if mode=='polyfit2d':
                self.logger.info('Polynomial fitting surface to A-line axial positions.')
                p = polyfit2d(x,y,z,order=2)
                self.logger.info('Evaluating polynomial function at A-line coordinates.')
                xx,yy = np.meshgrid(np.arange(nfast),np.arange(nslow))
                fit_surface = polyval2d(xx,yy,p)

            if mode=='median_filter':
            # This is a dumb way to fit. Use the goodness matrix, dummy, perhaps with 2D splines!
                self.logger.info('Median filtering to create a smoothed offset surface.')
                slow_height = np.median(offset_submatrix,axis=1)
                plt.figure()
                plt.plot(slow_height)
                plt.figure()
                debias = (offset_submatrix.T-slow_height).T

                
                plt.figure()
                plt.imshow(debias)
                plt.colorbar()
                
                fit_surface_1 = median_filter(offset_submatrix,(3,3))
                plt.figure()
                plt.imshow(fit_surface_1)
                plt.title('straight fit')
                plt.colorbar()
                
                fit_surface_2 = (median_filter(debias,(3,3)).T+slow_height).T
                plt.figure()
                plt.imshow(fit_surface_2)
                plt.title('debiased fit')
                plt.colorbar()
                plt.show()
                sys.exit()

            if mode=='interp2d':
                self.logger.info('Using interp2d to create a smoothed offset surface.')
                interpolation_function = interp2d(x,y,z)
                fit_surface = interpolation_function(x0,y0)
                print fit_surface
                print fit_surface.shape

            
    
            # print fit_surface
            # print fit_surface.shape
            if True:
                clim = np.min(offset_submatrix),np.max(offset_submatrix)
                plt.figure()
                plt.imshow(offset_submatrix,interpolation='none',clim=clim)
                plt.colorbar()
                plt.figure()
                plt.imshow(fit_surface,interpolation='none',clim=clim)
                plt.colorbar()
                plt.figure()
                plt.imshow(offset_submatrix-fit_surface,interpolation='none')
                plt.colorbar()

                plt.show()


            #goodness_used = np.zeros(goodness_submatrix.shape)
            #goodness_used[np.where(goodness_submatrix>goodness_threshold)] = 1.0
        else:
            fit_surface = offset_submatrix
            
        return offset_submatrix,goodness_submatrix,fit_surface
Пример #4
0
    def make_bscan(self,factor):
        # select region for B-projection
        x,y = self.click_collector(self.cones,'Click top and bottom edges of region for B-scan')
        if len(x)<2:
            self.acdb.close()
            sys.exit('Done!')
            
        x1 = np.min(x)
        x2 = np.max(x)
        y1 = np.min(y)
        y2 = np.max(y)
        sy,sx = self.cones.shape
        y1 = max(0,y1)
        y2 = min(sy,y2)

        subvol = self.volume[y1:y2,:,:]

        subvol_scaled = []
        profs = []

        newsy = factor[0]*subvol.shape[1]
        newsx = factor[1]*subvol.shape[2]
        
        for iy in range(subvol.shape[0]):
            #scaled = self.fftinterp(subvol[iy,:,:],factor)
            #scaled = self.fftinterp2(subvol[iy,:,:],factor)
            scaled = sp.misc.imresize(subvol[iy,:,:],(newsy,newsx))
            subvol_scaled.append(scaled)
            profs.append(np.mean(scaled,axis=1))


        sy = len(profs[0])
        
        shifts = [0]
        for prof in profs[1:]:
            tx,g = translation1(profs[0],prof)
            shifts.append(tx)

        shifts = -np.array(shifts)
        
        shifts = shifts - np.min(shifts)
        cropped_sy = sy - np.max(shifts)

        aligned = []
        
        for im,x in zip(subvol_scaled,shifts):
            im = im[x:x+cropped_sy,:]
            aligned.append(im)

        aligned = np.array(aligned)
        
        bscan_linear = np.mean(aligned,axis=0)
        bscan_log = np.log(bscan_linear)

        cclims = np.percentile(self.cones[20:-20,20:-20],(1,99))
        pclims = np.percentile(bscan_linear,(2,99.5))
        plclims = np.percentile(bscan_log,(5,99.5))

        bscan_tag = '%s_%03d_%03d'%(self.tag,y1,y2)

        cones_fn = os.path.join(self.outdir,'%s_cones.png'%(self.tag))
        self.savefig(cones_fn,self.cones,percentiles=(.5,99.9),hspan=None,scale_factor=3.0)

        isos_fn = os.path.join(self.outdir,'%s_isos.png'%(self.tag))
        self.savefig(isos_fn,self.isos,percentiles=(.5,99.9),hspan=None,scale_factor=3.0)

        cost_fn = os.path.join(self.outdir,'%s_cost.png'%(self.tag))
        self.savefig(cost_fn,self.cost,percentiles=(.5,99.9),hspan=None,scale_factor=3.0)

        cones_fn = os.path.join(self.outdir,'%s_cones.png'%bscan_tag)
        self.savefig(cones_fn,self.cones,percentiles=(.5,99.9),hspan=[y1,y2],scale_factor=3.0)

        


        
        linear_fn = os.path.join(self.outdir,'%s_bscan_linear.png'%bscan_tag)
        self.savefig(linear_fn,bscan_linear,percentiles=(2,99.9),scale_factor=3.0)
        log_fn = os.path.join(self.outdir,'%s_bscan_log.png'%bscan_tag)
        self.savefig(log_fn,bscan_log,percentiles=(3,99.75),scale_factor=3.0)
        plt.show()
        plt.close('all')
Пример #5
0
    def align_volume_multiscale(self,vidx=0,rad=2,debug=True):
        self.logger.info('align_volume_multiscale: Starting')
        self.logger.info('align_volume_multiscale: Getting volume from data store.')
        avol = np.abs(self.h5.get(self.data_block)[vidx,:,:,:])
        avol = np.swapaxes(avol,0,1)


        avol = (avol-np.mean(avol,axis=0))/np.std(avol,axis=0)
        

        # NOTE TO SELF: DON'T F*****G FORGET TO REMOVE THIS, YOU F*****G IDIOT
        # IF YOU DO, IT WILL RUIN YOUR LIFE FOR A MONTH WHILE YOU DEBUG IT
        # NOTE TO SELF: DON'T F*****G FORGET TO REMOVE THIS, YOU F*****G IDIOT
        # IF YOU DO, IT WILL RUIN YOUR LIFE FOR A MONTH WHILE YOU DEBUG IT
        # NOTE TO SELF: DON'T F*****G FORGET TO REMOVE THIS, YOU F*****G IDIOT
        # IF YOU DO, IT WILL RUIN YOUR LIFE FOR A MONTH WHILE YOU DEBUG IT
        # NOTE TO SELF: DON'T F*****G FORGET TO REMOVE THIS, YOU F*****G IDIOT
        # IF YOU DO, IT WILL RUIN YOUR LIFE FOR A MONTH WHILE YOU DEBUG IT
        # NOTE TO SELF: DON'T F*****G FORGET TO REMOVE THIS, YOU F*****G IDIOT
        # IF YOU DO, IT WILL RUIN YOUR LIFE FOR A MONTH WHILE YOU DEBUG IT
        # NOTE TO SELF: DON'T F*****G FORGET TO REMOVE THIS, YOU F*****G IDIOT
        # IF YOU DO, IT WILL RUIN YOUR LIFE FOR A MONTH WHILE YOU DEBUG IT
        avol = avol[:,:-2,:]

        

        ndepth,nslow,nfast = avol.shape
        profile = np.zeros(self.profile.shape)
        profile[...] = self.profile[...]
        profile = (profile-np.mean(profile))/np.std(profile)


        
        if len(profile)>ndepth:
            profile = profile[:ndepth]
        if ndepth>len(profile):
            avol = avol[:len(profile),:,:]
            ndepth,nslow,nfast = avol.shape

        gross_profile = np.mean(np.mean(avol,axis=2),axis=1)
        gross_offset,gross_goodness = translation1(gross_profile,profile,debug=False)
        
        offset_submatrix = np.ones((nslow,nfast))*gross_offset
        goodness_submatrix = np.ones((nslow,nfast))*gross_goodness

        # def smooth(v,k):
        #     # an interface to lateral_smooth_3d that handles the
        #     # transposing to minimize confusion
            
        #     return np.transpose(lateral_smooth_3d(np.transpose(avol_bc,(2,0,1)),k),(1,2,0))

        def show_brightest_layer(v):
            # assumes depth is first dimension
            p = np.mean(np.mean(v,axis=2),axis=1)
            mdepth = np.argmax(p)
            layer = v[mdepth,:,:]
            plt.figure()
            plt.imshow(layer)
            plt.colorbar()

        

        # fft the model, for cross-correlation by broadcasting
        f0 = np.fft.fft(profile,axis=0)
        self.logger.info('align_volume_multiscale: model length %d, FFT length %d.'%(len(profile),len(f0)))

        started = False
        sz,sy,sx = avol.shape
        initial_step = float(max(sy,sx))
        final_exp = -np.log(1.49999/initial_step)
        steps = np.round(200*np.exp(-np.linspace(0.0,final_exp,10)))
        
        for k in steps:
            self.logger.info('align_volume_multiscale: smoothing layers in the volume')
            smoothed_avol = lateral_smooth_3d(avol,k)
            # depth is still first dimension

            f1 = np.fft.fft(smoothed_avol,axis=0)
            f1c = f1.conjugate()

            # transpose depth to the final dimension:
            f1_transposed = np.transpose(f1,(1,2,0))
            f1c_transposed = np.transpose(f1c,(1,2,0))
            num_transposed = f0*f1c_transposed
            denom_transposed = np.abs(f0)*np.abs(f1_transposed)
            frac_transposed = num_transposed/denom_transposed

            # now transpose back:
            frac = np.transpose(frac_transposed,(2,0,1))
            
            
            ir = np.abs(np.fft.ifft(frac,axis=0))
            print np.mean(ir),np.max(ir),np.min(ir)

            
            goodness = np.max(ir,axis=0)
            tx = np.argmax(ir,axis=0)

            if not started:
                #goodness_final = goodness.copy()
                #tx_final = tx.copy()
                goodness_final = np.zeros(goodness.shape)
                tx_final = np.zeros(tx.shape)

                goodness_final[...] = goodness[...]
                tx_final[...] = tx[...]
                
                started = True
                better_goodness_mask = np.zeros(goodness.shape)
                small_shifts_mask = np.zeros(tx.shape)
            else:
                better_goodness = (goodness-goodness_final)>-.2
                shift_limit = 10
                small_shifts = np.abs(tx-tx_final)<shift_limit

                better_goodness_mask = np.zeros(goodness.shape)
                better_goodness_mask[np.where(better_goodness)] = 1.0
                small_shifts_mask = np.zeros(tx.shape)
                small_shifts_mask[np.where(small_shifts)] = 1.0


            refinements = better_goodness_mask*small_shifts_mask
            refined_idx = np.where(refinements)
            print refined_idx
            goodness_final[refined_idx] = goodness[refined_idx]
            tx_final[refined_idx] = tx[refined_idx]
            
            if debug:
                plt.clf()
                plt.subplot(2,4,1)
                plt.cla()
                plt.imshow(goodness-goodness_final,cmap='gray')
                plt.colorbar()
                plt.title('$\Delta$ current goodness k=%d'%k)

                plt.subplot(2,4,2)
                plt.cla()
                plt.imshow(tx-tx_final,cmap='gray')
                plt.colorbar()
                plt.title('$\Delta$ current tx k=%d'%k)

                plt.subplot(2,4,3)
                plt.cla()
                plt.imshow(better_goodness_mask,cmap='gray')
                plt.title('better_goodness_mask')
                plt.colorbar()
                
                plt.subplot(2,4,4)
                plt.cla()
                plt.imshow(refinements,cmap='gray')
                plt.title('refinements')
                plt.colorbar()
                
                plt.subplot(2,4,5)
                plt.cla()
                plt.imshow(goodness_final,cmap='gray')
                plt.colorbar()
                plt.title('overall goodness k=%d'%k)

                plt.subplot(2,4,6)
                plt.cla()
                plt.imshow(tx_final,cmap='gray')
                plt.colorbar()
                plt.title('overall tx k=%d'%k)

                plt.subplot(2,4,7)
                plt.cla()
                plt.imshow(small_shifts_mask,cmap='gray')
                plt.colorbar()
                plt.title('small_shifts_mask')
                
                plt.subplot(2,4,8)
                plt.cla()
                plt.imshow(np.mean(smoothed_avol,axis=2),cmap='gray')
                plt.colorbar()

                
                plt.show()
Пример #6
0
def align_volume_to_profile_multiscale(avol,profile,debug=False):
    # put depth first
    avol = np.swapaxes(avol,0,1)

    # for testing use a recognizable image:
    #avol = np.load('/home/rjonnal/code/octopod/kid_with_grenade_volume.npy')
    
    ndepth,nslow,nfast = avol.shape
    profile = (profile-np.mean(profile))/np.std(profile)

    if len(profile)>ndepth:
        print 'growing volume to to %d pixels'%len(profile)
        new_avol = np.ones((len(profile),nslow,nfast))*np.mean(avol)
        new_avol[:ndepth,:,:] = avol
        avol = new_avol
    elif ndepth>len(profile):
        print 'growing profile ot %d pixels'%ndepth
        new_profile = np.ones(ndepth)*np.mean(profile)
        new_profile[:len(profile)] = profile
        profile = new_profile
    else:
        print 'profile and volume match in depth'

    plen = len(profile)
        
    gross_profile = np.mean(np.mean(avol,axis=2),axis=1)
    gross_offset,gross_goodness = translation1(gross_profile,profile,debug=False)
    
    
    offset_submatrix = np.ones((nslow,nfast))*gross_offset
    goodness_submatrix = np.ones((nslow,nfast))*gross_goodness

    def show_brightest_layer(v,mdepth=None,tstring=''):
        if mdepth is None:
            # assumes depth is first dimension
            p = np.mean(np.mean(v,axis=2),axis=1)
            mdepth = np.argmax(p)
        print 'showing layer %d'%mdepth
        layer = v[mdepth,:,:]
        plt.figure()
        plt.imshow(layer)
        plt.title(tstring)
        plt.colorbar()
        return mdepth

    def show_four(v,tstring='',other=None):
        plt.figure()
        p = np.mean(np.mean(v,axis=2),axis=1)
        idx = np.argsort(p)[::-1]
        if other is not None:
            extrapanel = 1
        else:
            extrapanel = 0
        for k in range(4):
            depth = idx[k]
            plt.subplot(1,4+extrapanel,k+1)
            plt.imshow(v[depth,:,:],cmap='gray')
            plt.colorbar()
            plt.title(depth)
        if extrapanel:
            plt.subplot(1,5,5)
            plt.imshow(other)
            plt.colorbar()

    # fft the model, for cross-correlation by broadcasting
    f0 = np.fft.fft(profile,axis=0)

    started = False
    sz,sy,sx = avol.shape
    initial_step = float(max(sy,sx))/4.0
    #final_exp = -np.log(1.49999/initial_step)
    #steps = np.round(100*np.exp(-np.linspace(0.0,final_exp,8)))
    #steps = np.array([50,40,30,25,20,15,10,8,6,5,4,3,2,1])
    n_steps = 3
    step_steepness = 5.0
    steps = np.linspace(initial_step**(1.0/step_steepness),0.8,n_steps)**step_steepness/2.0
    ellipticities = np.linspace(1.0,0.5**.25,n_steps)**4

    #print steps
#    show_volume = True
#    if show_volume:
#        for s in range(avol.shape[1]):
#            plt.cla()
#            plt.imshow(avol[:,s,:],clim=clim,cmap='gray')
#            plt.pause(.001)

    for rad,ellip in zip(steps,ellipticities):
        smoothed_avol,kernel = lateral_smooth_3d(avol,rad,ellipticity=0.8)
        # depth is still first dimension

        #show_four(avol,other=kernel)
        #show_four(smoothed_avol,other=kernel)
        #plt.show()
        
        smoothed_avol = (smoothed_avol-np.mean(smoothed_avol,axis=0))/np.std(smoothed_avol,axis=0)
        #show_brightest_layer(smoothed_avol)
        
        f1 = np.fft.fft(smoothed_avol,axis=0)
        f1c = f1.conjugate()

        # transpose depth to the final dimension:
        f1_transposed = np.transpose(f1,(1,2,0))
        f1c_transposed = np.transpose(f1c,(1,2,0))
        num_transposed = f0*f1c_transposed
        
        denom_transposed = np.abs(f0)*np.abs(f1_transposed)

        denom_transposed[np.where(denom_transposed==0)]=1.0
        
        frac_transposed = num_transposed/denom_transposed

        # now transpose back:
        frac = np.transpose(frac_transposed,(2,0,1))


        ir = np.abs(np.fft.ifft(frac,axis=0))

        goodness = np.max(ir,axis=0)
        tx = np.argmax(ir,axis=0)
        tx[np.where(tx>plen//2)] = tx[np.where(tx>plen//2)] - plen
        
        #if tx > shape // 2:
        #    tx -= shape

        if not started:
            #goodness_final = goodness.copy()
            #tx_final = tx.copy()
            goodness_final = np.zeros(goodness.shape)
            tx_final = np.zeros(tx.shape)

            goodness_final[...] = goodness[...]
            tx_final[...] = tx[...]

            started = True
            better_goodness_mask = np.zeros(goodness.shape)
            small_shifts_mask = np.zeros(tx.shape)
        else:
            better_goodness = (goodness-goodness_final)>0.0
            shift_limit = 10
            small_shifts = np.abs(tx-tx_final)<shift_limit

            better_goodness_mask = np.zeros(goodness.shape)
            better_goodness_mask[np.where(better_goodness)] = 1.0
            small_shifts_mask = np.zeros(tx.shape)
            small_shifts_mask[np.where(small_shifts)] = 1.0


        refinements = better_goodness_mask*small_shifts_mask
        refined_idx = np.where(refinements)
        goodness_final[refined_idx] = goodness[refined_idx]
        tx_final[refined_idx] = tx[refined_idx]

        if debug:
            plt.subplot(1,2,1)
            plt.cla()
            plt.plot(np.mean(np.mean(smoothed_avol,axis=2),axis=1))
            plt.plot(profile)
            plt.title(rad)
            plt.subplot(1,2,2)
            plt.cla()
            plt.imshow(tx_final)
            plt.title('%d,%d'%(tx_final.min(),tx_final.max()))
            plt.pause(1)

    if debug:
        plt.subplot(1,2,1)
        plt.cla()
        plt.plot(np.mean(np.mean(smoothed_avol,axis=2),axis=1))
        plt.plot(profile)
        plt.subplot(1,2,2)
        plt.cla()
        plt.imshow(tx_final)
        plt.title('final %d,%d'%(tx_final.min(),tx_final.max()))
        plt.pause(1)

    return tx_final,goodness_final