* L'algorithme wathershed à partir d'une transformé de distance.
* Une fonction permettant l'écriture du gradient d'une image logique.
\subsubsection{Granulometrie}
-L'objectif ici est de déterminé la taille moyenne des
+L'objectif ici est de déterminer le rayon moyenne des globules rouges (souvent abrégé \emph{RBC} pour \emph{red blood cell}). Pour ce faire nous allons réaliser une succession de fermetures à l'aide d'un élément structurant de forme octogonale dont le rayon va être augmenté à chaque itération sur la composante \emph{saturation} ($imgFiltered\{2\}$). Nous évitons ici un élément structurant ayant la forme d'un disque pour des raisons de performance, une fermeture avec ce dernier demandant beaucoup plus de calculs à effectuer.
+Nous partons d'un rayon initial de 1 pour arriver à un rayon maximal de $largeur(imgRGB) / 35$. À chaque itération une fermeture est effectuée suivi du calcul du volume relatif de l'image : $volume(imgClosed) \rightarrow A, 1 - A / volImg \rightarrow N$ où $volImg$ est le volume de $imgFiltered\{2\}$.
imgH = imgHSV(:, :, 1) * 255;
% We shift the hue to have the greatest value for the nuclei.
- hueShiftValue = 175;
+ hueShiftValue = 100; % 175;
imgH = uint8(mod(255 - imgH + hueShiftValue, 256));
imwrite(imgH, '../output/imgH.png')
%% 13 mai 2015
-% imagePath = '13.05.2015/1412151257-100x-Teinte30-Saturation3-0013.tif';
-imagePath = '13.05.2015/1412151257-100x-Teinte30-Saturation3-0014.tif'; % Good result.
+imagePath = '13.05.2015/1412151257-100x-Teinte30-Saturation3-0013.tif';
+% imagePath = '13.05.2015/1412151257-100x-Teinte30-Saturation3-0014.tif'; % Good result.
% imagePath = '13.05.2015/1412151257-100x-Teinte0-Saturation0-0015.tif'; % Bad result.
+% imagePath = '13.05.2015/1412151257-100x-0010.tif';
segmentationMethod = SegmentationMethod.WatershedByMorphologicalGradient;
imwrite(compositesOpenedGradientThresholdHolesFilled, '../output/red cells segmentation - composites opened gradient threshold holes filled.png')
compositesThinning = mmthin(compositesOpenedGradientThresholdHolesFilled);
+
+ imwrite(compositesThinning, '../output/red cells segmentation - composites thinning 1.png')
+
compositesThinningFlooded = mmareaclose(compositesThinning, 5 * RBCRadiusMinArea);
compositesThinningFlooded(compositesThinning) = 0;
compositesThinningFlooded = mmero(compositesThinningFlooded); % We erode by a 3x3 cross to avoid the composites to touch the singles when fusionning later.
--- /dev/null
+% Watershed from a distance transformation.
+% Inspired by: http://mmorph.com/mxmorph/html/mmdemos/mmdcells.html.
+% img: A binary image.
+function [result] = WatershedsByDistanceTransform(img)
+ if ~islogical(img)
+ ME = MException('WatershedsByDistanceTransform:invalid_input_type', 'the input type must be logical');
+ throw(ME)
+ end
+
+ % Distance transform. Higher values denote the centers of cells.
+ distances = mmdist(img, mmsebox, 'EUCLIDEAN');
+
+ % Search the regional maximums to locate the center of each cell.
+ regionalMax = mmregmax(distances);
+
+ % To merge some very near detected cells, avoid some isolated pixels.
+ dilatedRegionalMax = mmdil(regionalMax, mmsedisk(5, '2D', 'EUCLIDEAN'));
+
+ % Apply the watershed algorithme to flood each cell from they center and find their boundaries.
+ cellBoundaries = mmcwatershed(mmneg(distances), dilatedRegionalMax, mmsebox);
+
+ % Cut the cells.
+ result = mmintersec(img, mmneg(cellBoundaries));
+end
\ No newline at end of file
--- /dev/null
+% From a logical image 'img', a gradient is calculated
+% then colored with color and written in 'filename'.
+function WriteImageGradient(img, filename, color)
+ gradientImg = mmgradm(img);
+ [M, N] = size(gradientImg);
+ red = zeros(M, N, 'uint8');
+ green = zeros(M, N, 'uint8');
+ blue = zeros(M, N, 'uint8');
+ alphaChannel = zeros(M, N, 'double');
+
+ red(gradientImg) = color(1);
+ green(gradientImg) = color(2);
+ blue(gradientImg) = color(3);
+ alphaChannel(gradientImg) = 1;
+
+ rgb = cat(3, red, green, blue);
+
+ imwrite(rgb, filename, 'Alpha', alphaChannel)
+end
+