From: Greg Burri Date: Mon, 13 Apr 2015 15:08:35 +0000 (+0200) Subject: First part> detection of nuclei (parasite) and white blood cells. X-Git-Url: https://git.euphorik.ch/?a=commitdiff_plain;h=b350b71e6eac42ecc6d78f4d2233204b26d1ed4d;p=malaria.git First part> detection of nuclei (parasite) and white blood cells. --- diff --git a/2002-DiRuberto.pdf b/2002-DiRuberto.pdf new file mode 100644 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 index 0000000..6434ec7 --- /dev/null +++ b/rapport/main.tex @@ -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 index 0000000..cfe4ac2 --- /dev/null +++ b/src/DetectionOfParasites.m @@ -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"’, "-dpng", "Toto.png") + + + + + + + diff --git a/src/DetectionOfSchizonts.m b/src/DetectionOfSchizonts.m new file mode 100644 index 0000000..e69de29 diff --git a/src/DetectionOfWhiteCells.m b/src/DetectionOfWhiteCells.m new file mode 100644 index 0000000..e69de29 diff --git a/src/IdentificationOfInfectedRedCells.m b/src/IdentificationOfInfectedRedCells.m new file mode 100644 index 0000000..e69de29 diff --git a/src/ParasiteClassification.m b/src/ParasiteClassification.m new file mode 100644 index 0000000..e69de29 diff --git a/src/SegmentationOfRedCells.m b/src/SegmentationOfRedCells.m new file mode 100644 index 0000000..e69de29 diff --git a/src/Tests.m b/src/Tests.m new file mode 100644 index 0000000..07f4594 --- /dev/null +++ b/src/Tests.m @@ -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 ...'); diff --git a/src/loadImg.m b/src/loadImg.m index 5397aca..1db3a64 100644 --- a/src/loadImg.m +++ b/src/loadImg.m @@ -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 index 0ba3187..0000000 --- a/src/main.m +++ /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 ...'); - -