Christine
Christine

Reputation: 83

Calculate 3D distance based on change in intensity

I have three sections (top, mid, bot) of grayscale images (3D). In each section, I have a point with coordinates (x,y) and intensity values [0-255]. The distance between each section is 20 pixels. I created an illustration to show how those images were generated using a microscope:

Illustration
Illustration.

Illustration (side view): red line is the object of interest. Blue stars represents the dots which are visible in top, mid, bot section. The (x,y) coordinates of these dots are known. The length of the object remains the same but it can rotate in space - 'out of focus' (illustration shows a rotating line at time point 5). At time point 1, the red line is resting (in 2D image: 2 dots with a distance equal to the length of the object).

I want to estimate the x,y,z-coordinate of the end points (represents as stars) by using the changes in intensity, the knowledge about the length of the object and the information in the sections I have. Any help would be appreciated.

Here is an example of images:

Bot section
Bot section

Mid section
Mid section

Top section
Top section

My 3D PSF data: https://drive.google.com/file/d/1qoyhWtLDD2fUy2zThYUgkYM3vMXxNh64/view?usp=sharing

Attempt so far: enter image description here

Upvotes: 0

Views: 231

Answers (1)

Patrick Happel
Patrick Happel

Reputation: 1351

I guess the correct approach would be to record three images with slightly different z-coordinates for your bot and your top frame, then do a 3D-deconvolution (using Richardson-Lucy or whatever algorithm).

However, a more simple approach would be as I have outlined in my comment. If you use the data for a publication, I strongly recommend to emphasize that this is just an estimation and to include the steps how you have done it.

I'd suggest the following procedure:

Since I do not have your PSF-data, I fake some by estimating the PSF as a 3D-Gaussiamn. Of course, this is a strong simplification, but you should be able to get the idea behind it.

First, fit a Gaussian to the PSF along z:

[xg, yg, zg] = meshgrid(-32:32, -32:32, -32:32);

rg = sqrt(xg.^2+yg.^2);

psf = exp(-(rg/8).^2) .* exp(-(zg/16).^2);


% add some noise to make it a bit more realistic

psf = psf + randn(size(psf)) * 0.05;
% view psf:

% 
subplot(1,3,1);
s = slice(xg,yg,zg, psf, 0,0,[]);
title('faked PSF');
for i=1:2
    s(i).EdgeColor = 'none';
end

% data along z through PSF's center

z = reshape(psf(33,33,:),[65,1]);
subplot(1,3,2);
plot(-32:32, z);
title('PSF along z');

% Fit the data

% Generate a function for a gaussian distibution plus some background

gauss_d = @(x0, sigma, bg, x)exp(-1*((x-x0)/(sigma)).^2)+bg;

ft = fit ((-32:32)', z, gauss_d, ...
    'Start', [0 16 0] ... % You may find proper start points by looking at your data
);

subplot(1,3,3);
plot(-32:32, z, '.');
hold on;
plot(-32:.1:32, feval(ft, -32:.1:32), 'r-'); 
title('fit to z-profile');

enter image description here

The function that relates the intensity I to the z-coordinate is

gauss_d = @(x0, sigma, bg, x)exp(-1*((x-x0)/(sigma)).^2)+bg;

You can re-arrange this formula for x. Due to the square root, there are two possibilities:


% now make a function that returns the z-coordinate from the intensity
% value:

zfromI = @(I)ft.sigma * sqrt(-1*log(I-ft.bg))+ft.x0;
zfromI2= @(I)ft.sigma * -sqrt(-1*log(I-ft.bg))+ft.x0;

Note that the PSF I have faked is normalized to have one as its maximum value. If your PSF data is not normalized, you can divide the data by its maximum.

Now, you can use zfromI or zfromI2 to get the z-coordinate for your intensity. Again, I should be normalized, that is the fraction of the intensity to the intensity of your reference spot:

zfromI(.7)

ans =

    9.5469

>> zfromI2(.7)

ans =

   -9.4644       

Note that due to the random noise I have added, your results might look slightly different.

Upvotes: 1

Related Questions