|
a |
|
b/matlab/normalizeStaining.m |
|
|
1 |
function [Inorm H E] = normalizeStaining(I, Io, beta, alpha, HERef, maxCRef) |
|
|
2 |
% normalizeStaining: Normalize the staining appearance of images |
|
|
3 |
% originating from H&E stained sections. |
|
|
4 |
% |
|
|
5 |
% Example use: |
|
|
6 |
% See test.m. |
|
|
7 |
% |
|
|
8 |
% Input: |
|
|
9 |
% I - RGB input image; |
|
|
10 |
% Io - (optional) transmitted light intensity (default: 240); |
|
|
11 |
% beta - (optional) OD threshold for transparent pixels (default: 0.15); |
|
|
12 |
% alpha - (optional) tolerance for the pseudo-min and pseudo-max (default: 1); |
|
|
13 |
% HERef - (optional) reference H&E OD matrix (default value is defined); |
|
|
14 |
% maxCRef - (optional) reference maximum stain concentrations for H&E (default value is defined); |
|
|
15 |
% |
|
|
16 |
% Output: |
|
|
17 |
% Inorm - normalized image; |
|
|
18 |
% H - (optional) hematoxylin image; |
|
|
19 |
% E - (optional)eosin image; |
|
|
20 |
% |
|
|
21 |
% References: |
|
|
22 |
% A method for normalizing histology slides for quantitative analysis. M. |
|
|
23 |
% Macenko et al., ISBI 2009 |
|
|
24 |
% |
|
|
25 |
% Efficient nucleus detector in histopathology images. J.P. Vink et al., J |
|
|
26 |
% Microscopy, 2013 |
|
|
27 |
% |
|
|
28 |
% Copyright (c) 2013, Mitko Veta |
|
|
29 |
% Image Sciences Institute |
|
|
30 |
% University Medical Center |
|
|
31 |
% Utrecht, The Netherlands |
|
|
32 |
% |
|
|
33 |
% See the license.txt file for copying permission. |
|
|
34 |
% |
|
|
35 |
|
|
|
36 |
% transmitted light intensity |
|
|
37 |
if ~exist('Io', 'var') || isempty(Io) |
|
|
38 |
Io = 240; |
|
|
39 |
end |
|
|
40 |
|
|
|
41 |
% OD threshold for transparent pixels |
|
|
42 |
if ~exist('beta', 'var') || isempty(beta) |
|
|
43 |
beta = 0.15; |
|
|
44 |
end |
|
|
45 |
|
|
|
46 |
% tolerance for the pseudo-min and pseudo-max |
|
|
47 |
if ~exist('alpha', 'var') || isempty(alpha) |
|
|
48 |
alpha = 1; |
|
|
49 |
end |
|
|
50 |
|
|
|
51 |
% reference H&E OD matrix |
|
|
52 |
if ~exist('HERef', 'var') || isempty(HERef) |
|
|
53 |
HERef = [ |
|
|
54 |
0.5626 0.2159 |
|
|
55 |
0.7201 0.8012 |
|
|
56 |
0.4062 0.5581 |
|
|
57 |
]; |
|
|
58 |
end |
|
|
59 |
|
|
|
60 |
% reference maximum stain concentrations for H&E |
|
|
61 |
if ~exist('maxCRef)', 'var') || isempty(maxCRef) |
|
|
62 |
maxCRef = [ |
|
|
63 |
1.9705 |
|
|
64 |
1.0308 |
|
|
65 |
]; |
|
|
66 |
end |
|
|
67 |
|
|
|
68 |
h = size(I,1); |
|
|
69 |
w = size(I,2); |
|
|
70 |
|
|
|
71 |
I = double(I); |
|
|
72 |
|
|
|
73 |
I = reshape(I, [], 3); |
|
|
74 |
|
|
|
75 |
% calculate optical density |
|
|
76 |
OD = -log((I+1)/Io); |
|
|
77 |
|
|
|
78 |
% remove transparent pixels |
|
|
79 |
ODhat = OD(~any(OD < beta, 2), :); |
|
|
80 |
|
|
|
81 |
% calculate eigenvectors |
|
|
82 |
[V, ~] = eig(cov(ODhat)); |
|
|
83 |
|
|
|
84 |
% project on the plane spanned by the eigenvectors corresponding to the two |
|
|
85 |
% largest eigenvalues |
|
|
86 |
That = ODhat*V(:,2:3); |
|
|
87 |
|
|
|
88 |
% find the min and max vectors and project back to OD space |
|
|
89 |
phi = atan2(That(:,2), That(:,1)); |
|
|
90 |
|
|
|
91 |
minPhi = prctile(phi, alpha); |
|
|
92 |
maxPhi = prctile(phi, 100-alpha); |
|
|
93 |
|
|
|
94 |
vMin = V(:,2:3)*[cos(minPhi); sin(minPhi)]; |
|
|
95 |
vMax = V(:,2:3)*[cos(maxPhi); sin(maxPhi)]; |
|
|
96 |
|
|
|
97 |
% a heuristic to make the vector corresponding to hematoxylin first and the |
|
|
98 |
% one corresponding to eosin second |
|
|
99 |
if vMin(1) > vMax(1) |
|
|
100 |
HE = [vMin vMax]; |
|
|
101 |
else |
|
|
102 |
HE = [vMax vMin]; |
|
|
103 |
end |
|
|
104 |
|
|
|
105 |
% rows correspond to channels (RGB), columns to OD values |
|
|
106 |
Y = reshape(OD, [], 3)'; |
|
|
107 |
|
|
|
108 |
% determine concentrations of the individual stains |
|
|
109 |
C = HE \ Y; |
|
|
110 |
|
|
|
111 |
% normalize stain concentrations |
|
|
112 |
maxC = prctile(C, 99, 2); |
|
|
113 |
|
|
|
114 |
C = bsxfun(@rdivide, C, maxC); |
|
|
115 |
C = bsxfun(@times, C, maxCRef); |
|
|
116 |
|
|
|
117 |
% recreate the image using reference mixing matrix |
|
|
118 |
Inorm = Io*exp(-HERef * C); |
|
|
119 |
Inorm = reshape(Inorm', h, w, 3); |
|
|
120 |
Inorm = uint8(Inorm); |
|
|
121 |
|
|
|
122 |
if nargout > 1 |
|
|
123 |
H = Io*exp(-HERef(:,1) * C(1,:)); |
|
|
124 |
H = reshape(H', h, w, 3); |
|
|
125 |
H = uint8(H); |
|
|
126 |
end |
|
|
127 |
|
|
|
128 |
if nargout > 2 |
|
|
129 |
E = Io*exp(-HERef(:,2) * C(2,:)); |
|
|
130 |
E = reshape(E', h, w, 3); |
|
|
131 |
E = uint8(E); |
|
|
132 |
end |
|
|
133 |
|
|
|
134 |
end |