(data can be downloaded from this link.)
I am trying to segment and count nuclei in a noisy 3-D image stack and it is proving to be somewhat challenging. The strategy I could come up with requires removal of noise, generating seeds (for watershed) and employing watershed segmentation.
(*importing the desired images*)
imgseries = ImageAdjust /@
Import["C:\\Users\\Ali \Hashmi\\Desktop\\emb1_MMStack_Pos0.ome.tif"][[6 ;; -34 ;; 2]];
(* now I subtract background from each 2D slice and fill holes in image *)
img3dinit = Image3D[ Module[{img = #, background},
background = ImageTake[img, {1, 88}, {1, 204}];
FillingTransform[img - Mean[background]]
] & /@ imgseries];
(* convolving the image with a GaussianMatrix and subtracting extraneous noise *)
img3dconv = ImageConvolve[img3dinit, GaussianMatrix[{{2, 2, 2}}]]
background = ImageTake[img3dconv, All, {1, 58}, {1, 360}];
img3d = DeleteSmallComponents[(img3dconv - Mean[background])];
at this point, I have a stack that looks like the following:
(*binarizing the imaging, deleting small components and filling holes *)
img3dbin = FillingTransform[DeleteSmallComponents[MorphologicalBinarize[img3d, 0.18], 500]];
img3dbin
(* calculating distance transform *)
distance = FillingTransform@DeleteSmallComponents[ImageAdjust@DistanceTransform[
img3dbin, Padding -> 0], 500];
distance
(* determing seeds from distance transform *)
markers = MaxDetect[distance, 0.1];
markers
(* performing watershed and setting background to zero *)
matr = WatershedComponents[GradientFilter[img3d, 2], markers,Method -> "Rainfall"];
maxind = Last@*First@ComponentMeasurements[matr, "LabelCount"];
backgroundind = Keys /@ MaximalBy[ComponentMeasurements[matr, "Area"], Values, 1];
(* visualizing the segmentation *)
(seg = ArrayComponents[matr, maxind, Thread[backgroundind -> 0]]) // Colorize
below is how the segmentation looks:
having a quick look at the final segmentation I feel it can be improved. Of course I can merge smaller blobs with the nearest neighbours provided the small ones are less than a certain size. All such trivial matters can be taken care of.
However, my main concern is to generate nice seeds and get a more accurate segmentation from the watershed method starting from the noisy stack. Do you consider the use of TotalVariationFilter
/ WienerFilter
or some other form of pre-processing prior to performing DistanceTransform
for generating seeds? Furthermore, which Method
is best for WatershedComponents
function?
Any help will be much appreciated.
ImageAdjust
(as in the code) you should be able to see nuclei. $\endgroup$Import
a set of 62 images from that link into Mathematica. I can run the first several lines of code above. What I get appears to be darker but maybe it is good enough. Not sure I will make progress on the actual problem but at least I can give it a try. $\endgroup$imgseries
dropbox.com/sh/41sd3el5zkxvjxx/AAAFg0erau_ySwSr5xGKeddpa?dl=0 $\endgroup$