├── Fast stain separation and color normalization ├── BLtrans.m ├── Demo_colornorm.m ├── Demo_stainsep.m ├── Faststainsep.m ├── Main_loop_GS.m ├── SSmain_fast.m ├── Wfast.m ├── definePar.m ├── estH.m ├── get_staincolor_sparsenmf.m ├── getstainMat.m ├── globalColorNormalization.m ├── images │ ├── source.tiff │ └── target.tiff ├── my_3image_compare_tool.m ├── normalize_W.m ├── readme.txt ├── stainsep.m └── vectorise.m ├── SNMF stain separation and color normalization ├── BLtrans.m ├── Demo_colornorm.m ├── Demo_stainsep.m ├── Main_loop.m ├── SCN.m ├── definePar.m ├── estH.m ├── get_staincolor_sparsenmf.m ├── images │ ├── he.png │ ├── img.tiff │ ├── norm.png │ ├── source1.png │ ├── source1_norm.png │ ├── source2.png │ ├── source2_norm.png │ ├── target1.png │ └── target2.png ├── readme.txt ├── stainsep.m └── vectorise.m └── readme.txt /Fast stain separation and color normalization/BLtrans.m: -------------------------------------------------------------------------------- 1 | % Beer-Lamber transformation 2 | 3 | function I=BLtrans(I) 4 | 5 | I=double(reshape(I,size(I,1)*size(I,2),size(I,3))); 6 | I=log(255)-log(I+1); % V=WH, +1 is to avoid divide by zero 7 | end -------------------------------------------------------------------------------- /Fast stain separation and color normalization/Demo_colornorm.m: -------------------------------------------------------------------------------- 1 | % Demo for fast color normalization 2 | clear 3 | close all 4 | clc 5 | %% Read source and target Whole slide images (WSIs) 6 | source=imread('images\source.tiff'); 7 | target=imread('images\target.tiff'); 8 | 9 | %% Fast separation of WSI 10 | nstains=2; 11 | lambda=0.02; 12 | 13 | parpool; 14 | [Wis, His,Hivs,stainss]=Faststainsep(source,nstains,lambda); 15 | [Wit, Hit,Hivt,stainst]=Faststainsep(target,nstains,lambda); 16 | delete('gcp') 17 | %% Stain Linear Normalization 18 | Hso_Rmax = prctile(Hivs,99); % 95 precentile of values in each column 19 | Hta_Rmax = prctile(Hivt,99); 20 | normfac=(Hta_Rmax./Hso_Rmax); 21 | Hsonorm = Hivs.*repmat(normfac,size(Hivs,1),1); 22 | 23 | imgsource_norm = Wit*Hsonorm'; 24 | rows=size(source,1);cols=size(source,2); 25 | sourcenorm=uint8(255*exp(-reshape(imgsource_norm',rows,cols,3))); 26 | 27 | %% Visuals 28 | figure; 29 | subplot(131);imshow(source);xlabel('source'); 30 | subplot(132);imshow(target);xlabel('target'); 31 | subplot(133);imshow(sourcenorm);xlabel('normalized source'); 32 | -------------------------------------------------------------------------------- /Fast stain separation and color normalization/Demo_stainsep.m: -------------------------------------------------------------------------------- 1 | % Demo of Fast Sparse Stain Separation (SSS) 2 | clear 3 | close all 4 | clc 5 | 6 | %% Read input image. We have given three types of images of size 20k*20k, 6k*6k, and 3k*3k 7 | % I=imread('wsi_20000.tif'); 8 | % I=importdata('I_size-6kX6k_to test on_8gb RAM processor.mat'); % For 8 GB RAM processor 9 | % I=importdata('I_size-3kX3k_to test on_4gb RAM processor.mat'); % For 4 GB RAM processor 10 | I=imread('images\source.tiff'); % Just for test on a small image 11 | %% Parameters 12 | nstains=2; % number of stains 13 | lambda=0.1; % default value sparsity regularization parameter 14 | 15 | if min(size(I,1),size(I,2))<4000 16 | display('Slow/direct stain separation is running because image resolution is less than 4000') 17 | str='slow'; 18 | else 19 | str=input('Please specify fast or slow =','s'); 20 | end 21 | if str=='fast' 22 | % Fast tain separation (V=WH) 23 | display('Fast stain separation is running....') 24 | % parpool % Use "matlabpool" instead if older version of MATLAB 25 | tic; 26 | [Wi, Hi,Hiv,stains]=Faststainsep(I,nstains,lambda); 27 | time=toc 28 | % delete(gcp) 29 | else 30 | % Slow stain separation 31 | display('Slow/direct stain separation is running....') 32 | tic; 33 | [Wi, Hi,Hiv,stains]=stainsep(I,nstains,lambda); 34 | time=toc 35 | end 36 | 37 | % Visuals (for 2 stains) 38 | figure; 39 | subplot(131);imshow(I);xlabel('Input') 40 | subplot(132);imshow(stains{1});xlabel('stain1') 41 | subplot(133);imshow(stains{2});xlabel('stain2') 42 | 43 | 44 | -------------------------------------------------------------------------------- /Fast stain separation and color normalization/Faststainsep.m: -------------------------------------------------------------------------------- 1 | % Demo for sparse stain separation (SSS) 2 | function [Wi, Hi,Hiv,sepstains]=Faststainsep(I,nstains,lambda) 3 | 4 | % Please cite below paper if you use this code: 5 | 6 | % @inproceedings{Vahadane2015ISBI, 7 | % Author = {Abhishek Vahadane and Tingying Peng and Shadi Albarqouni and Maximilian Baust and Katja Steiger and Anna Melissa Schlitter and Amit Sethi and Irene Esposito and Nassir Navab}, 8 | % Booktitle = {IEEE International Symposium on Biomedical Imaging}, 9 | % Date-Modified = {2015-01-31 17:49:35 +0000}, 10 | % Title = {Structure-Preserved Color Normalization for Histological Images}, 11 | % Year = {2015}} 12 | 13 | % Contact: vahadane@iitg.ernet.in, abhishek.vahadane@gmail.com 14 | %% input image should be color image 15 | ndimsI = ndims(I); 16 | if ndimsI ~= 3, 17 | error('colordeconv:InputImageDimensionError', ... 18 | 'Input image I should be 3-dimensional!'); 19 | end 20 | rows=size(I,1);cols=size(I,2); 21 | 22 | %% add SPAMS library 23 | start_spams; 24 | 25 | % Define parameter for SPAMS toolbox dictionary learning 26 | param=definePar(nstains,lambda,[]); 27 | 28 | %% Beer-Lamber tranformation 29 | V=BLtrans(I); % V=WH see in paper 30 | %% Estimate stain color bases + acceleration 31 | Wi=Wfast(I,param); 32 | Hiv=((Wi'*Wi)\Wi'*V')'; % Pseudo-inverse 33 | Hiv(Hiv<0)=0; 34 | Hi=reshape(Hiv,rows,cols,param.K); 35 | %% calculate the color image for each stain 36 | sepstains = cell(param.K, 1); 37 | for i = 1 : param.K, 38 | vdAS = Hiv(:, i)*Wi(:, i)'; 39 | sepstains{i} = uint8(255*reshape(exp(-vdAS), rows, cols, 3)); 40 | end 41 | 42 | % figure; 43 | % subplot(131);imshow(I) 44 | % subplot(132);imshow(sepstains{1}) 45 | % subplot(133);imshow(sepstains{2}) 46 | end 47 | 48 | -------------------------------------------------------------------------------- /Fast stain separation and color normalization/Main_loop_GS.m: -------------------------------------------------------------------------------- 1 | % Main file to run different color normalization techniques 2 | 3 | clear 4 | clc 5 | 6 | % Parameters 7 | nstains=2; 8 | lambda=0.05; 9 | addpath(genpath('D:\Dropbox\TUM 1\Report or writing\My Papers\TMI2015\CodeRelease')) 10 | 11 | target=imread('G:\Color normalization for JPI\target\PrognosisTMABlock1_A_3_1_H&E.tif'); 12 | [Wit, Hit,Hivt,stainst]=Faststainsep(target,nstains,lambda); 13 | 14 | %% Define source and target images (Add target and source images to the folder "images") 15 | folder='G:\Color normalization for JPI\source'; 16 | list=dir([folder,'\*.tif']); 17 | writefolder='G:\Color normalization for JPI\source_norm\GridSampling_0.05'; 18 | 19 | for k=1:length(list) 20 | 21 | 22 | %% Our Method (The techniques is published in ISBI 2015 under the title "STRUCTURE-PRESERVED COLOR NORMALIZATION FOR HISTOLOGICAL IMAGES") 23 | % For queries, contact: abhishek.vahadane@gmail.com, vahadane@iitg.ernet.in 24 | % Source and target stain separation and storage of factors 25 | % tic 26 | source=imread([folder,'\',list(k).name]); 27 | [Wis, His,Hivs,stainss]=Faststainsep(source,nstains,lambda); 28 | % save('source.mat','Wis','His','Hivs') 29 | % save('target.mat','Wi','Hi','Hiv') 30 | 31 | %% Stain Linear Normalization 32 | Hso_Rmax = prctile(Hivs,99); % 95 precentile of values in each column 33 | Hta_Rmax = prctile(Hivt,99); 34 | normfac=(Hta_Rmax./Hso_Rmax); 35 | Hsonorm = Hivs.*repmat(normfac,size(Hivs,1),1); 36 | 37 | imgsource_norm = Wit*Hsonorm'; 38 | rows=size(source,1);cols=size(source,2); 39 | sourcenorm=uint8(255*exp(-reshape(imgsource_norm',rows,cols,3))); 40 | imwrite(sourcenorm,[writefolder,'\',list(k).name(1:end-4),'_norm','.tif']); 41 | end 42 | %% Other state of art methods 43 | 44 | % addpath(genpath('stain_normalization_toolbox by Khan')) 45 | 46 | % verbose = 0; % Do not display result of each method 47 | % 48 | % [reinhard] = Reinhard( source, target, verbose ); % Reinhard method 49 | % 50 | % [macenko] = Macenko(source,target, 255, 0.15, 1, verbose); % Macenko method 51 | % currentFolder = pwd; 52 | % cd('KhanApp') 53 | % Khan=khan(source,target); % Khan method 54 | % cd(currentFolder) 55 | % %% Visuals and write normalized images in the folder "images" 56 | % imwrite(our,'images\Proposed.png'); 57 | % imwrite(Khan,'images\khan.png'); 58 | % imwrite(reinhard,'images\reinhard.png'); 59 | % imwrite(macenko,'images\macenko.png'); 60 | % 61 | % % gt=imread('images\ground truth.png'); 62 | % subplot(2,4,2);imshow(source);xlabel('Source') 63 | % subplot(2,4,3);imshow(target);xlabel('Target') 64 | % % subplot(2,4,3);imshow(gt);xlabel('ground truth') 65 | % subplot(2,4,5);imshow(our);xlabel('Proposed') 66 | % subplot(2,4,6);imshow(Khan);xlabel('Khan') 67 | % subplot(2,4,7);imshow(reinhard);xlabel('Reinhard') 68 | % subplot(2,4,8);imshow(macenko);xlabel('Macenko') 69 | % -------------------------------------------------------------------------------- /Fast stain separation and color normalization/SSmain_fast.m: -------------------------------------------------------------------------------- 1 | clear 2 | clc 3 | 4 | %% Read WSI 5 | img = imread('img.tiff'); 6 | ysource=size(img,1); 7 | xsource=size(img,2); 8 | sourcechannels=size(img,3); 9 | % img=checkforNSR_2(img); % Remove white region along boundary of stained slide 10 | 11 | tic 12 | gridsize= 10*round(min(xsource,ysource)./100); % gridsize 10% of the input size 13 | threshold=0.8; % For white regions 14 | patchsize=gridsize; 15 | initBias=ceil(patchsize./2)+1; % Avoid boundary of specified size 16 | 17 | % Add path to the spams toolbox 18 | addpath(genpath('D:\Dropbox\TUM 1\Report or writing\My Papers\TMI\CodeRelease\spams-matlab')); 19 | % start_spams; 20 | % Parameter settings 21 | nstains=2; 22 | 23 | param.mode=2; % solves for =min_{D in C} (1/n) sum_{i=1}^n (1/2)||x_i-Dalpha_i||_2^2 + ... 24 | % lambda||alpha_i||_1 + lambda_2||alpha_i||_2^2 25 | param.lambda=0.01; 26 | % param.lambda2=0.1; 27 | param.posAlpha=true; % positive stains 28 | param.posD=true; % positive staining matrix 29 | param.modeD=0; % {W in Real^{m x n} s.t. for all j, ||d_j||_2^2 <= 1 } 30 | param.whiten=0; % Do not whiten the data 31 | param.K=nstains; % No. of stain = 2 32 | param.numThreads=-1; % number of threads 33 | param.iter=200; % 20-50 is OK 34 | param.verbose='false'; 35 | param.batchsize=(patchsize+1)*(patchsize+1); 36 | %% image sampling and W estimation 37 | 38 | 39 | point_y=initBias:gridsize:ysource-initBias; 40 | point_x=initBias:gridsize:xsource-initBias; 41 | samval=img(point_y,point_x,:); 42 | C=makecform('srgb2lab'); 43 | out=applycform(samval,C); 44 | luminlayer = out(:,:,1); 45 | validpoints=[(double(luminlayer)/255)Hso_Rmax)=Hso_Rmax; 43 | 44 | end 45 | 46 | -------------------------------------------------------------------------------- /Fast stain separation and color normalization/vectorise.m: -------------------------------------------------------------------------------- 1 | function [vecI]=vectorise(I) 2 | vecI=reshape(I,size(I,1)*size(I,2),size(I,3)); 3 | end -------------------------------------------------------------------------------- /SNMF stain separation and color normalization/BLtrans.m: -------------------------------------------------------------------------------- 1 | % Beer-Lamber transformation 2 | 3 | function [V, VforW]=BLtrans(I) 4 | Ivecd=double(reshape(I,size(I,1)*size(I,2),size(I,3))); 5 | V=log(255)-log(Ivecd+1); % V=WH, +1 is to avoid divide by zero 6 | 7 | % V with exclusion of white pixels 8 | C=makecform('srgb2lab'); 9 | out=applycform(I,C); 10 | luminlayer = out(:,:,1); 11 | % validpoints=[(double(luminlayer(:))/255)Hso_Rmax)=Hso_Rmax; 43 | 44 | end 45 | 46 | -------------------------------------------------------------------------------- /SNMF stain separation and color normalization/vectorise.m: -------------------------------------------------------------------------------- 1 | function [vecI]=vectorise(I) 2 | vecI=reshape(I,size(I,1)*size(I,2),size(I,3)); 3 | end -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | There are two folders, one for color normalization, and other for accelerated (fast) color normalization (for histological images). Each folder has a readme. Please download and install the SPAMS toolbox 2 | available at http://spams-devel.gforge.inria.fr/index.html. 3 | 4 | Please install the SPAMS toolbox by following below steps or documentation at above URL: 5 | 1. Download SPAMS toolbox. Go to spams-matlab folder. 6 | 2. Run start_spams. 7 | 3. Add the path of "spams-matlab" to current MATLAB session by executing following command on the MATLAB command prompt 8 | : "addpath(genpath('PathOfspams-matlab')". Note that you should give correct path of the spams-matlab folder here. 9 | 4. Now the spams-matlab is added. Please go to any other folder and use readme file to run the code. 10 | 11 | 12 | --------------------------------------------------------------------------------