PRO dical_interp, img, loc, VERT=vert, MAXSIZE=maxsize, FLAGS=flags $ , Fail2DBlobs=fail2db ;;----------------------------------------------------------------------------- ;; PURPOSE: ;; Performs thin plate spline interpolation across segments of the given ;; image. At the edges, pixels are repeated, instead of extrapolated. ;; ;; CALLING SEQUENCE: ;; DICal_interp, img, loc, /VERT ;; ;; REQUIRED INPUTS: ;; img - The image to perform the interpolation on ;; loc - result of a WHERE call specifiying where to interpolate over ;; ;; OUTPUTS: ;; The image with the areas interpolated over ;; ;; OPTIONAL INPUT KEYWORDS: ;; VERT - only interpolate in the vertical direction. Used for IR images. ;; MAXSIZE - the maximum size of a region to interpolate over in 2D interpolation ;; FLAGS - flags identifying where the invalid pixels are ;; ;; OPTIONAL OUTPUT KEYWORDS: ;; FAIL2DBLOBS - 0b on success, 1b if too many flagged pixels for find_2Dblobs to work. ;; ;; EXAMPLE: ;; IDL> dical_interp, in, loc ;; ;; PROCEDURES USED (i.e. called directly!): ;; find_2Dblobs ;; ;; MODIFICATION HISTORY: ;; 2004-08-19 M. Desnoyer Created ;; ;;----------------------------------------------------------------------------- @dical_flags img = double(img) dim = size(img, /dimensions) IF NOT keyword_set(maxSize) THEN maxSize = 9999 fail2db=0b ;;; assume success IF size(loc, /n_dimension) EQ 0 THEN RETURN ;; Nothing to interpolate over ;; Determine where the invalid data resides badData = where(flags NE 0) IF keyword_set(VERT) THEN BEGIN ;; 1D interpolation along the columns img = dical_irinterp(img,loc,badData) ;; Modify the flags flags[loc] = flags[loc] OR FLAG_INTERP ENDIF ELSE BEGIN ;; 2D Interpolation ;; Figure out where the edges are X = loc mod dim[0] Y = loc / dim[0] edge = where((X EQ 0) OR (Y EQ 0) OR (X EQ dim[0]-1) OR (Y EQ dim[1]-1), cnt,$ complement=w, ncomplement=compCnt) IF cnt GT 0 THEN BEGIN ;; Fill in the edges, for now, just use the ir routine because we ;; there will only be holes that can be filled using the vertical and ;; development time is limited. THIS MAY BE REVISITED img = dical_irinterp(img,loc[edge],badData) ;; Update the flag map flags[loc[edge]] = flags[loc[edge]] OR FLAG_INTERP ;; Update the pixels that need interpolation IF compCnt EQ 0 THEN RETURN loc = loc[w] ENDIF ;; Group the gaps by size gaps = find_2DBlobs(loc, dim[0], SIZE=gapSize, Fail2DBlobs=fail2db) if fail2db THEN RETURN ;; find_2DBlobs failed; do nothing ;; Remove the gaps that are too big justRight = where((gapSize[0,*]<gapSize[1,*]) LE maxSize, cnt) IF cnt EQ 0 THEN RETURN ;; Nothing to interpolate over toInterp = gaps[*,justRight] ;; Interpolate over the gaps IF size(toInterp, /N_DIMENSIONS) GT 1 THEN $ gapCnt = (size(toInterp, /DIMENSIONS))[1] $ ELSE $ gapCnt = 1 FOR i=0, gapCnt-1 DO BEGIN gloTodo = toInterp[*,i] ;; Pixels to interpolate in global coordinates gloTodo = gloTodo[where(gloTodo GE 0)] ;; Make sure the gap still exists IF (size(gloTodo,/n_dimensions))[0] EQ 0 THEN CONTINUE ;; Move the gap so that it's top corner is at (1,1) todo = [[gloTodo MOD dim[0]], [gloTodo/dim[0]]] corner = [min(todo[*,0]), min(todo[*,1])]-2 dataSize = gapSize[*,i]+4 ;; Adjust the corner in case we're on an edge IF corner[0] LT 0 THEN BEGIN corner[0] = 0 dataSize[0] = dataSize[0]-1 ENDIF IF corner[1] LT 0 THEN BEGIN corner[1] = 0 dataSize[1] = dataSize[1]-1 ENDIF IF corner[0]+dataSize[0] GT dim[0] THEN $ dataSize[0] = dim[0] - corner[0] IF corner[1]+dataSize[1] GT dim[1] THEN $ dataSize[1] = dim[1] - corner[1] todo[*,0] = todo[*,0]-corner[0] todo[*,1] = todo[*,1]-corner[1] todo = (dataSize[0])*todo[*,1]+todo[*,0] ;; Get the points around the gap that have valid values known = setdifference(indgen(dataSize[0]*dataSize[1],/LONG),todo) window = img[corner[0]:corner[0]+dataSize[0]-1, $ corner[1]:corner[1]+dataSize[1]-1] flagWnd = flags[corner[0]:corner[0]+dataSize[0]-1, $ corner[1]:corner[1]+dataSize[1]-1] flagWnd = flagWnd[known] known = known[where((flagWnd AND (FLAG_GAP OR FLAG_BAD)) EQ 0)] X = (known MOD (dataSize[0])) Y = (known / (dataSize[0])) ;; Do the actual interpolation IF max(gapSize[*,i]) EQ 1 THEN BEGIN ;; Do a weighted average of the pixels. This is done to save ;; time because 1 pixel holes are probably just bad pixels and ;; there could be a lot of them sq2 = sqrt(2) diag = ((X+Y) MOD 2) EQ 0 ; 1 if the element is on a diagonal tot = total(diag)/sq2 - total(diag-1) weight = diag/sq2 - (diag-1) tmp = total(img[X+corner[0],Y+corner[1]]*weight, /nan)$ /tot ENDIF ELSE $ tmp= grid_tps(X,Y,img[X+corner[0],Y+corner[1]],$ NGRID = dataSize, START=0, DELTA=1) img[gloTodo] = tmp[todo] flags[gloTodo] = flags[gloTodo] OR FLAG_INTERP ENDFOR ENDELSE RETURN END