I need to repeatedly increment cuboidal chunks of a 3D image. The image is large - on the order of 1G elements.
The only way I know of doing it using built-in Image functions is:
accumulator = accumulator ~ ImageAdd ~ ImagePad[ImageConstant[1,size], padding]` This of course constantly allocates the constant images and the padded outputs. Tens of thousands them, and at these sizes, it's slow.
So, instead, I can use a packed array to represent the image data, and add to that using Part and AddTo:
regions = { Splice[{1;;2, 3;;4, 5;;6}, Part], ... }; size = {1100, 1100, 1100}; accumulator = ConstantArray[0, size]; Assert[Developer`PackedArrayQ[accumulator]]; (* accumulator has a single reference here *) Map[{region} |-> accumulator[[region]] += 1, regions]; result = Image3D[accumulator, "Bit16"]; Unfortunately, the AddTo function doesn't seem to have a specialization that would not reallocate, in spite of the modified array having just one reference*. Judging by the system memory use, each AddTo clones the image, modifies it, sets accumulator to it, then deallocates accumulator.
Is there some incantation that would do it without allocating memory?
* Bonus Question: Is there any way to inspect an object refcount in Mathematica?
The exact code I'm using is in a Module, and is:
gridCuboidImageData = {gcuboids} |-> Module[{gridSize, i, gcuboid, start, size, ex, ey, ez, n = Length[gcuboids], imageData}, gridSize = Plus @@ gcuboids[[1]]; (* if compiled to C, replace with: imageData=PadLeft[{{{}}}, Reverse@gridSize] *) imageData = ConstantArray[0, Reverse@gridSize]; Assert[Developer`PackedArrayQ[imageData]]; For[i = 1, i <= n, i++, gcuboid = gcuboids[[i]]; size = gcuboid[[3]]; start = gcuboid[[1]]; start = {start[[1]], gridSize[[2]] - start[[2]] - size[[2]], gridSize[[3]] - start[[3]] - size[[3]]}; ex = start[[1]] + size[[1]]; ey = start[[2]] + size[[2]]; ez = start[[3]] + size[[3]]; imageData[[1 + start[[3]] ;; ez, 1 + start[[2]] ;; ey, 1 + start[[1]] ;; ex]] += 1; ]; imageData ];
regions? $\endgroup$Do[accumulator[[region]] + 1, {region, regions}]the same problems? $\endgroup$regionsis a list of lists ofSpan-s that get spliced into thePart[accumulator, <here>]. I haven't tried theDoform, but somehow doubt it will be different. TheMapis not really changing anything. It is theaccumulator[[a;;b, c;;d, e;;f]] += 1expression that isn't doing what I'd expect it to. $\endgroup$