First part> detection of nuclei (parasite) and white blood cells.
authorGreg Burri <greg.burri@gmail.com>
Mon, 13 Apr 2015 15:08:35 +0000 (17:08 +0200)
committerGreg Burri <greg.burri@gmail.com>
Mon, 13 Apr 2015 15:08:35 +0000 (17:08 +0200)
2002-DiRuberto.pdf [new file with mode: 0644]
rapport/main.tex [new file with mode: 0644]
src/DetectionOfParasites.m [new file with mode: 0644]
src/DetectionOfSchizonts.m [new file with mode: 0644]
src/DetectionOfWhiteCells.m [new file with mode: 0644]
src/IdentificationOfInfectedRedCells.m [new file with mode: 0644]
src/ParasiteClassification.m [new file with mode: 0644]
src/SegmentationOfRedCells.m [new file with mode: 0644]
src/Tests.m [new file with mode: 0644]
src/loadImg.m
src/main.m [deleted file]

diff --git a/2002-DiRuberto.pdf b/2002-DiRuberto.pdf
new file mode 100644 (file)
index 0000000..454d160
Binary files /dev/null and b/2002-DiRuberto.pdf differ
diff --git a/rapport/main.tex b/rapport/main.tex
new file mode 100644 (file)
index 0000000..6434ec7
--- /dev/null
@@ -0,0 +1,103 @@
+\documentclass[a4paper,10pt]{article}
+
+\usepackage[francais]{babel}
+\usepackage[utf8]{inputenc}
+\usepackage[T1]{fontenc}
+\usepackage{lmodern}
+
+\usepackage{amssymb,amsmath,amsthm}
+
+\usepackage{graphicx}
+\usepackage{listings}
+\usepackage{url}
+\usepackage{upquote} 
+\usepackage{color}
+\usepackage[usenames,dvipsnames]{xcolor}
+
+\title{PA}
+\author{G.Burri}
+
+
+\begin{document}
+
+\nocite{*}
+
+%\maketitle
+
+Fichier : 1305121398-0001.png
+
+\begin{figure}[p]
+       \includegraphics[width=\linewidth]{../output/imgRGBResampled.png}
+       \caption{Image originale}
+       \label{fig:imgRGBResampled}
+\end{figure}
+
+\begin{figure}[p]
+       \includegraphics[width=\linewidth]{../output/gtResampled.png}
+       \caption{Ground truth}
+       \label{fig:gtResampled}
+\end{figure}
+
+%%%
+
+\begin{figure}[p]
+       \includegraphics[width=\linewidth]{../output/imgH.png}
+       \caption{Composante teinte (Hue)}
+       \label{fig:imgH}
+\end{figure}
+
+\begin{figure}[p]
+       \includegraphics[width=\linewidth]{../output/imgS.png}
+       \caption{Composante saturation}
+       \label{fig:imgS}
+\end{figure}
+
+%%%
+
+\begin{figure}[p]
+       \includegraphics[width=\linewidth]{../output/imgHFiltered.png}
+       \caption{Composante teinte filtrée : filtre médian 5x5 + \it{morphological area closing}}
+       \label{fig:imgHFiltered}
+\end{figure}
+
+\begin{figure}[p]
+       \includegraphics[width=\linewidth]{../output/imgSFiltered.png}
+       \caption{Composante saturation filtrée : filtre médian 5x5 + \it{morphological area closing}}
+       \label{fig:imgSFiltered}
+\end{figure}
+
+%%%
+
+\begin{figure}[p]
+       \includegraphics[width=\linewidth]{../granulometry_histogram.png}
+       \caption{Granulométrie \it{(Pattern spectrum)}}
+       \label{fig:granulometry_histogram}
+\end{figure}
+
+\begin{figure}[p]
+       \includegraphics[width=\linewidth]{../output/MH.png}
+       \caption{Marqueurs des parasites pour la composante teinte suite à l'application d'un maximum regional}
+       \label{fig:MH}
+\end{figure}
+
+\begin{figure}[p]
+       \includegraphics[width=\linewidth]{../output/MS.png}
+       \caption{Marqueurs des parasites pour la composante saturation suite à l'application d'un maximum regional}
+       \label{fig:MS}
+\end{figure}
+
+\begin{figure}[p]
+       \includegraphics[width=\linewidth]{../output/MHS.png}
+       \caption{Intersection entre MH et MS}
+       \label{fig:MHS}
+\end{figure}
+
+%%%
+
+\begin{figure}[p]
+       \includegraphics[width=\linewidth]{../output/THS.png}
+       \caption{Seuillage afin d'obtenir les parasites et globules blanc (actuellement erroné)}
+       \label{fig:THS}
+\end{figure}
+
+\end{document}
diff --git a/src/DetectionOfParasites.m b/src/DetectionOfParasites.m
new file mode 100644 (file)
index 0000000..cfe4ac2
--- /dev/null
@@ -0,0 +1,155 @@
+% Detection of parasites by means of granulometry and regional maxima.
+
+%% Parameters
+clear;
+
+imageFolder = '1305121398';
+imageNumber = '0001';
+scaleFactor = 0.6;
+
+% Load the image and its ground truth.
+[imgRGB, gt] = loadImg(imageFolder, imageNumber);
+
+
+%% Extracting of H, S and V components
+
+% Resample the image and its ground truth.
+imgRGBResampled = imresize(imgRGB, scaleFactor);
+gtResampled = imresize(gt, scaleFactor);
+
+imgHSV = rgb2hsv(imgRGBResampled);
+
+imgH = imgHSV(:, :, 1) * 255;
+% We shift the hue to have the greatest value for the nuclei.
+hueShiftValue = 195; % 100
+imgH = uint8(mod(255 - imgH + hueShiftValue, 256));
+
+imgS = uint8(imgHSV(:, :, 2) * 255);
+
+% imgV = uint8(imgHSV(:, :, 3) * 255); % The value component isn't used.
+% imgH = 255 - imgV; % We use the value component instead of the hue one (just for testing)
+
+% 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.
+imgFiltered{1} = mmareaclose(medfilt2(imgH, [5, 5]), 400); % Hue.
+imgFiltered{2} = mmareaclose(medfilt2(imgS, [5, 5]), 400); % Saturation.
+
+% Shading correction with a Top-hat transformation (p. 673).
+% imgHFiltered = mmopenth(imgHFiltered, mmsedisk(80, '2D', 'OCTAGON'));
+% imgSFiltered = mmopenth(imgSFiltered, mmsedisk(80, '2D', 'OCTAGON'));
+
+
+%% Granulometry
+% We use the saturation component to find the red cells mean size.
+
+redCellMaxSize = 42; % Radius [px].
+funVolume = @(m) sum(sum(m));
+
+volImg = funVolume(imgFiltered{2});
+
+sizeDistribution = zeros(redCellMaxSize, 1);
+parfor k = 1:redCellMaxSize 
+    SE = mmsedisk(k, '2D', 'OCTAGON');
+    imgOpened = mmopen(imgFiltered{2}, SE);
+    A = funVolume(imgOpened);
+    N = 1 - A / volImg;
+    sizeDistribution(k) = N;
+end
+
+patternSpectrum = zeros(redCellMaxSize - 1, 1);
+for k = 1:redCellMaxSize - 1
+    patternSpectrum(k) = abs(sizeDistribution(k + 1) - sizeDistribution(k));
+end
+
+% The paper choose the biggest red cell size among the possible red cell sizes. (FIXME)
+[m, c] = max(patternSpectrum);
+c = c + 3;
+nucleiRadius = 5; % 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).
+
+regionalMaxSE = mmsedisk(c, '2D', 'OCTAGON');
+
+parfor i = 1:2
+    % This operation is very time consuming!
+    M{i} = mmregmax(imgFiltered{i}, regionalMaxSE);
+end
+
+nucleiSE = mmsedisk(nucleiRadius, '2D', 'OCTAGON');
+MHS = mmdil(M{1}, nucleiSE) & mmdil(M{2}, nucleiSE);
+
+volumeMHS = funVolume(~MHS);
+muH = funVolume(uint8(~MHS) .* imgFiltered{1}) / volumeMHS;
+muS = funVolume(uint8(~MHS) .* imgFiltered{2}) / volumeMHS;
+
+TH = im2bw(imgFiltered{1}, double(muH) / 255);
+TS = im2bw(imgFiltered{2}, double(muS) / 255);
+THS = TH & TS;
+
+
+%% Output
+
+mkdir('../output') % Just in case the 'output' directory doesn't exist.
+
+imwrite(imgRGBResampled, '../output/imgRGBResampled.png')
+imwrite(gtResampled, '../output/gtResampled.png')
+
+imwrite(imgH, '../output/imgH.png')
+imwrite(imgS, '../output/imgS.png')
+
+imwrite(M{1}, '../output/MH.png')
+imwrite(imgFiltered{1}, '../output/imgHFiltered.png');
+
+imwrite(M{2}, '../output/MS.png')
+imwrite(imgFiltered{2}, '../output/imgSFiltered.png');
+
+imwrite(MHS, '../output/MHS.png')
+
+imwrite(THS, '../output/THS.png')
+
+
+%% Display
+
+figure('Position', [100 100 1600 800])
+colormap(gray);
+
+subplot(2, 4, 1);
+imagesc(imgRGBResampled);
+title(['Original: ', imageFolder, '/', imageNumber]);
+
+subplot(2, 4, 2);
+imagesc(imgFiltered{1});
+title('Hue component');
+
+subplot(2, 4, 3);
+imagesc(imgFiltered{2});
+title('Saturation component');
+
+subplot(2, 4, 4);
+imagesc(M{1});
+title('MH');
+
+subplot(2, 4, 5);
+imagesc(M{2});
+title('MS');
+
+subplot(2, 4, 6);
+imagesc(MHS);
+title('MHS');
+
+subplot(2, 4, 7);
+imagesc(THS);
+title('THS');
+
+% print("-f1"\92, "-dpng", "Toto.png")
+
+
+
+
+
+
+
diff --git a/src/DetectionOfSchizonts.m b/src/DetectionOfSchizonts.m
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/DetectionOfWhiteCells.m b/src/DetectionOfWhiteCells.m
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/IdentificationOfInfectedRedCells.m b/src/IdentificationOfInfectedRedCells.m
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/ParasiteClassification.m b/src/ParasiteClassification.m
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/SegmentationOfRedCells.m b/src/SegmentationOfRedCells.m
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/Tests.m b/src/Tests.m
new file mode 100644 (file)
index 0000000..07f4594
--- /dev/null
@@ -0,0 +1,138 @@
+% These tests are mainly from http://mmorph.com/mxmorph/html/mmdemos/mmdcells.html
+
+% Load the image and its ground truth.
+imageFolder = '1305121398';
+imageNumber = '0001';
+[img, gt] = loadImg(imageFolder, imageNumber);
+
+% Resample the image and its ground truth.
+img = imresize(img, 0.2);
+gt = imresize(gt, 0.2);
+
+% Crop the image (for testing).
+% img = img(1:300, 1:300, :);
+
+% Image properties.
+[h, w, d] = size(img); % height, width, depth
+
+%% To gray.
+img = rgb2hsv(img);
+imgGray = zeros(h, w);
+
+% hsv = rgb2hsv(rgb);
+% S = hsv (:, :, 3);
+
+for i = 1:h
+    for j = 1:w
+        h = img(i, j, 1);
+        s = img(i, j, 2);
+        v = img(i, j, 3);
+        imgGray(i, j) = h;
+%         
+%         if (h > 0.861 || h < 0.042) && s > 0.05 && v < 0.85
+%             imgGray(i, j) = 255 * v;
+%         else
+%             imgGray(i, j) = 0;
+%         end
+    end
+end
+
+
+%% Normalization. // Pas forcément utile
+minimum = min(min(imgGray));
+maximum = max(max(imgGray));
+imgGrayNorm = uint8(255 * (imgGray - minimum) / (maximum - minimum));
+
+
+%% Morphologic transformation
+
+% Top-hat transformation (p 673).
+% Try to do some shading correction // MMOPENPH
+a = imgGrayNorm - mmopen(imgGrayNorm, mmsedisk(40)); % Octagon bcp plus rapide.
+
+% Area opening to flatten the cells.
+b = mmareaopen(a, 200);
+
+% Threshold the image to segment cells. // Seuil automatique: graythresh.
+% Seuil otsu -> mieux.
+% 
+c = mmcmp(uint8(0), '<=', b, '<=', uint8(45));
+
+% Smooth the cells and remove little holes.
+d = mmopen(c, mmsedisk(2, '2D', 'OCTAGON'));
+
+% Distance of each cell pixel to its border.
+e1 = mmdist(d, mmsebox, 'EUCLIDEAN');
+e2 = mmregmax(e1); % Regional maxima,default SE is a 3x3 cross.
+e  = mmdil(e2); % Dilation by a 3x3 cross.
+
+% Watershed.
+f = mmneg(e1);
+fs = mmsurf(f);
+g = mmcwatershed(f, e, mmsebox);
+
+% Cell separation.
+h = mmintersec(c, mmneg(g));
+
+% Removing the cells touching the border and too small cells.
+i = mmopen(mmedgeoff(h), mmsedisk(3));
+
+% Create the border of each cell. 
+j = mmgradm(i);
+
+figure('Position', [100 100 1000 800])
+colormap(gray);
+
+subplot(2, 2, 1); 
+imagesc(imgGrayNorm);
+title([imageFolder, '-', imageNumber]);
+
+subplot(2, 2, 2);
+imagesc(a);
+title('a');
+
+subplot(2, 2, 3);
+imagesc(b);
+title('b');
+
+subplot(2, 2, 4);
+imagesc(c);
+title('c');
+
+figure('Position', [100 100 1000 800])
+colormap(gray);
+
+subplot(2, 2, 1);
+imagesc(d);
+title('d');
+
+subplot(2, 2, 2);
+imagesc(mmsurf(e1));
+title('Surface of e1');
+
+subplot(2, 2, 3);
+imagesc(i);
+title('i');
+
+subplot(2, 2, 4);
+mmshow(imgGrayNorm, j);
+title('Original + j');
+
+
+% figure('Position', [100 100 1000 800])
+% colormap(gray);
+% 
+% subplot(2, 2, 1);
+% imagesc(f);
+% title('f');
+% 
+% subplot(2, 2, 2);
+% imagesc(fs);
+% title('fs');
+
+% image(imfuse(img, gt, 'blend'));
+% colormap('HSV')
+% image(gt);
+% colormap([0 0 0; 1 1 1]);
+
+% disp('Some tests ...');
index 5397aca..1db3a64 100644 (file)
@@ -5,6 +5,6 @@ function [img, gt] = loadImg(name, num)
     filename = [name, '-', num, '.png'];
     
     img = imread([imagesFolder, '/', name, '/', filename]);
-    gt = imread([groundTruthFolder, '/', name, '/', filename]) ./ 255;
+    gt = imread([groundTruthFolder, '/', name, '/', filename]);
 end
 
diff --git a/src/main.m b/src/main.m
deleted file mode 100644 (file)
index 0ba3187..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-% Load the image and its ground truth.
-imageFolder = '1305121398';
-imageNumber = '0001';
-[img, gt] = loadImg(imageFolder, imageNumber);
-
-% Resample the image and its ground truth.
-img = imresize(img, 0.2);
-gt = imresize(img, 0.2);
-
-% Crop the image (for testing).
-% img = img(1:300, 1:300, :);
-
-% Image properties.
-[h, w, d] = size(img); % height, width, depth
-
-%% To gray.
-img = rgb2hsv(img);
-imgGray = zeros(h, w);
-
-for i = 1:h
-    for j = 1:w
-        h = img(i, j, 1);
-        s = img(i, j, 2);
-        v = img(i, j, 3);
-        imgGray(i, j) = v;
-%         
-%         if (h > 0.861 || h < 0.042) && s > 0.05 && v < 0.85
-%             imgGray(i, j) = 255 * v;
-%         else
-%             imgGray(i, j) = 0;
-%         end
-    end
-end
-
-
-%% Normalization.
-minimum = min(min(imgGray));
-maximum = max(max(imgGray));
-imgGrayNorm = uint8(255 * (imgGray - minimum) / (maximum - minimum));
-
-
-%% Morphologic transformation
-
-% Top-hat transformation (p 673).
-% Try to do some shading correction
-a = imgGrayNorm - mmopen(imgGrayNorm, mmsedisk(40));
-
-% Area opening to flatten the cells.
-b = mmareaopen(a, 200);
-
-% Threshold the image to segment cells.
-c = mmcmp(uint8(0), '<=', b, '<=', uint8(45));
-
-% Smooth the cells and remove little holes.
-d = mmopen(c, mmsedisk(2, '2D', 'OCTAGON'));
-
-% Distance of each cell pixel to its border.
-e1 = mmdist(d, mmsebox, 'EUCLIDEAN');
-e2 = mmregmax(e1); % Regional maxima,default SE is a 3x3 cross.
-e  = mmdil(e2); % Dilation by a 3x3 cross.
-
-% Watershed.
-f = mmneg(e1);
-fs = mmsurf(f);
-g = mmcwatershed(f, e, mmsebox);
-
-% Cell separation.
-h = mmintersec(c, mmneg(g));
-
-% Removing the cells touching the border and too small cells.
-i = mmopen(mmedgeoff(h), mmsedisk(3));
-
-% Create the border of each cell. 
-j = mmgradm(i);
-
-figure('Position', [100 100 1000 800])
-colormap(gray);
-
-subplot(2, 2, 1); 
-imagesc(imgGrayNorm);
-title([imageFolder, '-', imageNumber]);
-
-subplot(2, 2, 2);
-imagesc(a);
-title('a');
-
-subplot(2, 2, 3);
-imagesc(b);
-title('b');
-
-subplot(2, 2, 4);
-imagesc(c);
-title('c');
-
-figure('Position', [100 100 1000 800])
-colormap(gray);
-
-subplot(2, 2, 1);
-imagesc(d);
-title('d');
-
-subplot(2, 2, 2);
-imagesc(mmsurf(e1));
-title('Surface of e1');
-
-subplot(2, 2, 3);
-imagesc(i);
-title('i');
-
-subplot(2, 2, 4);
-mmshow(imgGrayNorm, j);
-title('Original + j');
-
-
-
-% figure('Position', [100 100 1000 800])
-% colormap(gray);
-% 
-% subplot(2, 2, 1);
-% imagesc(f);
-% title('f');
-% 
-% subplot(2, 2, 2);
-% imagesc(fs);
-% title('fs');
-
-
-
-
-
-
-% image(imfuse(img, gt, 'blend'));
-% colormap('HSV')
-% image(gt);
-% colormap([0 0 0; 1 1 1]);
-
-% disp('Some tests ...');
-
-