github.com/janelia-flyem/dvid@v1.0.0/datatype/common/labels/index.go (about)

     1  package labels
     2  
     3  import (
     4  	fmt "fmt"
     5  	"sort"
     6  
     7  	"github.com/janelia-flyem/dvid/datatype/common/proto"
     8  	"github.com/janelia-flyem/dvid/dvid"
     9  )
    10  
    11  type Index struct {
    12  	proto.LabelIndex
    13  }
    14  
    15  // EncodeBlockIndex converts signed (x,y,z) block coordinate into
    16  // a single uint64, which is packed in ZYX order with MSB empty,
    17  // the most-significant 21 bits is Z (21st bit is sign flag), next
    18  // 21 bits is Y, then least-significant 21 bits is X.
    19  func EncodeBlockIndex(x, y, z int32) (zyx uint64) {
    20  	if z < 0 {
    21  		zyx |= 0x00100000
    22  		z = -z
    23  	}
    24  	zyx |= uint64(z & 0x000FFFFF)
    25  	zyx <<= 21
    26  	if y < 0 {
    27  		zyx |= 0x00100000
    28  		y = -y
    29  	}
    30  	zyx |= uint64(y & 0x000FFFFF)
    31  	zyx <<= 21
    32  	if x < 0 {
    33  		zyx |= 0x00100000
    34  		x = -x
    35  	}
    36  	zyx |= uint64(x & 0x000FFFFF)
    37  	return
    38  }
    39  
    40  // IZYXStringToBlockIndex returns an encoded Block Index for a given IZYXString,
    41  // returning an error if the IZYXString is formatted incorrectly.
    42  func IZYXStringToBlockIndex(s dvid.IZYXString) (zyx uint64, err error) {
    43  	var blockPt dvid.ChunkPoint3d
    44  	blockPt, err = s.ToChunkPoint3d()
    45  	if err != nil {
    46  		return
    47  	}
    48  	return EncodeBlockIndex(blockPt[0], blockPt[1], blockPt[2]), nil
    49  }
    50  
    51  // DecodeBlockIndex decodes a packed block index into int32 coordinates.
    52  // At most, each block int32 coordinate can be 20 bits.
    53  func DecodeBlockIndex(zyx uint64) (x, y, z int32) {
    54  	x = int32(zyx & 0x00000000000FFFFF)
    55  	if zyx&0x0000000000100000 != 0 {
    56  		x = -x
    57  	}
    58  	zyx >>= 21
    59  	y = int32(zyx & 0x00000000000FFFFF)
    60  	if zyx&0x0000000000100000 != 0 {
    61  		y = -y
    62  	}
    63  	zyx >>= 21
    64  	z = int32(zyx & 0x00000000000FFFFF)
    65  	if zyx&0x0000000000100000 != 0 {
    66  		z = -z
    67  	}
    68  	return
    69  }
    70  
    71  // BlockIndexToIZYXString decodes a packed block index into an IZYXString.
    72  // At most, each block int32 coordinate can be 20 bits.
    73  func BlockIndexToIZYXString(zyx uint64) dvid.IZYXString {
    74  	var x, y, z int32
    75  	x = int32(zyx & 0x00000000000FFFFF)
    76  	if zyx&0x0000000000100000 != 0 {
    77  		x = -x
    78  	}
    79  	zyx >>= 21
    80  	y = int32(zyx & 0x00000000000FFFFF)
    81  	if zyx&0x0000000000100000 != 0 {
    82  		y = -y
    83  	}
    84  	zyx >>= 21
    85  	z = int32(zyx & 0x00000000000FFFFF)
    86  	if zyx&0x0000000000100000 != 0 {
    87  		z = -z
    88  	}
    89  	return dvid.ChunkPoint3d{x, y, z}.ToIZYXString()
    90  }
    91  
    92  // Equal returns true if the receiver and passed Index are equivalent.
    93  func (idx Index) Equal(idx2 Index) bool {
    94  	if idx.Label != idx2.Label {
    95  		return false
    96  	}
    97  	if idx.LastMutId != idx2.LastMutId {
    98  		return false
    99  	}
   100  	if idx.LastModTime != idx2.LastModTime {
   101  		return false
   102  	}
   103  	if idx.LastModUser != idx2.LastModUser {
   104  		return false
   105  	}
   106  	if idx.LastModApp != idx2.LastModApp {
   107  		return false
   108  	}
   109  	if len(idx.Blocks) != len(idx2.Blocks) {
   110  		return false
   111  	}
   112  	if len(idx.Blocks) > 0 {
   113  		for block, svc := range idx.Blocks {
   114  			svc2, found := idx2.Blocks[block]
   115  			if !found {
   116  				return false
   117  			}
   118  			if (svc == nil && svc2 != nil) || (svc != nil && svc2 == nil) {
   119  				return false
   120  			}
   121  			if svc != nil {
   122  				if len(svc.Counts) != len(svc2.Counts) {
   123  					return false
   124  				}
   125  				for label, count := range svc.Counts {
   126  					count2, found := svc2.Counts[label]
   127  					if !found {
   128  						return false
   129  					}
   130  					if count != count2 {
   131  						return false
   132  					}
   133  				}
   134  			}
   135  		}
   136  	}
   137  	return true
   138  }
   139  
   140  // StringDump returns a description of the data within the Index.
   141  // If showMutationInfo is true, the mutation ID and information about
   142  // modification is also printed.
   143  func (idx Index) StringDump(showMutationInfo bool) string {
   144  	s := fmt.Sprintf("\nLabel: %d\n", idx.Label)
   145  	if showMutationInfo {
   146  		s += fmt.Sprintf("Last Mutation ID: %d\n", idx.LastMutId)
   147  		s += fmt.Sprintf("Last Modification Time: %s\n", idx.LastModTime)
   148  		s += fmt.Sprintf("Last Modification User: %s\n", idx.LastModUser)
   149  		s += fmt.Sprintf("Last Modification App:  %s\n\n", idx.LastModApp)
   150  	}
   151  
   152  	s += fmt.Sprintf("Total blocks: %d\n", len(idx.Blocks))
   153  	for zyx, svc := range idx.Blocks {
   154  		izyxStr := BlockIndexToIZYXString(zyx)
   155  		s += fmt.Sprintf("Block %s:\n", izyxStr)
   156  		for sv, count := range svc.Counts {
   157  			s += fmt.Sprintf("  Supervoxel %10d: %d voxels\n", sv, count)
   158  		}
   159  		s += fmt.Sprintf("\n")
   160  	}
   161  	return s
   162  }
   163  
   164  // NumVoxels returns the number of voxels for the Index.
   165  func (idx Index) NumVoxels() uint64 {
   166  	if len(idx.Blocks) == 0 {
   167  		return 0
   168  	}
   169  	var numVoxels uint64
   170  	for _, svc := range idx.Blocks {
   171  		if svc != nil && svc.Counts != nil {
   172  			for _, sz := range svc.Counts {
   173  				numVoxels += uint64(sz)
   174  			}
   175  		}
   176  	}
   177  	return numVoxels
   178  }
   179  
   180  // SupervoxelsPresent checks whether each label from a Set are within the index.
   181  func (idx *Index) SupervoxelsPresent(supervoxels Set) (present map[uint64]bool) {
   182  	present = make(map[uint64]bool, len(supervoxels))
   183  	toCheck := make(Set, len(supervoxels))
   184  	for supervoxel := range supervoxels {
   185  		present[supervoxel] = false
   186  		toCheck[supervoxel] = struct{}{}
   187  	}
   188  	if idx == nil || len(idx.Blocks) == 0 || len(toCheck) == 0 {
   189  		return
   190  	}
   191  	for _, svc := range idx.Blocks {
   192  		if svc != nil && svc.Counts != nil {
   193  			for sv := range svc.Counts {
   194  				if _, found := toCheck[sv]; found {
   195  					present[sv] = true
   196  					delete(toCheck, sv)
   197  					if len(toCheck) == 0 {
   198  						return
   199  					}
   200  				}
   201  			}
   202  		}
   203  	}
   204  	return
   205  }
   206  
   207  // GetSupervoxels returns a set of supervoxels within the receiver Index.
   208  func (idx *Index) GetSupervoxels() Set {
   209  	if idx == nil || len(idx.Blocks) == 0 {
   210  		return Set{}
   211  	}
   212  	lbls := make(Set, 2*len(idx.Blocks)) // guess 2 supervoxel per block
   213  	for _, svc := range idx.Blocks {
   214  		if svc != nil && svc.Counts != nil {
   215  			for sv := range svc.Counts {
   216  				lbls[sv] = struct{}{}
   217  			}
   218  		}
   219  	}
   220  	return lbls
   221  }
   222  
   223  // GetBlockIndices returns the block coordinates within the Index.
   224  func (idx *Index) GetBlockIndices() dvid.IZYXSlice {
   225  	if idx == nil || len(idx.Blocks) == 0 {
   226  		return nil
   227  	}
   228  	blocks := make(dvid.IZYXSlice, len(idx.Blocks))
   229  	i := 0
   230  	for zyx := range idx.Blocks {
   231  		blocks[i] = BlockIndexToIZYXString(zyx)
   232  		i++
   233  	}
   234  	return blocks
   235  }
   236  
   237  // GetSupervoxelCount returns the # of voxels for a supervoxel in an Index.
   238  // Note that the counts are uint64 because although each block might only hold
   239  // a # of voxels < max uint32, a massive supervoxel could hold many more.
   240  func (idx *Index) GetSupervoxelCount(supervoxel uint64) (count uint64) {
   241  	if idx == nil || len(idx.Blocks) == 0 {
   242  		return
   243  	}
   244  	for _, svc := range idx.Blocks {
   245  		if svc != nil && svc.Counts != nil {
   246  			count += uint64(svc.Counts[supervoxel])
   247  		}
   248  	}
   249  	return
   250  }
   251  
   252  // GetSupervoxelCounts returns the # of voxels for each supervoxel in an Index.
   253  // Note that the counts are uint64 because although each block might only hold
   254  // a # of voxels < max uint32, a massive supervoxel could hold many more.
   255  func (idx *Index) GetSupervoxelCounts() (counts map[uint64]uint64) {
   256  	counts = make(map[uint64]uint64)
   257  	if idx == nil || len(idx.Blocks) == 0 {
   258  		return
   259  	}
   260  	for _, svc := range idx.Blocks {
   261  		if svc != nil && svc.Counts != nil {
   262  			for supervoxel, sz := range svc.Counts {
   263  				counts[supervoxel] += uint64(sz)
   264  			}
   265  		}
   266  	}
   267  	return
   268  }
   269  
   270  // LimitToSupervoxel returns a copy of the index but with only the given supervoxel
   271  func (idx *Index) LimitToSupervoxel(supervoxel uint64) (*Index, error) {
   272  	if idx == nil || len(idx.Blocks) == 0 {
   273  		return nil, nil
   274  	}
   275  	sidx := new(Index)
   276  	sidx.Label = idx.Label
   277  	sidx.LastMutId = idx.LastMutId
   278  	sidx.LastModTime = idx.LastModTime
   279  	sidx.LastModUser = idx.LastModUser
   280  	sidx.Blocks = make(map[uint64]*proto.SVCount)
   281  	for zyx, svc := range idx.Blocks {
   282  		if svc != nil && len(svc.Counts) != 0 {
   283  			count, found := svc.Counts[supervoxel]
   284  			if found {
   285  				if count == 0 {
   286  					dvid.Debugf("ignoring block %s for supervoxel %d because zero count\n", BlockIndexToIZYXString(zyx), supervoxel)
   287  					continue
   288  				}
   289  				sidx.Blocks[zyx] = &proto.SVCount{Counts: map[uint64]uint32{supervoxel: count}}
   290  			}
   291  		}
   292  	}
   293  	if len(sidx.Blocks) == 0 {
   294  		return nil, nil
   295  	}
   296  	return sidx, nil
   297  }
   298  
   299  // GetProcessedBlockIndices returns the blocks for an index, possibly bounded in and with
   300  // down-res applied by the given scale.  If supervoxel is 0, assumes that all blocks
   301  // should be returned after the other restrictions, otherwise it screens for only
   302  // blocks that contain the given supervoxel id.
   303  func (idx *Index) GetProcessedBlockIndices(scale uint8, bounds dvid.Bounds, supervoxel uint64) (dvid.IZYXSlice, error) {
   304  	if idx == nil {
   305  		return nil, nil
   306  	}
   307  
   308  	// Get all blocks in index, skipping any that are empty.
   309  	indices := make(dvid.IZYXSlice, len(idx.Blocks))
   310  	totBlocks := 0
   311  	for zyx := range idx.Blocks {
   312  		izyx := BlockIndexToIZYXString(zyx)
   313  		svc := idx.Blocks[zyx]
   314  		if svc == nil || svc.Counts == nil {
   315  			dvid.Debugf("ignoring block %s for label %d because of nil Counts\n", izyx, idx.Label)
   316  			continue
   317  		}
   318  		if supervoxel != 0 {
   319  			count, found := svc.Counts[supervoxel]
   320  			if !found || count == 0 {
   321  				continue // filter any blocks not containing given supervoxel id
   322  			}
   323  		} else {
   324  			var ok bool
   325  			for _, count := range svc.Counts {
   326  				if count > 0 {
   327  					ok = true
   328  					break
   329  				}
   330  			}
   331  			if !ok {
   332  				dvid.Debugf("ignoring block %s for label %d because all counts are zero: %v\n", izyx, idx.Label, svc.Counts)
   333  				continue
   334  			}
   335  		}
   336  		indices[totBlocks] = izyx
   337  		totBlocks++
   338  	}
   339  	if totBlocks == 0 {
   340  		return nil, nil
   341  	}
   342  	indices = indices[:totBlocks]
   343  
   344  	// Downres if requested.
   345  	if scale > 0 {
   346  		var err error
   347  		if indices, err = indices.Downres(scale); err != nil {
   348  			return nil, err
   349  		}
   350  	}
   351  
   352  	// Apply bounds if given.
   353  	if bounds.Block.IsSet() {
   354  		if scale == 0 {
   355  			sort.Sort(indices)
   356  		}
   357  		return indices.FitToBounds(bounds.Block)
   358  	}
   359  	return indices, nil
   360  }
   361  
   362  // GetSupervoxelsBlocks returns the blocks for a given list of supervoxels.
   363  func (idx *Index) GetSupervoxelsBlocks(supervoxels Set) map[dvid.IZYXString]struct{} {
   364  	if idx == nil {
   365  		return nil
   366  	}
   367  	blockMap := make(map[dvid.IZYXString]struct{})
   368  	for zyx := range idx.Blocks {
   369  		izyx := BlockIndexToIZYXString(zyx)
   370  		svc := idx.Blocks[zyx]
   371  		if svc == nil || svc.Counts == nil {
   372  			continue
   373  		}
   374  		for supervoxel, count := range svc.Counts {
   375  			if _, found := supervoxels[supervoxel]; found && count > 0 {
   376  				blockMap[izyx] = struct{}{}
   377  				break
   378  			}
   379  		}
   380  	}
   381  	return blockMap
   382  }
   383  
   384  // FitToBounds modifies the receiver to fit the given optional block bounds.
   385  func (idx *Index) FitToBounds(bounds *dvid.OptionalBounds) error {
   386  	if bounds == nil {
   387  		return nil
   388  	}
   389  	for zyx := range idx.Blocks {
   390  		x, y, z := DecodeBlockIndex(zyx)
   391  		blockPt := dvid.ChunkPoint3d{x, y, z}
   392  		if bounds.BeyondZ(blockPt) {
   393  			break
   394  		}
   395  		if bounds.Outside(blockPt) {
   396  			continue
   397  		}
   398  		delete(idx.Blocks, zyx)
   399  	}
   400  	return nil
   401  }
   402  
   403  // Add adds the given Index to the receiver.
   404  func (idx *Index) Add(idx2 *Index) error {
   405  	if idx == nil {
   406  		return fmt.Errorf("can't use Index.Add with nil receiver Index")
   407  	}
   408  	if idx2 == nil || len(idx2.Blocks) == 0 {
   409  		return nil
   410  	}
   411  	if idx.Blocks == nil {
   412  		idx.Blocks = idx2.Blocks
   413  		return nil
   414  	}
   415  	for zyx, svc2 := range idx2.Blocks {
   416  		svc, found := idx.Blocks[zyx]
   417  		if !found || svc == nil || svc.Counts == nil {
   418  			idx.Blocks[zyx] = svc2
   419  		} else {
   420  			// supervoxels cannot be in more than one set index, so if it's in idx2,
   421  			// that supervoxel can't be in idx.
   422  			for sv2, c2 := range svc2.Counts {
   423  				svc.Counts[sv2] = c2
   424  			}
   425  		}
   426  	}
   427  	return nil
   428  }
   429  
   430  // Cleave the given supervoxels from an index and returns a new index, modifying both receiver
   431  // and creating new cleaved index.
   432  func (idx *Index) Cleave(cleaveLabel uint64, toCleave []uint64) (cleavedSize, remainSize uint64, cidx *Index) {
   433  	cleaveSet := NewSet(toCleave...)
   434  	cidx = new(Index)
   435  	cidx.Label = cleaveLabel
   436  	cidx.Blocks = make(map[uint64]*proto.SVCount)
   437  
   438  	for zyx, svc := range idx.Blocks {
   439  		if svc != nil && svc.Counts != nil {
   440  			cleavedCounts := make(map[uint64]uint32)
   441  			for supervoxel, sz := range svc.Counts {
   442  				_, inCleave := cleaveSet[supervoxel]
   443  				if inCleave {
   444  					cleavedSize += uint64(sz)
   445  					cleavedCounts[supervoxel] = sz
   446  					delete(svc.Counts, supervoxel)
   447  				} else {
   448  					remainSize += uint64(sz)
   449  				}
   450  			}
   451  			if len(cleavedCounts) > 0 {
   452  				cidx.Blocks[zyx] = &proto.SVCount{Counts: cleavedCounts}
   453  			}
   454  		}
   455  	}
   456  	for zyx, svc := range idx.Blocks {
   457  		if svc == nil || len(svc.Counts) == 0 {
   458  			delete(idx.Blocks, zyx)
   459  		}
   460  	}
   461  	return
   462  }
   463  
   464  // SupervoxelChanges tabulates changes in voxels among supervoxels across blocks.
   465  type SupervoxelChanges map[uint64]map[dvid.IZYXString]int32
   466  
   467  // ModifyBlocks modifies the receiver Index to incorporate supervoxel changes among the given blocks.
   468  func (idx *Index) ModifyBlocks(label uint64, sc SupervoxelChanges) error {
   469  	if idx == nil {
   470  		return fmt.Errorf("cannot pass nil index into ModifyBlocks()")
   471  	}
   472  	if idx.Blocks == nil {
   473  		idx.Blocks = make(map[uint64]*proto.SVCount)
   474  	}
   475  	labelSupervoxels := idx.GetSupervoxels()
   476  	if len(labelSupervoxels) == 0 {
   477  		labelSupervoxels[label] = struct{}{} // A new index has at least its original label
   478  	}
   479  	for supervoxel, blockChanges := range sc {
   480  		_, inSet := labelSupervoxels[supervoxel]
   481  		if inSet {
   482  			for izyxStr, delta := range blockChanges {
   483  				zyx, err := IZYXStringToBlockIndex(izyxStr)
   484  				if err != nil {
   485  					return err
   486  				}
   487  				svc, found := idx.Blocks[zyx]
   488  				if found && svc != nil {
   489  					oldsz := svc.Counts[supervoxel]
   490  					newsz := oldsz
   491  					if delta < 0 && uint32(-delta) > oldsz {
   492  						return fmt.Errorf("bad attempt to subtract %d from %d voxels for supervoxel %d in block %s", -delta, oldsz, supervoxel, izyxStr)
   493  					}
   494  					newsz = uint32(int64(oldsz) + int64(delta))
   495  					if newsz == 0 {
   496  						delete(svc.Counts, supervoxel)
   497  					} else {
   498  						svc.Counts[supervoxel] = newsz
   499  					}
   500  				} else {
   501  					svc = new(proto.SVCount)
   502  					svc.Counts = make(map[uint64]uint32)
   503  					if delta < 0 {
   504  						return fmt.Errorf("bad attempt to subtract %d voxels from supervoxel %d in block %s when it wasn't previously in that block", -delta, supervoxel, izyxStr)
   505  					}
   506  					svc.Counts[supervoxel] = uint32(delta)
   507  					idx.Blocks[zyx] = svc
   508  				}
   509  			}
   510  		}
   511  	}
   512  	// if blocks no longer have any supervoxels, delete them.
   513  	for zyx, svc := range idx.Blocks {
   514  		if svc == nil || len(svc.Counts) == 0 {
   515  			delete(idx.Blocks, zyx)
   516  		}
   517  	}
   518  	return nil
   519  }