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