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 }