Regionprops handling of big images
9 views (last 30 days)
Show older comments
Marcio Teixeira
on 12 Oct 2023
Commented: Ashish Uthama
on 16 Oct 2023
Hello. I am processing a quite big image (120 GB) and need to find connected regions and calcularte some properties.
The "preprocessing" of the image works pretty fine. Here is the code:
bim = blockedImage("my_big_image.tif");
tmp = apply(bim,@(bs)processImgBlock(bs,filter_value));
And the function is like this
function bw = processImgBlock(bs,m)
bw = bs.Data == m; % masked image
bw = bwareaopen(bw,250);
bw = bwconncomp(bw);
bw = labelmatrix(bw);
end
So far so good. I get my label matrix ready to be processed. It is a 80k x 80k lines, single band image. According to documentation I will get as return a blocked image that I can retrieve using:
img = gather(tmp);
The issue is that if I run regionprops on img, Matlab does not process it due to memory. Note that I have 64GB in my computer.
So my next try that (quite obviously) failed was:
my_props = apply(tmp,@(bs)get_stats(bs,land_code));
% % % getstats is like follows
function s = get_stats(bs,land_code)
s = regionprops('table',bs.Data,'Area','Perimeter','Eccentricity','Orientation','Centroid');
end
because the function should return a blocked image and not a table.
Here comes the question(s):
- Is there any function that works similarly to apply that can perform the regionprops operations?
- If not, any suggestion on how to handle it? Splitting image in small parts would be the obvious choice but it could split a connected region in 2 or more subimages and I'd like to avoid it (if possible).
Thank you in advance and please reach me if you need more information or if you find my explanation unclear.
0 Comments
Accepted Answer
Walter Roberson
on 12 Oct 2023
Splitting image in small parts would be the obvious choice but it could split a connected region in 2 or more subimages
Any method that involves splitting the image into sub-images and processing the sub-images, runs the risk that you might miss connectivity that extends over sub-image boundaries.
blockedImage and apply and the older blockproc pass in partial images and assume the processing on the partial images can be handled independently. They do not transform the called function to be able to handle large arrays without running out of memory, and they have no idea how to synthesize the results of processing the sub-images together to form a complete result.
The sort of thing you would need would be to use regionprops with a tall array. Unfortunately, regionprops does not support tall arrays.
You are going to have to split the image up into sub-images, process that, get the results out, and then patch up the boundaries -- such as checking to see whether any connected components extend to the sub-image boundaries in adjacent sub-images, and if so then adjusting the information, such as re-labeling.
bw = bwconncomp(bw);
I am morally certain that is not going to return "correct" information when you use blocked images.
because the function should return a blocked image and not a table.
If you use the older blockproc() then it is not required that the output be the same size as the input block -- but if you use overlapping blocks, then make sure you use options to not trim the output. You have to return something numeric, but as long as you can make the output a consistent size then you could potentially pack data into a numeric array. This would not work very well for returning per-region information (unless you set a fixed maximum number to return), but it would work, for example, to return information about the largest region.
0 Comments
More Answers (3)
Image Analyst
on 12 Oct 2023
How big is your bs.data binary image? I would start by trying to delete any variables the in workspace that you don't need anymore. Use the clear function. If you still don't have enough memory, try writing out the binary image to a disk file and then, in a separate program read in the binary file and get your properties. That should work since you won't have any other large variables hanging around in memory anymore.
5 Comments
Ashish Uthama
on 16 Oct 2023
Depending on how large these regions are, downsampling might be worth trying. i.e if they occupy say ~>5-10% each of the full image, the resolution lost in area/perimeter might be small when compared to the full image. (its likely also a function of the details in the mask edges, if its mostly uniform/straight then the loss might be even less).
If you only have a few well defined regions, you could consider using blockedImage's zero-copy crop like this example shows: crop and mask geoTiff Files. Adapt the idea here like so: 1)create a low res image of the mask (retain the WorldStart/WorldEnd of the orginal!) Use regionprops on this to get bounding boxes for each object, then iterate on that to crop the finest level one by one to recompute stats on the finest level individually. This will work as long as your objects are well localized, so a crop is actually much smaller than the full image.
(For questions like these, it really helps to share sample images so some 'non standard' ideas can be formed :D)
Ashish Uthama
on 13 Oct 2023
Edited: Ashish Uthama
on 13 Oct 2023
@Marcio Teixeira - what is the maximum size of an individual 'region' that you are trying to analyze? If its small enough w.r.t to the image the approach outlined in this example: Detect Nuclei in Large Whole Slide Images Using Cellpose ought to work. It shows how to use regionprops on a blockedImage using apply.
It shows how to use blockedImage to process 100kx100k+ images while ensuring that objects on the border are correctly captured only once.
In short:
- Determine the maxium size of your individual object. This is the crucial part.
- Process large image in blocks with additional border size of max size/2 at least (use apply())
- In the processing function, reject objects whose centroids fall on the border region and only retain stats for objects whose centroids fall within the core block region
You ought to be able to modify the helpers in the linked example for your use case.
2 Comments
Ashish Uthama
on 16 Oct 2023
Glad you have something that works for you!
Point of clarification: You only need Medical if you want to use cellpose for segmentation. For just blockedImage+regionprops, you only need Image processing Toolbox. So you could just replace the cellpose call in the above example with whatever you currently use for segmentation to adapt it. Or you could just study the code and modify it for your use.
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!