Commit cc22d505 authored by Turnhout, M.C. van's avatar Turnhout, M.C. van
Browse files

ready for testing?

parent 1d55fd6e
function [amounts, atoRGB, imrgb] = clrdecon(dyes, imRGB)
function [amounts, P, Q, R] = clrdecon(dyes, im)
% dyes: 3by2 or 3by3 matrix with a column with RGB values for each dye
if size(dyes, 2) < 3, dyes(3, 3) = 0; end
% dye OD matrix: amount*nOD
p = log(dyes + 1); % add one to avoid taking log(0) (which would be bad)
% normalise: matrix M contains `p-hat' or `nOD'
M = p;
for r = 1:size(p, 2) % loop over rows (input colours)
M(r, :) = M(r, :)/norm(p(r, :)); % divide row by its length
end
M = M
% image OD
imOD = log(imRGB + 1);
amounts = zeros(size(im));
P = amounts; Q = P; R = P;
% dye contributions: 3 by 1 column
amounts = inv(M')*imOD'
amounts = M'\imOD'; % is faster and more accurate in Matlab
% dye OD columns: a*k
A = -log( (dyes + 1)/256 ); % add one to avoid taking log(0) (which would be bad)
if sum(dyes(:, 3)) < 1
% replace third colour by a perpendicluar one
A(:, 3) = cross(A(:, 1), A(:, 2));
end
% convert back to intensities
atoRGB = zeros(3);
for c = 1:3
% [amounts(1)*M(c, 1) amounts(3)*M(c, 3) amounts(3)*M(c, 3)]
atoRGB(c, :) = exp(amounts'.*M(c, :)) - 1; % subtract one to scale back to 0-255
% normalise: matrix K contains `k-hat'
K = A;
for c = 1:size(K, 2)
K(:, c) = K(:, c)/norm(K(:, c));
end
K = K
for r = 1:size(im, 1)
for c = 1:size(im, 2)
% pixel RGB values: 3 by 1 column
Ip = double(squeeze(im(r, c, :)));
% pixel OD
Ap = -log( (Ip + 1)/256 );
% dye contributions: 3 by 1 column
% amounts = inv(K)*Ap
ap = K\Ap; % is faster in Matlab
amounts(r, c, :) = ap;
% reconstruct pixels RGB contributions
P(r, c, :) = 256*exp(-ap(1)*K(:, 1))-1;
Q(r, c, :) = 256*exp(-ap(2)*K(:, 2))-1;
R(r, c, :) = 256*exp(-ap(3)*K(:, 3))-1;
end
end
imrgb = sum(atoRGB, 1);
end
\ No newline at end of file
......@@ -79,7 +79,7 @@ Which simply says that the total amount of light absorbed at a certain wavelengt
Equation \ref{sumdyedis} can be written in matrix form as (see equation \ref{sumdyesRGB} for an example):
\begin{align}
\mat{K} & = \begin{bmatrix} \col{\hat{k}}_1 & \col{\hat{k}}_ 2 & \dots & \col{\hat{k}}_D\end{bmatrix},\; \col{a} = \begin{bmatrix} \hat{a}_1 \\ \hat{a}_ 2\\ \vdots \\ \hat{a}_D\end{bmatrix}\\
\mat{K} & = \begin{bmatrix} \col{\hat{k}}_1 & \col{\hat{k}}_ 2 & \dots & \col{\hat{k}}_D\end{bmatrix},\; \col{a} = \begin{bmatrix} \hat{a}_1 \\ \hat{a}_ 2\\ \vdots \\ \hat{a}_D\end{bmatrix} \label{Kna}\\
\mat{K}\col{\hat{a}} & = \col{A} \label{sumdyesmat}
\end{align}
Matrix $\mat{K}$ is composed of the $D$ columns with (normalized) absorption coefficients $\col{\hat{k}}$ put together side-by-side. Since each column $\col{\hat{k}}$ contains $N$ coefficients for $N$ wavelengths, the size of $\mat{K}$ is $N\times D$. The column $\hat{a}$ contains the $D$ dye amounts $\hat{a}_1$ through $\hat{a}_D$, and column $\col{A}$ contains the total (summed) absorption of the $D$ dyes for each of the $N$ wavelengths.
......@@ -102,7 +102,7 @@ When we use three wavelengths and label them, say, $R$, $G$, and $B$ and (thus)
\end{equation}
and equation \ref{sumdyesinv} comes out as:
\begin{equation}
\begin{bmatrix}\hat{a}_1\\\hat{a}_2\\\hat{a}_3 \end{bmatrix} = \begin{bmatrix} \hat{k}_{R_1} & \hat{k}_{R_2} & k_{R_3} \\ \hat{k}_{G_1} & \hat{k}_{G_2} & \hat{k}_{G_3} \\ \hat{k}_{B_1} & \hat{k}_{B_2} & \hat{k}_{B_3}\end{bmatrix}^{-1}\cdot \begin{bmatrix}A_R\\A_G\\A_B \end{bmatrix}
\begin{bmatrix}\hat{a}_1\\\hat{a}_2\\\hat{a}_3 \end{bmatrix} = \begin{bmatrix} \hat{k}_{R_1} & \hat{k}_{R_2} & k_{R_3} \\ \hat{k}_{G_1} & \hat{k}_{G_2} & \hat{k}_{G_3} \\ \hat{k}_{B_1} & \hat{k}_{B_2} & \hat{k}_{B_3}\end{bmatrix}^{-1}\cdot \begin{bmatrix}A_R\\A_G\\A_B \end{bmatrix} \label{sumdyesinvRGB}
\end{equation}
So when we know matrix $\mat{K}$ (and can calculate its inverse), and know the total amount of absorption for the three wavelengths $\col{A}$, we can calculate the contributions (amounts) of the three dyes $\hat{a}$.
......@@ -148,22 +148,53 @@ Further note that this is now an \textsl{approximation} of the exact optical den
\label{Apixelcompare}}
\end{figure}
Finally note that we introduced $\col{\hat{A}}$ to distinguish this approximated absorbance from equation \ref{Apixel}. So that we will now also write
Finally note that we introduced $\col{\hat{A}}$ to distinguish this approximated absorbance from equation \ref{Apixel}. When we convert approximated absorbances back to (estimated) pixel intensities, we can undo the effect of adding 1 for the log:
\begin{equation}
\hat{\col{I}}_p = I_\mathrm{max} \hat{\col{T}} = I_\mathrm{max} \mathrm{e}^{-\col{\hat{A}}} \label{Ipixela}
\hat{\col{I}}_p = I_\mathrm{max} \mathrm{e}^{-\col{A}} =\left(I_\mathrm{max} + 1\right) \mathrm{e}^{-\col{\hat{A}}} - 1 \label{Ipixela}
\end{equation}
for pixel values and transmission values that are calculated from the approximated absorbance $\col{\hat{A}}$. Since $\col{\hat{A}}$ is an underestimation of $\col{A}$ (figure \ref{Apixela}), $\hat{\col{T}}$ is an overestimation of $\col{T}$ in the conversion $\col{T} \rightarrow \hat{\col{A}} \rightarrow \hat{\col{T}}$ ($\text{RGB} \rightarrow \text{absorbance} \rightarrow \text{RGB}$). The conversion $\col{T} \rightarrow \col{A} \rightarrow\col{T}$ is reversible and exact (figure \ref{notlogzeroT}).
\begin{figure}[h]
\tiny
\subfloat[\label{notlogzeroT}]{%
\def\svgwidth{0.47\linewidth}\includesvg{../pics/notlogzeroT}}\hfill
\subfloat[\label{notlogzerodT}]{%
\def\svgwidth{0.47\linewidth}\includesvg{../pics/notlogzerodT}}\\
\caption{Comparison of the transmission (pixel intensities) calculated with the exact and approximated absorbance. With \textbf{(a)} transmission with exact absorbance (equation \ref{Ipixel}, solid blue) and transmission with the approximated absorbance (equation \ref{Ipixela}, dashed red) as a function of pixel value $I_p$ for an 8-bits image ($I_\mathrm{max} = 255$); and \textbf{(b)} the relative error as a function of pixel value $I_p$ for 8-bits (blue), 12-bits ($I_\mathrm{max} = 4095$, red) and 16-bits images ($I_\mathrm{max} = 65\,535$, yellow). \label{Ipixelcompare}}
\end{figure}
The 100\,\% error in figure \ref{notlogzerodT} may look worse than it is: it means that the original pixel value of 1 has become 2, and the error of about 10\,\% for a pixel value of 10 means that the converted pixel value is about 11. The dynamic range of the camera does affect this error, but not to any appreciable amount.
\section{And the number of the counting shall be three}
\subsection{Getting $\hat{k}$ from measurement}
You cannot just derive the (normalized) absorption vector $\hat{k}$ for your dye(s) in RGB from first principles. You may be able to find values on the internet \cite{Landini2020} or presets in the ImageJ plugin \cite{Landini2004}, but these values also once had to be derived from `raw' RGB values.\\
\noindent You first need to record the RGB values in an image with `pure dye'. This can be a specifically prepared sample or a region in your image where you are yo that you are only looking at that single dye \cite{Landini2004,Landini2020}. From this column with RGB values of the dye, you can calculate the dyes (approximated) absorbance column:
\begin{equation}
\col{\hat{A}}_d = -\ln \left(\frac{\col{I}_d + 1}{I_\mathrm{max}+1} \right) \label{Apixeld}
\end{equation}
The values in this column are the product of the amount of dye (a single number) and the (normalised) absorbance of the dye: $\hat{a}\hat{k}$. And therefore:
\begin{align}
l_d & = \sqrt{\hat{A}_R^2 + \hat{A}_G^2 + \hat{A}_B^2}\\
\col{\hat{k}}_d & = \frac{\col{\hat{A}}_d}{l_d} \label{kpixeld}
\end{align}
That is: the normalized column $\col{\hat{k}}$ equals the normalized column $\col{\hat{A}}$.
\subsection{Dealing with (only) two dyes}
Three shall be the number thou shalt count, and the number of the counting shall be three.
\ No newline at end of file
If you want to deconvolve in three `colours', you will have to use three dyes. So when you only have two dyes in your images, you will have to `come up' with a third one, just to fill $\mat{K}$ for the deconvolution.
For the analysis, it is best when this invented third colour is `perpendicular' to the other two colours. To find a`perpendicular' colour, you can use the cross product:
\begin{equation}
\col{k}_3 = \col{\hat{k}}_1 \times \col{\hat{k}}_2 = \begin{bmatrix} k_{G_1}k_{B_2} - k_{B_1}k_{G_2}\\ % Kb*kg - Kg*kb
k_{B_1}k_{R_2} - k_{R_1}k_{B_2} \\ % Kr*kb - Kb*kr,
k_{R_1}k_{G_2} - k_{G_1}k_{R_2} \end{bmatrix} %Kg*kr - Kr*kg
\end{equation}
Note that this column still needs to be normalized to $\col{\hat{k}}_3$.
\subsection{Summary: colour deconvolution in RGB}
So the general workflow may look like this
\begin{itemize}
\item Get the RGB values for the three dyes that you would like to have deconvolved in your image and put them in a column $\col{I}_d$ for each dye.
\item Calculate the (approximated) optical density columns $\col{\hat{A}}_d$ of the three dyes from $I_d$ (equation \ref{Apixeld}).
\item Normalise the $\col{\hat{A}}_d$ columns to find the columns with coefficients $\hat{k}_d$ for each dye (equation \ref{kpixeld}).
\item Collect the three $\hat{k}_d$ columns in a matrix $\mat{K}$ (equations \ref{Kna}, \ref{sumdyesRGB}) and calculate its inverse $\mat{K}^{-1}$.
\item Then for each pixel in the image
\begin{itemize}
\item Get the RGB values for the pixel and put them in a (temporary) column $\col{I}_p$.
\item Calculate the (approximated) optical density column $\col{\hat{A}}_p$ of the pixel (equation \ref{Apixela}).
\item Multiply $\mat{K}^{-1}$ with $\col{\hat{A}}_p$ to find the column with dye contributions $\hat{a}$ for this pixel (equations \ref{sumdyesinv}, \ref{sumdyesinvRGB}).
\item For image reconstruction: calculate the approximated column with pixel RGB values $\hat{I}_p$ with $\hat{a}_p$ (equation \ref{Ipixela}).
\end{itemize}
\end{itemize}
......@@ -13,7 +13,7 @@ h = legend('$\col{A} = -\ln(I_p/255)$', '$\col{\hat{A}} = -\ln( (I_p+1)/256)$');
set(h, 'box', 'off')
figure('defaultlinelinewidth', 2)
loglog(Ip, 255*exp(-A(1, :)), Ip, 255*exp(-A(2, :)), '--')
loglog(Ip, 255*exp(-A(1, :)), Ip, 256*exp(-A(2, :))-1, '--')
ylim([1 1000])
xlabel('pixel intensity\,[-]')
ylabel('transmission\,[-]')
......@@ -35,7 +35,7 @@ for d = 1:numel(DR)
IP(d, 1:numel(ip)) = ip;
dA(d, 1:numel(ip)) = A(2, :)./A(1, :);
dT(d, 1:numel(ip)) = exp(-A(2, :))./exp(-A(1, :));
dT(d, 1:numel(ip)) = ((2^n)*exp(-A(2, :))-1)./((2^n-1)*exp(-A(1, :)));
end
figure('defaultlinelinewidth', 2)
......
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="1330"
height="665" viewBox="0 0 266 133" stroke-width="10">
<path d="m0,0h266v133H0"/>
<path stroke="#962192" d="m1,6h264"/>
<path stroke="#5228cc" d="m1,17h264"/>
<path stroke="#0433ff" d="m1,28h264"/>
<path stroke="#009292" d="m1,39h264"/>
<path stroke="#00f900" d="m1,50h264"/>
<path stroke="#cafa00" d="m1,61h264"/>
<path stroke="#fffb00" d="m1,72h264"/>
<path stroke="#ffc700" d="m1,83h264"/>
<path stroke="#ff9300" d="m1,94h264"/>
<path stroke="#ff5000" d="m1,105h264"/>
<path stroke="#ff2600" d="m1,116h264"/>
<path stroke="#d82253" d="m1,127h264"/>
</svg>
\ No newline at end of file
%% Creator: Inkscape inkscape 0.92.5, www.inkscape.org
%% PDF/EPS/PS + LaTeX output extension by Johan Engelen, 2010
%% Accompanies image file 'notlogzeroT.pdf' (pdf, eps, ps)
%%
%% To include the image in your LaTeX document, write
%% \input{<filename>.pdf_tex}
%% instead of
%% \includegraphics{<filename>.pdf}
%% To scale the image, write
%% \def\svgwidth{<desired width>}
%% \input{<filename>.pdf_tex}
%% instead of
%% \includegraphics[width=<desired width>]{<filename>.pdf}
%%
%% Images with a different path to the parent latex file can
%% be accessed with the `import' package (which may need to be
%% installed) using
%% \usepackage{import}
%% in the preamble, and then including the image with
%% \import{<path to file>}{<filename>.pdf_tex}
%% Alternatively, one can specify
%% \graphicspath{{<path to file>/}}
%%
%% For more information, please see info/svg-inkscape on CTAN:
%% http://tug.ctan.org/tex-archive/info/svg-inkscape
%%
\begingroup%
\makeatletter%
\providecommand\color[2][]{%
\errmessage{(Inkscape) Color is used for the text in Inkscape, but the package 'color.sty' is not loaded}%
\renewcommand\color[2][]{}%
}%
\providecommand\transparent[1]{%
\errmessage{(Inkscape) Transparency is used (non-zero) for the text in Inkscape, but the package 'transparent.sty' is not loaded}%
\renewcommand\transparent[1]{}%
}%
\providecommand\rotatebox[2]{#2}%
\newcommand*\fsize{\dimexpr\f@size pt\relax}%
\newcommand*\lineheight[1]{\fontsize{\fsize}{#1\fsize}\selectfont}%
\ifx\svgwidth\undefined%
\setlength{\unitlength}{495.98342126bp}%
\ifx\svgscale\undefined%
\relax%
\else%
\setlength{\unitlength}{\unitlength * \real{\svgscale}}%
\fi%
\else%
\setlength{\unitlength}{\svgwidth}%
\fi%
\global\let\svgwidth\undefined%
\global\let\svgscale\undefined%
\makeatother%
\begin{picture}(1,0.79287731)%
\lineheight{1}%
\setlength\tabcolsep{0pt}%
\put(0,0){\includegraphics[width=\unitlength,page=1]{notlogzeroT.pdf}}%
\put(0.05650088,0.03427534){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} $10^0$ \end{tabular}}}}%
\put(0.35651091,0.03427534){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} $10^1$ \end{tabular}}}}%
\put(0.65652094,0.03427534){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} $10^2$ \end{tabular}}}}%
\put(0.95653096,0.03427534){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} $10^3$ \end{tabular}}}}%
\put(0,0){\includegraphics[width=\unitlength,page=2]{notlogzeroT.pdf}}%
\put(0.02028125,0.06149802){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} $10^0$ \end{tabular}}}}%
\put(0.02028125,0.29811884){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} $10^1$ \end{tabular}}}}%
\put(0.02028125,0.53473965){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} $10^2$ \end{tabular}}}}%
\put(0.02028125,0.77136046){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} $10^3$ \end{tabular}}}}%
\put(0,0){\includegraphics[width=\unitlength,page=3]{notlogzeroT.pdf}}%
\put(0.44401383,0){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} pixel intensity\,[-] \end{tabular}}}}%
\put(0.02020027,0.33291905){\rotatebox{90}{\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} transmission\,[-] \end{tabular}}}}}%
\put(0,0){\includegraphics[width=\unitlength,page=4]{notlogzeroT.pdf}}%
\put(0.1492318,0.73736557){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} $\col{T}$ \end{tabular}}}}%
\put(0.1492318,0.70762647){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} $\col{\hat{T}}$ \end{tabular}}}}%
\put(0,0){\includegraphics[width=\unitlength,page=5]{notlogzeroT.pdf}}%
\end{picture}%
\endgroup%
This diff is collapsed.
%% Creator: Inkscape inkscape 0.92.5, www.inkscape.org
%% PDF/EPS/PS + LaTeX output extension by Johan Engelen, 2010
%% Accompanies image file 'notlogzerodT.pdf' (pdf, eps, ps)
%%
%% To include the image in your LaTeX document, write
%% \input{<filename>.pdf_tex}
%% instead of
%% \includegraphics{<filename>.pdf}
%% To scale the image, write
%% \def\svgwidth{<desired width>}
%% \input{<filename>.pdf_tex}
%% instead of
%% \includegraphics[width=<desired width>]{<filename>.pdf}
%%
%% Images with a different path to the parent latex file can
%% be accessed with the `import' package (which may need to be
%% installed) using
%% \usepackage{import}
%% in the preamble, and then including the image with
%% \import{<path to file>}{<filename>.pdf_tex}
%% Alternatively, one can specify
%% \graphicspath{{<path to file>/}}
%%
%% For more information, please see info/svg-inkscape on CTAN:
%% http://tug.ctan.org/tex-archive/info/svg-inkscape
%%
\begingroup%
\makeatletter%
\providecommand\color[2][]{%
\errmessage{(Inkscape) Color is used for the text in Inkscape, but the package 'color.sty' is not loaded}%
\renewcommand\color[2][]{}%
}%
\providecommand\transparent[1]{%
\errmessage{(Inkscape) Transparency is used (non-zero) for the text in Inkscape, but the package 'transparent.sty' is not loaded}%
\renewcommand\transparent[1]{}%
}%
\providecommand\rotatebox[2]{#2}%
\newcommand*\fsize{\dimexpr\f@size pt\relax}%
\newcommand*\lineheight[1]{\fontsize{\fsize}{#1\fsize}\selectfont}%
\ifx\svgwidth\undefined%
\setlength{\unitlength}{495.43440126bp}%
\ifx\svgscale\undefined%
\relax%
\else%
\setlength{\unitlength}{\unitlength * \real{\svgscale}}%
\fi%
\else%
\setlength{\unitlength}{\svgwidth}%
\fi%
\global\let\svgwidth\undefined%
\global\let\svgscale\undefined%
\makeatother%
\begin{picture}(1,0.79056278)%
\lineheight{1}%
\setlength\tabcolsep{0pt}%
\put(0,0){\includegraphics[width=\unitlength,page=1]{notlogzerodT.pdf}}%
\put(0.05545533,0.03431332){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} $10^0$ \end{tabular}}}}%
\put(0.23566083,0.03431332){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} $10^1$ \end{tabular}}}}%
\put(0.41586632,0.03431332){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} $10^2$ \end{tabular}}}}%
\put(0.59607181,0.03431332){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} $10^3$ \end{tabular}}}}%
\put(0.7762773,0.03431332){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} $10^4$ \end{tabular}}}}%
\put(0.95648279,0.03431332){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} $10^5$ \end{tabular}}}}%
\put(0,0){\includegraphics[width=\unitlength,page=2]{notlogzerodT.pdf}}%
\put(0.03939096,0.06560303){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} 1 \end{tabular}}}}%
\put(0.02122508,0.20773285){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} 1.2 \end{tabular}}}}%
\put(0.02122508,0.34986267){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} 1.4 \end{tabular}}}}%
\put(0.02122508,0.49199248){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} 1.6 \end{tabular}}}}%
\put(0.02122508,0.6341223){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} 1.8 \end{tabular}}}}%
\put(0.03939096,0.77625211){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} 2 \end{tabular}}}}%
\put(0,0){\includegraphics[width=\unitlength,page=3]{notlogzerodT.pdf}}%
\put(0.44339771,0){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} pixel intensity\,[-] \end{tabular}}}}%
\put(0.02113297,0.38505212){\rotatebox{90}{\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} $\col{\hat{T}}/ \col{T}$\,[-] \end{tabular}}}}}%
\put(0,0){\includegraphics[width=\unitlength,page=4]{notlogzerodT.pdf}}%
\put(0.88793285,0.74022999){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} 8-bits \end{tabular}}}}%
\put(0.88793285,0.71253409){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} 12-bits \end{tabular}}}}%
\put(0.88793285,0.68483819){\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l} 16-bits \end{tabular}}}}%
\put(0,0){\includegraphics[width=\unitlength,page=5]{notlogzerodT.pdf}}%
\end{picture}%
\endgroup%
This diff is collapsed.
% dye RGB matrix
dyes = [255 0 0; % RGB stain 1
0 255 0; % RGB stain 2
0 0 255]; % RGB stain 3
% dye OD matrix: amount*nOD
p = -log(dyes + 1) % add one to avoid taking log(0) (which would be bad)
% normalise: matrix M contains `p-hat'
M = p;
for r = 1:size(p, 2)
M(r, :) = M(r, :)/norm(p(r, :));
end
M = M
% image RGB values: 3 by 1 column
imRGB = [200; 100; 0];
% imRGB = [75 0 130]';
% dye OD column: a*k
A = -log( (dyes + 1)/256 ) % add one to avoid taking log(0) (which would be bad)
% image OD
imOD = -log(imRGB + 1)
% dye contributions: 3 by 1 column
% amounts = inv(M)*imOD
amounts = M\imOD % is faster in Matlab
if sum(dyes(3, :)) < 1
% replace third colour by a perpendicluar one
A(3, :) = cross(A(1, :), A(2, :))
end
% convert back to intensities
atoR = exp(-amounts'.*M(1, :)) - 1;
atoG = exp(-amounts'.*M(2, :)) - 1;
atoB = exp(-amounts'.*M(3, :)) - 1;
% normalise: matrix K contains `k-hat'
K = A;
for r = 1:size(K, 1)
K(r, :) = K(r, :)/norm(A(r, :));
end
K = K
imrgb = [atoR(1) atoG(2) atoB(3)]
% pixel RGB values: 3 by 1 column
Ip = [200; 100; 0]
atoRGB = zeros(3);
for c = 1:3
atoRGB(c, :) = exp(-amounts'.*M(c, :)) - 1;
end
imrgb = sum(atoRGB, 1)
% pixel OD
Ap = -log( (Ip + 1)/256 )
% dye contributions: 3 by 1 column
% amounts = inv(K)*Ap
ap = K\Ap % is faster in Matlab
a = [.65 .7 .29; .07 .99 .11; .27 .57 .78];
norm(a(1, :))
inv(a)
% reconstruct pixels RGB value
Ir = 256*exp(-Ap)-1
clear all; close all;
dyes = [75 0 130; % `indigo'
255 255 0; % yellow
0 140 20]; % no idea...
dyes = [255 255 0; % yellow
0 255 0]'; % green
im = imread('pics/Flag_of_Jamaica.png');
dyes = eye(3)
imRGB = [0 14 2];
%
% dyes = 255*eye(3);
% im = imread('pics/1330px_Rainbow_flag_12_colours_black_bordered.png');
[amounts, P, Q, R] = clrdecon(dyes, im);
[amounts, atoRGB, imrgb] = clrdecon(dyes, imRGB)
\ No newline at end of file
figure
imshow(im)
figure
imshow(P)
figure
imshow(Q)
figure
imshow(R)
for d = 1:3
figure
imagesc(amounts(:, :, d))
colormap(gray)
colorbar
end
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment