; $Id: search3d.pro,v 1.7 1997/01/15 03:11:50 ali Exp $ ; Copyright (c) 1992-1997, Research Systems, Inc. All rights reserved. ; Unauthorized reproduction prohibited. ; ;+ ; NAME: ; SEARCH3D ; ; PURPOSE: ; This function finds "objects" or regions of similar data ; values within a 3-D array of data. Given a starting location ; and a range of values to search for, SEARCH3D will find all ; the cells within the array that are within the specified range ; of values, and have some path of connectivity through these cells ; to the starting location. See the procedure "SEARCH2D" for the ; two dimensional case. ; ; This function returns a list of the array subscripts that define ; the selected object or region. ; ; CATEGORY: ; Data subsetting. ; Image manipulation. ; ; CALLING SEQUENCE: ; Region = SEARCH3D(Array, Xpos, Ypos, Zpos, Min_val, Max_val) ; ; INPUTS: ; Array: The 3-D array of data to search. ; Data type : Any 3-D array except string or structure. ; Xpos: The X coordinate(s) (first subscript into the 3-D Array) ; of the seed point(s) for the search. Xpos can be a ; single value, or an array of subscripts specifying the ; X coordinates of a seed region. Xpos must have the same ; number of elements as Ypos and Zpos. ; Data type : Long or Lonarr. ; Ypos: The Y coordinate(s) (second subscript into the 3-D Array) ; of the seed point(s) for the search. Ypos can be a ; single value, or an array of subscripts specifying the ; Y coordinates of a seed region. Ypos must have the same ; number of elements as Xpos and Zpos. ; Data type : Long or Lonarr. ; Zpos: The Z coordinate(s) (third subscript into the 3-D Array) ; of the seed point(s) for the search. Zpos can be a ; single value, or an array of subscripts specifying the ; Z coordinates of a seed region. Zpos must have the same ; number of elements as Xpos and Ypos. ; Data type : Long or Lonarr. ; Min_val: The minimum data value to search for. All cells that ; are connected to the starting cell, and have a value ; greater than or equal to Min_val and less than or equal ; to Max_val, will be considered part of the "object". ; If omitted, the default is MIN(Array[Xpos, Ypos, Zpos]) . ; Max_val: The maximum data value to search for. ; If omitted, the default is MAX(Array[Xpos, Ypos, Zpos]) . ; ; KEYWORD PARAMETERS: ; IMAGE: If set, SEARCH3D returns a bi-level volume (3-D byte array) ; with the same dimensions as Array, containing the value ; (1) where the object is, and (0) where it isn't. ; DIAGONAL: Normally, cells are considered adjacent only when ; cubes surrounding the cells share a common face. ; If a non-zero value is passed to DIAGONAL then ; SEARCH3D will also locate cells meeting the search ; criteria whose surrounding cubes share a common ; edge or corner. The default is no diagonal searching. ; Data type : int ; ; DECREASE: This keyword is now obsolete as are INCREASE and LPF_BAND. ; A better way to perform this operation is to pre-process ; the Array parameter before passing to SEARCH3D. ; INCREASE: See the DECREASE keyword. ; LPF_BAND: See the DECREASE keyword. ; ; OUTPUTS: ; This function returns a list of the indices into the 3-D array ; that are part of the located object or region. This list is ; returned as a LONARR(n) where n is the number of cells found. ; ; If the returned array of indices is called Region, and the ; size of the 3-D volume of data is size_x by size_y by size_z, ; then the actual X, Y, and Z indices can be obtained by using ; the following algorithm : ; ; index_z = Region / (size_x * size_y) ; index_y = (Region - (index_z * size_x * size_y)) / size_x ; index_x = (Region - (index_z * size_x * size_y)) - (index_y * size_x) ; ; The object within the 3-D Array could then be subscripted as : ; ; Array[Region] ; OR ; Array[index_x, index_y, index_z] ; ; If the IMAGE keyword is set, however, SEARCH3D returns a bi-level ; volume (3-D byte array) with the same dimensions as Array, containing ; the value (1) where the object is, and (0) where it isn't. ; ; EXAMPLE: ; Find all the indices corresponding to an object contained in a ; 3-D volume of data. ; ; ; Create some data. ; vol = RANDOMU(s, 40, 40, 40) ; vol[3:13, 1:15, 17:33] = 1.3 ; vol[15:25, 5:25, 15:25] = 0.2 ; vol[5:30,17:38,7:28] = 1.3 ; vol[9:23, 16:27, 7:33] = 1.5 ; ; ; Search for an object starting at (6, 22, 16) whose data values ; ; are between (1.2) and (1.4).. ; Region = SEARCH3D(vol, 6, 22, 16, 1.2, 1.4, /DIAGONAL) ; ; ; Scale the background cells into the range 0 to 127. ; vol = BYTSCL(vol, TOP=127B) ; ; ; Highlight the object region by setting it to 255. ; vol[Region] = 255B ; ; ; Set up a 3-D view. ; Window, 0, Xsize=640, Ysize=512, Retain=2 ; Create_View, Xmax=39, Ymax=39, Zmax=39, ax=(-30), az=30, zoom=0.8 ; ; ; Display the volume with the highlighted object in it. ; TVSCL, PROJECT_VOL(vol, 64, 64, 40, Depth_Q=0.4) ; ; MODIFICATION HISTORY: ; Written by: Daniel Carr. Thu Sep 3 17:36:04 MDT 1992 ; Modified: Daniel Carr. ; Re-wrote to improve performance using "DILATE". ; Obsoleted keywords INCREASE, DECREASE, and LPF_BAND. ; Added IMAGE keyword. ;- FUNCTION Search3d, array, xpos, ypos, zpos, min_val, max_val, $ Diagonal=diagonal, Object=object, Decrease=decrease, $ Increase=increase, Lpf_band=smooth_band ON_ERROR, 2 IF (N_Elements(decrease) GT 0L) THEN $ Print, 'Search3D: Obsolete keyword "DECREASE" ignored.' IF (N_Elements(increase) GT 0L) THEN $ Print, 'Search3D: Obsolete keyword "INCREASE" ignored.' IF (N_Elements(smooth_band) GT 0L) THEN $ Print, 'Search3D: Obsolete keyword "LPF_BAND" ignored.' IF (N_Elements(min_val) LE 0L) THEN min_val = MIN(array[xpos, ypos, zpos], Max=max_val) IF (N_Elements(max_val) LE 0L) THEN max_val = MAX(array[xpos, ypos, zpos]) s = Bytarr(3, 3, 3) IF (Keyword_Set(diagonal)) THEN s[*] = 1B $ ELSE BEGIN s[1, *, *] = 1B s[*, 1, *] = 1B s[*, *, 1] = 1B ENDELSE size_array = size(array) xmax = size_array[1] - 1L ymax = size_array[2] - 1L zmax = size_array[3] - 1L vol = Bytarr(size_array[1], size_array[2], size_array[3]) vol[xpos, ypos, zpos] = 1B ; Since "DILATE" does not handle the edges, it is necessary ; to propagate the edges manually. vol[1L, *, *] = vol[1L, *, *] > vol[0L, *, *] vol[xmax-1L, *, *] = vol[xmax-1L, *, *] > vol[xmax, *, *] vol[*, 1L, *] = vol[*, 1L, *] > vol[*, 0L, *] vol[*, ymax-1L, *] = vol[*, ymax-1L, *] > vol[*, ymax, *] vol[0, 0, 1L] = vol[*, *, 1L] > vol[*, *, 0L] vol[0, 0, zmax-1L] = vol[*, *, zmax-1L] > vol[*, *, zmax] vol = Temporary(vol) and ((array GE min_val) and (array LE max_val)) vol[xpos, ypos, zpos] = 1B last_found = 0L ne_obj = N_Elements(Where(vol)) WHILE (ne_obj ne last_found) DO BEGIN vol = Dilate(Temporary(vol), s) vol = Temporary(vol) and ((array GE min_val) and (array LE max_val)) vol[xpos, ypos, zpos] = 1B last_found = ne_obj ne_obj = N_Elements(Where(vol)) ENDWHILE IF (Keyword_Set(object)) THEN RETURN, vol $ ELSE RETURN, Where(vol) END