* Avancement dans le rapport.
* 'c' est renommé 'RBCRadius' pour plus de clareté.
\maketitle
+\section{Résumé}
+
+<TODO>
+
+\section{Mots-clef}
+
+<TODO>
+
\section{Introduction}
Le but de ce projet est de dénombrer de manière automatisée les globules rouges infectés par la malaria. Le nombre total de globules rouges est également recensé afin de pouvoir établir un taux de contamination. Cela est réalisé à partir d'images microscopiques fournies par Dr. Guy Prod'hom du laboratoire de parasitologie du CHUV à Lausanne.
\section{Approche générale}
-La première étape consiste à détecter les éléments marqués comprenant les parasites, les globules blanc et les plaquettes. Les parasites peuvent se trouver à l'extérieure de cellules, par exemple groupés sous la forme de schizontes.
+L'image de départ correspond à une photographie de sang contaminé agrandit 200 fois. Un colorant est utilisé afin de faire resortir les parasites avec une teinte spéciale.
+
+La première étape consiste à détecter les éléments colorés comprenant les parasites, les globules blanc et les plaquettes. Les parasites peuvent se trouver à l'extérieure de cellules, par exemple groupés sous la forme de schizontes.
La deuxième et troisième étape consiste à chercher et à extraire les globules blancs, respectivement les schizontes.
La quatrième étape va ségmenter les globules rouges.
-La cinquième étape consiste à reconstruire les globules rouges parasités à partir des parasites marqués de la première étape et la ségmentation de la quatrième étape.
+La cinquième étape consiste à reconstruire les globules rouges parasités à partir des parasites marqués de la première étape et de la ségmentation de la quatrième étape.
La sixième et dernière étape va compter le nombre de globules rouges total et de globules rouges infectés afin de calculer le rapport entre ces deux valeurs.
-
-\begin{itemize}
- \item Mettre un diagramme montrant le processus complet
-\end{itemize}
+<TODO> Mettre un diagramme montrant le processus complet
\section{Outils utilisés}
-<TODO>
-
-\begin{itemize}
- \item Description de la structuration du projet MATLAB
-\end{itemize}
-
+<TODO> Description de la structuration du projet MATLAB
\section{Détail du processus}
-Le processus est actuellement réalisé sur des images réduites de 40 \% par rapport à la taille originale afin d'augmenter la vitesse de l'ensemble du processus.
+Le processus est actuellement réalisé sur des images réduites de 40 \% à l'aide d'une intérpolation bicubique par rapport à la taille originale afin d'augmenter la vitesse de l'ensemble du processus. La taille des images traitées après réduction est de 1167 x 1556. Voir la figure \ref{fig:imgRGB}.
-TODO : faire des mesures précises sur des images plus grandes afin de voir s'il y a beaucoup d'imprécisions liées à la réduction.
+\begin{figure}[htbp]
+ \centering
+ \includegraphics[width=\linewidth]{img/imgRGB.png}
+ \caption{Image originale en entrée ($imgRGB$)}
+ \label{fig:imgRGB}
+\end{figure}
+Tout au long de cette description nous lions certain résultats d'opération à des noms de variables issue du code \emph{MATLAB} (fourni en annexe). Ceci afin de pouvoir facilement retrouver le détail de ces opérations dans le code et de facilité le suivit de l'enchaînements des opérations.
+
+<TODO> Caractériser les images en entrée + mettre une image en figure (sachant que l'ensemble du processus y est très sensible).
+<TODO> faire des mesures précises sur des images plus grandes afin de voir s'il y a beaucoup d'imprécisions liées à la réduction.
\subsection{Détection des parasites}
-Cette opération a pour but de marquer les parasites, les schizontes ainsi que les globules blancs. Nous utilisons ici les composantes "teinte" et "saturation" de l'image.
+Cette opération a pour but de marquer les éléments colorés qui correspondent aux parasites, schizontes et globules blancs. Nous utilisons ici les composantes "teinte" et "saturation" de l'image.
+
+\subsection{Filtrage préliminaire}
+
+Il est nécessaire pour la suite du traitement d'avoir les intensités les plus élevés pour les éléments coloriés pour les deux composantes teinte et valeur. Pour se faire nous allons utiliser le négatif des deux composantes. De plus la composante teinte doit être translatée de $175 / 255$ afin que les éléments coloriés soient d'intensité la plus grande. $imgRGB \rightarrow (imgH, imgS)$.
+
+Un filtre médian 5 x 5 suivi d'une fermeture par aire de 1000 sont appliqués à $imgH$ et $imgS$ afin de gommer le bruit et de rendre le fond plus homogène et plus sombre. $imgH \rightarrow imgFiltered\{1\}, imgS \rightarrow imgFiltered\{2\}$.
+
+\begin{figure}[htbp]
+ \centering
+ \includegraphics[width=\linewidth]{img/imgHFiltered.jpg}
+ \caption{Composante \emph{teinte} après filtrage ($imgFiltered\{1\}$)}
+ \label{fig:imgHFiltered}
+\end{figure}
+
+\begin{figure}[htbp]
+ \centering
+ \includegraphics[width=\linewidth]{img/imgSFiltered.jpg}
+ \caption{Composante \emph{saturation} après filtrage ($imgFiltered\{2\}$)}
+ \label{fig:imgSFiltered}
+\end{figure}
+
+
+\subsubsection{Granulometrie}
+
+L'objectif ici est de déterminé la taille moyenne des
+
+
-TODO : (à développer)
\begin{itemize}
- \item La composante teinte est inversée puis "shiftée" afin d'obtenir le fond le plus foncé possible. Les cellules sont alors plus claires et les parasites encore plus clairs.
- \item La composante saturation est inversée afin que l'intensité des parasites soit la plus élevée.
- \item Réalisation d'un filtre médian 5x5 ainsi que d'une fermeture d'aire sur les deux composantes
\item Lors de la granulométrie, afin d'être indépendant de la taille de l'image, nous définisson la valeur supérieure de recherche en fonction de la largeur de l'image. Y a-t-il un moyen d'obtenir le DPI de l'images ?
\item La taille des parasites est difficle à extraire de l'histogramme de la granulométrie, donc définissions donc celle-ci comme étant un cinquième de la taille des globules rouges.
\item les fermeturees successives utilisées lors de la granulométrie utilisé une forme octogone et non un disk afin d'augmenter la vitesse de traitement (speed-up de 3 fois environ).
\item Dénombrement des cellules saines à l'oeil : 94
\item Dénombrement des cellules infectées à l'oeil : 22
\item Taux de cellules infectées réel : 19.0~\% (22 / (94 + 22))
- \item Erreur : +0.5~\%
+ \item Erreur : +0.9~\%
\end{itemize}
-\subsubsection{\texttt{1412151257-0002}}
+\subsubsection{\texttt{1412151257-0004}}
\begin{itemize}
\item Taux de cellules infectées : 12.6~\% (15/119)
\item Temps de calcul : 106 secondes
\item Dénombrement des cellules saines à l'oeil : 104
\item Dénombrement des cellules infectées à l'oeil : 19
- \item Taux de cellules infectées réel : 15.5 \% (19 / (104 + 19))
- \item Erreur : -18.7~\%
+ \item Taux de cellules infectées réel : 15.4 \% (19 / (104 + 19))
+ \item Erreur : -18.4~\%
\end{itemize}
Cette erreur importante est liée à beaucoup de parasite manqué lors de la recherche des minimums locaux sur la composante saturation.
-\subsubsection{\texttt{1412151257-0003}}
+\subsubsection{\texttt{1412151257-0007}}
\begin{itemize}
\item Taux de cellules infectées : 23.1~\% (34/147)
\item Dénombrement des cellules saines à l'oeil : 106
\item Dénombrement des cellules infectées à l'oeil : 33
\item Taux de cellules infectées réel : 23.7~\% (33 / (106 + 33))
- \item Erreur : -2.5~\%
+ \item Erreur : -2.6~\%
\end{itemize}
\subsubsection{\texttt{1412151257-0013}}
\subsubsection{Statistiques}
\begin{itemize}
- \item Erreur moyenne : -6.1~\%
- \item Écart type sur l'erreur : 6.7~\%
- \item Taux de cellules infectées moyen détecté : 16.3~\%
- \item Écart type sur le taux de cellules infectées moyen détecté : 4.1~\%
+ \item Taux de cellules infectées moyen détecté : 16.4~\%
+ \item Écart type sur le taux de cellules infectées moyen détecté : 4.6~\%
\item Taux de cellules infectées moyen réel : 17.3~\%
- \item Écart type sur le taux de cellules infectées moyen réel : 3.7~\%
+ \item Écart type sur le taux de cellules infectées moyen réel : 4.1~\%
+ \item Erreur moyenne : -6.0~\%
+ \item Écart type sur l'erreur : 7.5~\%
\end{itemize}
\end{figure}
-\begin{figure}[htbp]
- \centering
- %\includegraphics[width=\linewidth]{img/1412151257-Gamma-1-0001-faux-positif-schizonts.png}
- \caption{Parasites au sein de globules rouges detecté à tort comme des schizonts}
- \label{fig:kjh}
-\end{figure}
-
\section{Conclusion}
% imgRGB: The image of a blood sample.
% Outputs:
% THS: Parasites of all types and WBC (mask).
-% c: Typical red cell radius [px].
-function [THS, c, nucleiRadius] = DetectionOfParasites(imgRGB)
+% RBCRadius: Typical red cell radius [px].
+function [THS, RBCRadius, nucleiRadius] = DetectionOfParasites(imgRGB)
%% Extracting of H, S and V components
imgHSV = rgb2hsv(imgRGB);
imgS = uint8(255 - 255 * imgHSV(:, :, 2));
imwrite(imgS, '../output/imgS.png')
+ % We keep the value component even if we do not use it.
imgV = uint8(255 - 255 * imgHSV(:, :, 3));
imwrite(imgV, '../output/imgV.png')
% p. 136: median filter to smooth the noise and
% area closing to enhance the bright objects and make flatter, darker and cleaner the image background.
medianFilterWindow = [5, 5];
- imgFiltered{1} = mmareaclose(medfilt2(imgH, medianFilterWindow), 200); % Hue.
- imgFiltered{2} = mmareaclose(medfilt2(imgS, medianFilterWindow), 200); % Saturation.
- imgFiltered{3} = mmareaclose(medfilt2(imgV, medianFilterWindow), 200); % Value. This component isn't used.
+ imgFiltered{1} = mmareaclose(medfilt2(imgH, medianFilterWindow), 1000); % Hue.
+ imgFiltered{2} = mmareaclose(medfilt2(imgS, medianFilterWindow), 1000); % Saturation.
+ imgFiltered{3} = mmareaclose(medfilt2(imgV, medianFilterWindow), 1000); % Value. This component isn't used.
imwrite(imgFiltered{1}, '../output/imgHFiltered.png');
imwrite(imgFiltered{2}, '../output/imgSFiltered.png');
end
% The paper chooses the biggest red cell size among the possible red cell sizes. (FIXME)
- [~, c] = max(patternSpectrum);
- nucleiRadius = c / 5; % We admit the size of a parasite is five time smaller than a red blood cell. Find a way to extract this information from the pattern spectrum histogram. (FIXME)
+ [~, RBCRadius] = max(patternSpectrum);
+ nucleiRadius = RBCRadius / 5; % We admit the size of a parasite is five time smaller than a red blood cell. Find a way to extract this information from the pattern spectrum histogram. (FIXME)
bar(patternSpectrum);
%% Regional extrema
% The size of the SE (c) must be equal to the size of red cells (see granulometry below).
- regionalExtremumSE = mmsedisk(c, '2D', 'OCTAGON');
+ regionalExtremumSE = mmsedisk(RBCRadius, '2D', 'OCTAGON');
% The functions 'mmregmax' and 'mmregmin' are very time consuming!
parfor i = 1:3
% Inputs:
% THS:
% c: (TODO: should be the average red cell size)
-function [schizontsSmoothed] = DetectionOfSchizonts(THS, c)
+function [schizontsSmoothed] = DetectionOfSchizonts(THS, RBCRadius)
schizontsConnectivityMin = 6; % Minimum cluster size when detecting schizonts.
- redCellsSE = mmsedisk(c, '2D', 'OCTAGON');
+ redCellsSE = mmsedisk(RBCRadius, '2D', 'OCTAGON');
schizonts = zeros(size(THS), 'uint8');
%% Extract all sets.
% Inputs:
-% c: The typical red cell radius [px].
-function [WBCSmoothed] = DetectionOfWhiteCells(THS, c)
+% RBCRadius: The typical red cell radius [px].
+function [WBCSmoothed] = DetectionOfWhiteCells(THS, RBCRadius)
% We use a radius near the smallest red blood cell size (80% of the radius)
- redCellsSE = mmsedisk(c * 0.5, '2D', 'OCTAGON');
+ redCellsSE = mmsedisk(RBCRadius * 0.5, '2D', 'OCTAGON');
% The white cells may not be correctly marked in the case they have a very special shape (oblong).
WBCMarker = mmero(THS, redCellsSE); % Erosion to keep only fragments of white cells.
% imageFolder = '1401063467'; % 3.
% imageFolder = '1405022890'; % 4.
% imageFolder = '1409191647'; % 9.
-imageFolder = '1412151257'; % 10. (Gamma)
+% imageFolder = '1412151257'; % 10. (Gamma)
% imageFolder = '13.05.2015';
%% Gamma
-% imageName = '1412151257-Gamma-0.8-0002.png';
-% imageName = '1412151257-Gamma-0.8-0005.png';
-% imageName = '1412151257-Gamma-0.8-0008.png';
+% imagePath = '1412151257/1412151257-Gamma-0.8-0002.png';
+% imagePath = '1412151257/1412151257-Gamma-0.8-0005.png';
+% imagePath = '1412151257/1412151257-Gamma-0.8-0008.png';
-% imageName = '1412151257-Gamma-1-0001.png';
-% imageName = '1412151257-Gamma-1-0004.png';
-imageName = '1412151257-Gamma-1-0007.png';
+% imagePath = '1412151257/1412151257-Gamma-1-0001.png';
+% imagePath = '1412151257/1412151257-Gamma-1-0004.png';
+% imagePath = '1412151257/1412151257-Gamma-1-0007.png';
-% imageName = 'Gamma-1.2-0003';
-% imageName = 'Gamma-1.2-0006';
-% imageName = 'Gamma-1.2-0009';
-
%% 13 mai 2015
-% imageName = '1412151257-100x-Teinte30-Saturation3-0013.tif';
-% imageName = '1412151257-100x-Teinte30-Saturation3-0014.tif'; % Good result.
-% imageName = '1412151257-100x-Teinte0-Saturation0-0015.tif'; % Bad 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.
segmentationMethod = SegmentationMethod.WatershedByMorphologicalGradient;
%% Main
-fprintf('Folder: %s, Image name: %s\n', imageFolder, imageName);
+fprintf('Image path: %s\n', imagePath);
scaleFactor = 0.6;
% Load the image and its ground truth.
-imgRGB = loadImg(imageFolder, imageName);
+imgRGB = loadImg(imagePath);
% Resample the image and its ground truth.
imgRGBResampled = imresize(imgRGB, scaleFactor);
imwrite(imgRGBResampled, '../output/imgRGB.png')
disp('1) Detection of parasites ...')
-[THS, c, nucleiRadius] = DetectionOfParasites(imgRGBResampled);
+[THS, RBCRadius, nucleiRadius] = DetectionOfParasites(imgRGBResampled);
disp('2) Detection of white cells ...')
-[WBC] = DetectionOfWhiteCells(THS, c);
+[WBC] = DetectionOfWhiteCells(THS, RBCRadius);
THSWithoutWBC = THS & ~WBC; % We remove the white cells from THS.
disp('3) Detection of schizonts ...')
-[schizonts] = DetectionOfSchizonts(THSWithoutWBC, c);
+[schizonts] = DetectionOfSchizonts(THSWithoutWBC, RBCRadius);
THS(schizonts) = 0; % We remove the white cells from THS.
THSWithoutWBCandSchizonts = THSWithoutWBC & ~schizonts; % We remove the shizonts from THS.
disp('4) Segmentation of red cells ...')
-[redCells] = SegmentationOfRedCells(imgRGBResampled, c, WBC, schizonts, segmentationMethod);
+[redCells] = SegmentationOfRedCells(imgRGBResampled, RBCRadius, WBC, schizonts, segmentationMethod);
disp('5) Finding infected red cells ...')
[infectedRedCells] = IdentificationOfInfectedRedCells(redCells, THSWithoutWBCandSchizonts);
-function [segmentedCells] = SegmentationOfRedCells(imgRGB, c, WBC, schizonts, segmentationMethod)
- cMin = uint32(c * 0.75); % 75%.
- cMinArea = pi * cMin ^ 2;
+function [segmentedCells] = SegmentationOfRedCells(imgRGB, RBCRadius, WBC, schizonts, segmentationMethod)
+ RBCRadiusMin = uint32(RBCRadius * 0.75); % 75%.
+ RBCRadiusMinArea = pi * RBCRadiusMin ^ 2;
gray = imgRGB(:,:,2);
gray(WBC) = 255;
gray(schizonts) = 255;
imwrite(gray, '../output/red cells segmentation - gray.png')
- grayFlat = mmareaopen(gray, 2 * cMinArea, mmsebox(1)); % The gray image is better than the green component alone.
+ grayFlat = mmareaopen(gray, 2 * RBCRadiusMinArea, mmsebox(1)); % The gray image is better than the green component alone.
imwrite(grayFlat, '../output/red cells segmentation - gray flat.png')
% Thresholding using the Otsu's method.
threshold = ~im2bw(grayFlat, graythresh(grayFlat));
% We remove all objects with a smaller area than a red blood cell.
- threshold = mmareaopen(threshold, cMinArea);
+ threshold = mmareaopen(threshold, RBCRadiusMinArea);
% We set the background to 0 by using the previous threshold.
redCellsFiltered = grayFlat;
%% Segmentation
% To smooth the borders and to remove little elements.
- opened = mmopen(redCellsFiltered, mmsedisk(cMin, '2D', 'EUCLIDEAN', 'NON-FLAT'));
+ opened = mmopen(redCellsFiltered, mmsedisk(RBCRadiusMin, '2D', 'EUCLIDEAN', 'NON-FLAT'));
imwrite(opened, '../output/red cells segmentation - opened.png')
openedThreshold = im2bw(opened, 0.02);
axisProperties = regionprops(watershedLabeled, 'MajorAxisLength', 'MinorAxisLength');
% The area opening remove the little artifacts.
- watershedSingles = mmareaopen(watershed, cMinArea / 5);
+ watershedSingles = mmareaopen(watershed, RBCRadiusMinArea / 5);
for k = 1:length(axisProperties)
% We remove each composite cell from 'watershedSingle'.
compositesOpened = grayFlat;
compositesOpened(~composites) = 0;
- compositesOpened = mmopen(compositesOpened, mmsedisk(cMin, '2D', 'EUCLIDEAN', 'FLAT'));
+ compositesOpened = mmopen(compositesOpened, mmsedisk(RBCRadiusMin, '2D', 'EUCLIDEAN', 'FLAT'));
imwrite(compositesOpened, '../output/red cells segmentation - composites opened.png')
compositesOpenedGradientThreshold = im2bw(compositesOpenedGradient, 0.00001);
imwrite(compositesOpenedGradientThreshold, '../output/red cells segmentation - composites opened gradient threshold.png')
- compositesOpenedGradientThresholdHolesFilled = ~mmareaopen(~compositesOpenedGradientThreshold, cMinArea / 2);
+ compositesOpenedGradientThresholdHolesFilled = ~mmareaopen(~compositesOpenedGradientThreshold, RBCRadiusMinArea / 2);
imwrite(compositesOpenedGradientThresholdHolesFilled, '../output/red cells segmentation - composites opened gradient threshold holes filled.png')
compositesThinning = mmthin(compositesOpenedGradientThresholdHolesFilled);
- compositesThinningFlooded = mmareaclose(compositesThinning, 5 * cMinArea);
+ 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.
imwrite(compositesThinningFlooded, '../output/red cells segmentation - composites thinning.png')
% Load the image from the given foldername and filename.
-function img = loadImg(dirname, filename)
+function img = loadImg(filepath)
imagesFolder = '../imgs_corrMK';
- filepath_img = [imagesFolder, '/', dirname, '/', filename];
- img = imread(filepath_img);
+ filepath_img = [imagesFolder, '/', filepath];
+ img = imread(filepath_img);
end