1 #.
(progn (require :asdf
)
4 (require :simplex-anneal
)
9 (:use
:cl
:vol
:raytrace
))
13 cp
/home
/martin
/0519/MedianofCelegans-10-02-09-LSM700-t58.tif ~
/tmp
/med.tif
16 for i in
*.tif
; do tifftopnm $i > `basename $i .tif`.pgm;done
20 `(simple-array fixnum
(3)))
22 (defstruct (vec-i (:type
(vector fixnum
)))
25 (declaim (ftype (function (vec-i vec-i
)
26 (values fixnum
&optional
))
29 (+ (* (vec-i-x a
) (vec-i-x b
))
30 (* (vec-i-y a
) (vec-i-y b
))
31 (* (vec-i-z a
) (vec-i-z b
))))
33 (declaim (ftype (function (vec-i vec-i
)
34 (values vec-i
&optional
))
37 (make-vec-i :x
(- (vec-i-x a
) (vec-i-x b
))
38 :y
(- (vec-i-y a
) (vec-i-y b
))
39 :z
(- (vec-i-z a
) (vec-i-z b
))))
41 (make-vec-i :x
(+ (vec-i-x a
) (vec-i-x b
))
42 :y
(+ (vec-i-y a
) (vec-i-y b
))
43 :z
(+ (vec-i-z a
) (vec-i-z b
))))
45 (declaim (ftype (function (vec-i)
46 (values double-float
&optional
))
49 (sqrt (* 1d0
(v.-i a a
))))
51 (declaim (ftype (function (string (simple-array (complex double-float
) 3)
52 &key
(:function function
))
53 (values null
&optional
))
55 (defun save-stack (fn vol
&key
(function #'realpart
))
56 (ensure-directories-exist fn
)
57 (destructuring-bind (z y x
)
58 (array-dimensions vol
)
59 (let ((b (make-array (list y x
)
60 :element-type
'(unsigned-byte 8))))
62 (do-rectangle (j i
0 y
0 x
)
64 (clamp (floor (* 255 (funcall function
(aref vol k j i
)))))))
65 (write-pgm b
(format nil
"~a/~3,'0d.pgm" fn k
)))))
68 (declaim (ftype (function (string (simple-array (unsigned-byte 8) 3))
69 (values null
&optional
))
71 (defun save-stack-ub8 (fn vol
)
72 (ensure-directories-exist fn
)
73 (destructuring-bind (z y x
)
74 (array-dimensions vol
)
75 (let ((b (make-array (list y x
)
76 :element-type
'(unsigned-byte 8))))
78 (do-rectangle (j i
0 y
0 x
)
81 (write-pgm b
(format nil
"~a/~3,'0d.pgm" fn k
)))))
85 (declaim (ftype (function (fixnum fixnum string
86 (simple-array (complex double-float
) 3))
87 (values null
&optional
))
89 (defun save-scaled-stack (h w fn vol
)
90 (destructuring-bind (z y x
)
91 (array-dimensions vol
)
92 (let* ((b (make-array (list y x
)
93 :element-type
'(unsigned-byte 8)))
94 (bb (make-array (list h w
)
95 :element-type
'(unsigned-byte 8))))
97 (do-rectangle (j i
0 y
0 x
)
99 (clamp (floor (* 255 (realpart (aref vol k j i
)))))))
100 (do-rectangle (j i
0 h
0 w
)
102 (floor (interpolate2 b
(* (/ 1d0 h
) j y
) (* (/ 1d0 w
) i x
)))))
103 (write-pgm bb
(format nil
"~a~3,'0d.pgm" fn k
)))))
106 (declaim (ftype (function ((simple-array (complex double-float
) 3)
107 (simple-array (complex double-float
) 3))
108 (values (simple-array (complex double-float
) 3) &optional
))
110 (defun .
* (vola volb
)
111 (let ((result (make-array (array-dimensions vola
)
112 :element-type
(array-element-type vola
))))
113 (destructuring-bind (z y x
)
114 (array-dimensions vola
)
115 (do-box (k j i
0 z
0 y
0 x
)
116 (setf (aref result k j i
)
118 (aref volb k j i
)))))
121 (declaim (ftype (function (double-float (simple-array (complex double-float
) 3))
122 (values (simple-array (complex double-float
) 3) &optional
))
126 (let* ((a (sb-ext:array-storage-vector vol
))
129 (setf (aref a i
) (* s
(aref a i
)))))
133 (declaim (ftype (function ((simple-array (complex double-float
) 3)
134 (simple-array (complex double-float
) 3))
135 (values (simple-array (complex double-float
) 3) &optional
))
136 convolve3-circ convolve3
))
137 (defun convolve3-circ (vola volb
)
138 (let* ((da (array-dimensions vola
))
139 (db (array-dimensions volb
))
140 (compare-ab (map 'list
#'(lambda (x y
) (eq x y
)) da db
)))
141 (when (some #'null compare-ab
)
142 (error "convolve3-circ expects both input arrays to have the same dimensions.")))
143 (ift3 (.
* (ft3 vola
) (ft3 volb
))))
145 ;; volb is the kernel
146 (defun convolve3 (vola volb
)
147 (destructuring-bind (za ya xa
)
148 (array-dimensions vola
)
149 (destructuring-bind (zb yb xb
)
150 (array-dimensions volb
)
151 (let* ((biga (make-array (list (+ za zb
)
154 :element-type
'(complex double-float
)))
155 (bigb (make-array (array-dimensions biga
)
156 :element-type
'(complex double-float
)))
163 (do-box (k j i
0 za
0 ya
0 xa
)
164 (setf (aref biga
(+ k fzb
) (+ j fyb
) (+ i fxb
))
166 (do-box (k j i
0 zb
0 yb
0 xb
)
167 (setf (aref bigb
(+ k fza
) (+ j fya
) (+ i fxa
))
169 (let* ((conv (convolve3-circ biga
(fftshift3 bigb
)))
170 (result (make-array (array-dimensions vola
)
171 :element-type
'(complex double-float
))))
172 (do-box (k j i
0 za
0 ya
0 xa
)
173 (setf (aref result k j i
)
174 (aref conv
(+ k fzb
) (+ j fyb
) (+ i fxb
))))
178 (let ((a (make-array (list 100 200 300)
179 :element-type
'(complex double-float
)))
180 (b (make-array (list 10 200 30)
181 :element-type
'(complex double-float
))))
185 (declaim (ftype (function (double-float fixnum fixnum fixnum
&key
(:scale-z double-float
))
186 (values (simple-array (complex double-float
) 3) &optional
))
188 (defun draw-sphere (radius z y x
&key
(scale-z 1d0
))
189 (let ((sphere (make-array (list z y x
)
190 :element-type
'(complex double-float
))))
191 (do-box (k j i
0 z
0 y
0 x
)
192 (let ((r (sqrt (+ (square (- i
(* .5d0 x
)))
193 (square (- j
(* .5d0 y
)))
194 (square (* scale-z
(- k
(* .5d0 z
))))))))
195 (setf (aref sphere k j i
)
201 (declaim (ftype (function ()
202 (values (simple-array vec-i
1)
203 (simple-array double-float
1)
208 ;; to find centers of cells do a convolution with a sphere
209 (defun find-centers ()
210 (let* ((stack-byte (read-stack "/home/martin/tmp/xa*.pgm"))
211 (stack (make-array (array-dimensions stack-byte
)
212 :element-type
'(complex double-float
))))
213 (destructuring-bind (z y x
)
214 (array-dimensions stack
)
218 (let ((v (+ (* .43745d0 k
)
219 (aref stack-byte k j i
))))
221 (aref stack-byte k j i
) (clamp (floor v
))
222 (aref stack k j i
) (complex v
))))))
223 #+nil
(setf *stack
* stack
)
224 ;; find centers of cells by convolving with sphere
225 (let* ((sphere (draw-sphere 11d0 z y x
:scale-z
5d0
))
226 (conv (convolve3-circ stack
(fftshift3 sphere
)))
227 (conv-byte (make-array (list y x
)
228 :element-type
'(unsigned-byte 8)))
229 (centers (make-array 0 :element-type
'vec-i
230 :initial-element
(make-vec-i)
233 (center-heights (make-array 0 :element-type
'double-float
236 (loop for k from
6 below
(- z
3) do
237 (loop for j from
1 below
(1- y
) do
238 (loop for i from
1 below
(1- x
) do
239 (let ((v (abs (aref conv k j i
))))
240 (setf (aref conv-byte j i
)
241 (if (and (< (abs (aref conv k j
(1- i
))) v
)
242 (< (abs (aref conv k j
(1+ i
))) v
)
243 (< (abs (aref conv k
(1- j
) i
)) v
)
244 (< (abs (aref conv k
(1+ j
) i
)) v
)
245 (< (abs (aref conv
(1- k
) j i
)) v
)
246 (< (abs (aref conv
(1+ k
) j i
)) v
))
249 (make-vec-i :z k
:y j
:x i
)
251 (vector-push-extend v center-heights
)
253 (clamp (floor (/ v
(* 4e2 x y z
)))))))))
254 #+nil
(write-pgm conv-byte
255 (format nil
"/home/martin/tmp/conv~3,'0d.pgm" k
)))
256 (let ((c (make-array (length centers
)
258 :initial-contents centers
))
259 (ch (make-array (length center-heights
)
260 :element-type
'double-float
261 :initial-contents center-heights
)))
262 (values c ch
(array-dimensions stack
)))))))
265 (declaim (ftype (function (fixnum)
266 (values fixnum
&optional
))
268 (defun ensure-even (x)
273 (declaim (ftype (function (double-float (simple-array vec-i
1)
274 &key
(:div-x double-float
)
275 (:div-y double-float
)
276 (:div-z double-float
))
277 (values (simple-array (complex double-float
) 3)
279 draw-scaled-spheres
))
280 ;; put points into the centers of nuclei and convolve a sphere around each
281 (defun draw-scaled-spheres (radius centers
&key
(div-x 5d0
)
284 (let* ((max-x (floor (reduce #'max
285 (map '(simple-array fixnum
1) #'vec-i-x
287 (max-y (floor (reduce #'max
288 (map '(simple-array fixnum
1) #'vec-i-y
290 (max-z (floor (reduce #'max
291 (map '(simple-array fixnum
1) #'vec-i-z
293 (cr (ceiling radius
))
294 (rh (floor radius
2))
295 (x (ensure-even (+ max-x cr
)))
296 (y (ensure-even (+ max-y cr
)))
297 (z (ensure-even (+ max-z cr
)))
299 (points (make-array dims
300 :element-type
'(complex double-float
))))
301 (loop for c across centers do
303 (- (floor (vec-i-z c
) div-z
) rh
)
304 (- (floor (vec-i-y c
) div-y
) rh
)
305 (- (floor (vec-i-x c
) div-x
) rh
))
307 (convolve3-circ points
(draw-sphere radius z y x
))))
309 (declaim (ftype (function ((simple-array (complex double-float
) 3))
310 (values (simple-array (unsigned-byte 8) 3)
313 (defun convert-vol (vol)
314 (destructuring-bind (z y x
)
315 (array-dimensions vol
)
316 (let ((result (make-array (array-dimensions vol
)
317 :element-type
'(unsigned-byte 8))))
318 (do-box (k j i
0 z
0 y
0 x
)
319 (setf (aref result k j i
)
320 (clamp (floor (* 255 (abs (aref vol k j i
)))))))
323 (declaim (ftype (function ((simple-array (complex double-float
) 2)
325 (values (simple-array (unsigned-byte 8) 2)
328 (defun convert-img (img &optional
(function #'abs
))
329 (destructuring-bind (y x
)
330 (array-dimensions img
)
331 (let ((result (make-array (array-dimensions img
)
332 :element-type
'(unsigned-byte 8))))
333 (do-rectangle (j i
0 y
0 x
)
334 (setf (aref result j i
)
335 (clamp (floor (funcall function
(aref img j i
))))))
338 (declaim (ftype (function (double-float (simple-array vec-i
1)
341 (values (simple-array (complex double-float
) 3)
344 ;; put points into the centers of nuclei and convolve a sphere around each
345 (defun draw-spheres (radius centers z y x
)
346 (let* ((dims (list z y x
))
347 (points (make-array dims
348 :element-type
'(complex double-float
)))
349 (n (length centers
)))
351 (let ((c (aref centers i
)))
357 (convolve3-circ points
(fftshift3 (draw-sphere radius z y x
)))))
363 (defparameter *merge
*
364 (let ((a (make-array (array-dimensions *stack
*)
365 :element-type
'(unsigned-byte 8))))
366 (destructuring-bind (z y x
)
367 (array-dimensions *stack
*)
368 (do-box (k j i
0 z
0 y
0 x
)
370 (clamp (if (eq 0 (aref *blobs
*
372 (* (aref *stack
* k j i
) 2)
375 (save-stack-ub "/home/martin/tmp/merge" *merge
*))
377 ;; (- z k 1) (- y j 1) (- x i 1)
381 #+nil
;; model with isotropic pixels
382 (save-stack-ub "/home/martin/tmp/iso/iso"
383 (convert-vol (draw-scaled-spheres 2d0
*centers
*)))
386 (save-stack-ub "/home/martin/tmp/blobs" *blobs
*)
389 (save-scaled-stack 100 100 "/home/martin/tmp/sca" *blobs
*)
391 #+nil
;; find maximum
392 (reduce #'max
(map 'vector
#'abs
(sb-ext:array-storage-vector
*stack
*)))
395 (destructuring-bind (z y x
)
396 (array-dimensions *stack
*)
397 (do-box (k j i
0 z
0 y
0 x
)
398 (setf (aref *stack
* k j i
)
399 (/ (aref *stack
* k j i
) 257d0
))))
402 (save-stack "/home/martin/tmp/stack" *stack
*)
405 #+nil
;; make a text image of the psf
406 (let ((numerical-aperture 1.38d0
))
407 (psf:init
:numerical-aperture numerical-aperture
)
408 (multiple-value-bind (u v
)
409 (psf:get-uv
0 1.5 3 :numerical-aperture numerical-aperture
)
412 (a (psf:integ-all nu nv
(/ u nu
) (/ v nv
)))
415 (destructuring-bind (uu vv
)
420 (format t
"~2d" (truncate (* scale
(aref a u v
)))))
427 (save-stack "/home/martin/tmp/psf"
428 (fftshift3 (ft3 (sim-psf 128 128 128 z
(* .5d0 z
))))
429 :function
#'(lambda (x) (* .01d0
(abs x
))))))
431 ;; worm stack 0.198 um in X and Y and 1 um in Z
434 (array-dimensions *blobs
*)
436 #+nil
;; write ft of object
438 (save-stack "/home/martin/tmp/kblobs" (fftshift3 (ft3 *blobs
*))
439 :function
#'(lambda (x) (* 1d-4
(abs x
)))))
441 #+nil
;; write ft of psf
443 (destructuring-bind (z y x
)
444 (array-dimensions *blobs
*)
445 (save-stack "/home/martin/tmp/otf"
446 (fftshift3 (ft3 (sim-psf z y x
447 (* .198d0 z
) (* .198d0
(ceiling (* (sqrt 2d0
) (max y x
)))))))
448 :function
#'(lambda (x) (* 1d-1
(abs x
))))))
450 (declaim (ftype (function ((simple-array (complex double-float
) (* * *)))
451 (values (simple-array (complex double-float
) (* * *))
455 (let ((out (make-array (array-dimensions in
)
456 :element-type
'(complex double-float
))))
457 (destructuring-bind (w2 w1 w0
)
458 (array-dimensions in
)
462 (let* ((kk (if (> k
(/ w2
2))
463 (+ w2
(/ w2
2) (- k
))
465 (setf (aref out k j i
)
474 (destructuring-bind (z y x
)
475 (array-dimensions *blobs
*)
476 (let ((psf (sim-psf z y x
477 (* .198d0 z
) (* .198d0
(ceiling (* (sqrt 2d0
) (max y x
)))))))
478 (save-stack "/home/martin/tmp/impsf"
479 (convolve3 *blobs
* psf
)
480 :function
#'(lambda (x) (* 1d-8
(realpart x
)))))))
483 (declaim (ftype (function ((simple-array (complex double-float
) 3)
485 (values (simple-array (complex double-float
) 2)
488 (defun cross-section-xz (a &optional
(y (floor (array-dimension a
1) 2)))
489 (destructuring-bind (z y-size x
)
491 (unless (<= 0 y
(1- y-size
))
492 (error "Y is out of bounds."))
493 (let ((b (make-array (list z x
)
494 :element-type
`(complex double-float
))))
495 (do-rectangle (j i
0 z
0 x
)
500 (declaim (ftype (function ((simple-array (complex double-float
) 2)
501 &key
(:function function
))
502 (values (simple-array (unsigned-byte 8) 2)
505 (defun normalize-img (a &key
(function #'abs
))
506 (destructuring-bind (y x
)
508 (let ((b (make-array (list y x
)
509 :element-type
'double-float
)))
510 (do-rectangle (j i
0 y
0 x
)
512 (funcall function
(aref a j i
))))
513 (let* ((b1 (sb-ext:array-storage-vector b
))
514 (ma (reduce #'max b1
))
515 (mi (reduce #'min b1
))
516 (result (make-array (list y x
)
517 :element-type
'(unsigned-byte 8)))
518 (s (/ 255d0
(- ma mi
))))
519 (do-rectangle (j i
0 y
0 x
)
520 (setf (aref result j i
)
521 (floor (* s
(- (aref b j i
) mi
)))))
524 (declaim (ftype (function ((simple-array (complex double-float
) 3)
525 &key
(:function function
))
526 (values (simple-array (unsigned-byte 8) 3)
529 (defun normalize-vol (a &key
(function #'abs
))
530 (destructuring-bind (z y x
)
532 (let ((b (make-array (list z y x
)
533 :element-type
'double-float
)))
534 (do-box (k j i
0 z
0 y
0 x
)
536 (funcall function
(aref a k j i
))))
537 (let* ((b1 (sb-ext:array-storage-vector b
))
538 (ma (reduce #'max b1
))
539 (mi (reduce #'min b1
))
540 (result (make-array (list z y x
)
541 :element-type
'(unsigned-byte 8)))
542 (s (/ 255d0
(- ma mi
))))
543 (do-box (k j i
0 z
0 y
0 x
)
544 (setf (aref result k j i
)
545 (floor (* s
(- (aref b k j i
) mi
)))))
548 #+nil
;; compare intensity and |e-field|^2
553 (multiple-value-bind (e0 e1 e2
)
554 (psf:electric-field-psf z x y
10d0
5d0
)
555 (let ((intens (make-array (array-dimensions e0
)
556 :element-type
'(complex double-float
))))
557 (do-box (k j i
0 z
0 y
0 x
)
558 (setf (aref intens k j i
) (complex (+ (psf::abs2
(aref e0 k j i
))
559 (psf::abs2
(aref e1 k j i
))
560 (psf::abs2
(aref e2 k j i
))))))
561 (let* ((k0 (fftshift3 (ft3 intens
)))
562 (k1 (fftshift3 (ft3 (psf:intensity-psf z y x
10d0
5d0
))))
563 (k- (make-array (array-dimensions k0
)
564 :element-type
'(complex double-float
))))
565 (do-box (k j i
0 z
0 y
0 x
)
566 (setf (aref k- k j i
) (- (aref k0 k j i
)
568 (save-stack "/home/martin/tmp/intens0"
570 :function
#'(lambda (x) (* 1d-1
(abs x
))))
571 (write-pgm (convert-img (cross-section-xz k-
)
572 #'(lambda (z) (* 1e-1 (abs z
))))
573 "/home/martin/tmp/intens0xz.pgm"))))))
575 ;; create psf by blocking light in the back-focal plane. only a disk
576 ;; centered on point p=(CENTER-X, CENTER-Y) with r=RADIUS is left
577 ;; transparent. p=(0,0) and r=1 will unblock the full
578 ;; bfp. p=(.9,0). r=.1 will illuminate with a high angle from positive
581 ;; SIZE-X and SIZE-Z give the extend in um. the extend in the y
582 ;; direction is set to SIZE-X.
583 (declaim (ftype (function (double-float double-float double-float
584 &key
(:x fixnum
) (:y fixnum
) (:z fixnum
)
585 (:size-x double-float
)
586 (:size-z double-float
)
587 (:wavelength double-float
)
588 (:numerical-aperture double-float
)
589 (:immersion-index double-float
)
590 (:integrand-evaluations fixnum
))
591 (values (simple-array (complex double-float
) 3)))
593 (defun angular-psf (center-x center-y radius
&key
594 (x 64) (y 64) (z 64) (size-x 12d0
)
597 (numerical-aperture 1.38d0
)
598 (immersion-index 1.515d0
)
599 (integrand-evaluations 31))
600 (let* ((dx (/ x size-x
)) ;; pixels/um
602 ;; calculate the electric field in focus
603 (multiple-value-bind (e0 e1 e2
)
604 (psf:electric-field-psf z y x size-z size-x
605 :numerical-aperture numerical-aperture
606 :immersion-index immersion-index
607 :wavelength wavelength
608 :integrand-evaluations integrand-evaluations
)
609 (write-pgm (normalize-img (cross-section-xz e0
))
610 "/home/martin/tmp/cut-asf-e0-no.pgm")
611 ;; k0, k1 and k2 contain sections of the k-sphere
612 (let* ((k0 (fftshift3 (ft3 e0
)))
613 (k1 (fftshift3 (ft3 e1
)))
614 (k2 (fftshift3 (ft3 e2
)))
615 ;; radius of the circular border of the cut k-sphere
616 ;; sin(phi)=r/k, k=2pi/lambda, sin(phi)=NA/n -> r=k*sin(phi)
617 (sinphi (/ numerical-aperture immersion-index
))
618 (klen (/ (* 2d0 pi
) wavelength
))
619 (bfp-radius (* klen sinphi
))
620 (bfp-radius-pixels (* bfp-radius
(/ dx
(* 2d0
(sqrt 2d0
)))))
621 ;; wiil contain distance to center-x,center-y
622 (rad-a (make-array (list y x
)
623 :element-type
'double-float
)))
624 (defparameter *efield-k
* (list k0 k1 k2
))
625 (write-pgm (normalize-img (cross-section-xz k0
))
626 "/home/martin/tmp/cut-e0-no.pgm")
627 ;; calculate distances to center point for all points in one slice
628 (do-rectangle (j i
0 y
0 x
)
629 (let* ((ii (- i
(floor x
2) (* center-x bfp-radius-pixels
)))
630 (jj (- j
(floor y
2) (* center-y bfp-radius-pixels
)))
631 (radius (sqrt (+ (* 1d0 ii ii
) (* jj jj
)))))
632 (setf (aref rad-a j i
) radius
)))
634 ;; set fourier field to zero if outside of transparent circle
635 (do-box (k j i
0 z
0 y
0 x
)
636 (when (< (* radius bfp-radius-pixels
) (aref rad-a j i
))
637 (setf (aref k0 k j i
) (complex 0d0
)
638 (aref k1 k j i
) (complex 0d0
)
639 (aref k2 k j i
) (complex 0d0
))))
640 (write-pgm (normalize-img (cross-section-xz k0
))
641 "/home/martin/tmp/cut-e0.pgm")
643 ;; deteriorated electric fields
644 (setf e0
(ift3 (fftshift3 k0
))
645 e1
(ift3 (fftshift3 k1
))
646 e2
(ift3 (fftshift3 k2
)))
648 ;; calculate energy density of electric field
649 (let ((density (make-array (array-dimensions e0
)
650 :element-type
'(complex double-float
))))
651 (do-box (k j i
0 z
0 y
0 x
)
652 (setf (aref density k j i
)
653 (complex (+ (psf:abs2
(aref e0 k j i
))
654 (psf:abs2
(aref e1 k j i
))
655 (psf:abs2
(aref e2 k j i
))))))
656 (write-pgm (normalize-img (cross-section-xz density
))
657 "/home/martin/tmp/cut-intens.pgm")
660 #+nil
;; find centers of nuclei
662 (multiple-value-bind (c ch dims
)
664 (defparameter *centers
* c
)
665 (defparameter *center-heights
* ch
)
666 (defparameter *dims
* dims
)
667 (sb-ext:gc
:full t
)))
669 #+nil
;; draw the spheres
671 (destructuring-bind (z y x
)
673 (draw-spheres 7d0
*centers
* (* 5 z
) y x
))))
674 (setf *spheres
* spheres
)
675 (save-stack-ub8 "/home/martin/tmp/spheres" (normalize-vol *spheres
*)))
678 #+nil
;; construct LCOS image
679 (let ((coord (aref *centers
* 0))
681 (slice (make-array (array-dimensions *spheres
*)
682 :element-type
'(complex double-float
))))
683 (destructuring-bind (z y x
)
684 (array-dimensions *spheres
*)
685 ;; draw only the center sphere
686 (let* ((xc (vec-i-x coord
))
688 (zc (* 5 (vec-i-z coord
)))
690 (do-rectangle (j i
0 y
0 x
)
691 (let ((r (sqrt (+ (square (* 1d0
(- i xc
)))
692 (square (* 1d0
(- j yc
)))
693 (square (* 1d0
(- k zc
)))))))
694 (setf (aref slice k j i
)
698 (defparameter *slice
* slice
)
699 (save-stack-ub8 "/home/martin/tmp/slice" (convert-vol slice
))
700 #+nil
(write-pgm (normalize-img (cross-section-xz slice
(* 5 (vec-i-z coord
))))
701 "/home/martin/tmp/cut-intens2.pgm"))
703 (defparameter *bfp-circ-radius
* .5d0
)
704 (defparameter *bfp-circ-center-x
* (- .999d0
*bfp-circ-radius
*))
709 (angular-psf *bfp-circ-center-x
* 0d0
*bfp-circ-radius
* :x
200 :y
200 :z
200
710 :size-x
(* 200 .2d0
) :size-z
(* 200 .2d0
)
711 :integrand-evaluations
160)
714 #+nil
;; light distribution in the specimen
715 ;; default resolution is isotropic 12 um /64 = 187.5 nm/pixel
717 (let* ((radius *bfp-circ-radius
*)
718 (x *bfp-circ-center-x
*)
723 (psf (angular-psf x
0d0 radius
:x xx
:y yy
:z zz
724 :size-x
(* xx dx
) :size-z
(* zz dx
)
725 :integrand-evaluations
190))
726 (dims (destructuring-bind (z y x
)
729 #+nil
(psf-big (make-array dims
730 :element-type
'(complex double-float
))))
731 #+nil
(destructuring-bind (z y x
)
733 (let ((ox (- (floor x
2) (floor xx
2)))
734 (oy (- (floor y
2) (floor yy
2)))
735 (oz (- (floor z
2) (floor zz
2))))
736 (do-box (k j i
0 zz
0 yy
0 xx
)
737 (setf (aref psf-big
(+ oz k
) (+ oy j
) (+ ox i
))
739 #+nil
(defparameter *psf-big
* psf-big
)
740 #+nil
(save-stack-ub8 "/home/martin/tmp/psf-big" (normalize-vol psf-big
))
741 (defparameter *psf
* psf
)
743 (defparameter *slice-x-psf
* (convolve3 *slice
* psf
))
744 (sb-ext:gc
:full t
)))
747 (save-stack-ub8 "/home/martin/tmp/psf" (normalize-vol *psf
*))
764 #+nil
;; draw lines into the light distribution in the specimen
765 (destructuring-bind (z y x
)
766 (array-dimensions *slice-x-psf
*)
767 (let ((coord (elt *centers
* 0))
768 (vol (normalize-vol *slice-x-psf
*))
770 (loop for pos in
(list (list (* (- (floor x
2) (- (vec-i-x coord
) 7)) dx
)
771 (* (- (floor y
2) (vec-i-y coord
)) dx
))
772 (list (* (- (floor x
2) (+ (vec-i-x coord
) 7)) dx
)
773 (* (- (floor y
2) (vec-i-y coord
)) dx
))) do
774 (loop for angle in
(list 0d0
776 (- (- *bfp-circ-center-x
* *bfp-circ-radius
*))
777 (- (+ *bfp-circ-center-x
* *bfp-circ-radius
*))) do
778 (draw-ray-into-vol (first pos
) (second pos
)
781 :shift-z
(- (* 5d0
(vec-i-z coord
))
783 (save-stack-ub8 "/home/martin/tmp/slice-x-psf" vol
)))
786 #+nil
;; draw lines into the volume of the psf
787 (destructuring-bind (z y x
)
788 (array-dimensions *psf-big
*)
789 (let ((vol (normalize-vol *psf-big
*))
791 (draw-ray-into-vol 0d0
0d0
794 :center-z
(floor z
2))
795 (draw-ray-into-vol 0d0
0d0
797 :center-z
(floor z
2))
798 (draw-ray-into-vol 0d0
0d0
800 :center-z
(floor z
2))
801 (draw-ray-into-vol 0d0
0d0
803 :center-z
(floor z
2))
804 (save-stack-ub8 "/home/martin/tmp/psf-big" vol
)))
807 #+nil
;; excited fluorophores
809 (setf *slice-x-psf-times-spheres
* (.
* *spheres
* *slice-x-psf
*))
810 (save-stack-ub8 "/home/martin/tmp/slice-x-psf-times-spheres"
811 (normalize-vol *slice-x-psf-times-spheres
*)))
814 #+nil
;; blur with detection psf
822 (psf (psf:intensity-psf zz yy xx
(* zz dx
) (* xx dx
)
823 :integrand-evaluations
100))
824 (dims (destructuring-bind (z y x
)
827 (psf-big (make-array dims
828 :element-type
'(complex double-float
))))
829 (setf *psf-big
* psf-big
)
830 (destructuring-bind (z y x
)
832 (let ((ox (- (floor x
2) (floor xx
2)))
833 (oy (- (floor y
2) (floor yy
2)))
834 (oz (- (floor z
2) (floor zz
2))))
835 (do-box (k j i
0 zz
0 yy
0 xx
)
836 (setf (aref psf-big
(+ oz k
) (+ oy j
) (+ ox i
))
838 (save-stack-ub8 "/home/martin/tmp/psf-detect-big" (normalize-vol psf-big
))
840 (defparameter *camera-volume
* (convolve3-circ *slice-x-psf-times-spheres
*
841 (fftshift3 psf-big
)))
842 (save-stack-ub8 "/home/martin/tmp/camera-volume"
843 (normalize-vol *camera-volume
*))
844 (sb-ext:gc
:full t
)))
848 #+nil
;; check convolution
850 (let ((a (make-array (list 64 64 64)
851 :element-type
'(complex double-float
)))
852 (b (psf:intensity-psf
64 64 64 20d0
20d0
) #+nil
(make-array (list 64 64 64)
853 :element-type
'(complex double-float
))))
854 (setf (aref a
12 12 12) (complex 255d0
))
855 #+nil
(setf (aref b
0 0 0) (complex 255d0
))
856 (save-stack-ub8 "/home/martin/tmp/conv-test" (normalize-vol (convolve3-circ a
(fftshift3 b
))))))
859 #+nil
;; output the xz cross section centered on a sphere in the middle
860 (let ((coord (aref *centers
* 30)))
861 (write-pgm (normalize-img (cross-section-xz *spheres
* (* 5 (vec-i-z coord
))))
862 "/home/martin/tmp/cut-spheres.pgm")
863 (write-pgm (normalize-img (cross-section-xz *psf-big
*))
864 "/home/martin/tmp/cut-psf-big.pgm")
865 (write-pgm (normalize-img (cross-section-xz *slice-x-psf
* (* 5 (vec-i-z coord
))))
866 "/home/martin/tmp/cut-slice-x-psf.pgm")
867 (write-pgm (normalize-img (cross-section-xz (.
* *spheres
* *slice-x-psf
*) (* 5 (vec-i-z coord
))))
868 "/home/martin/tmp/cut-exfluo.pgm"))
871 (save-stack-ub8 "/home/martin/tmp/spheres" (normalize-vol *spheres
*))
874 (let ((sli (make-array (array-dimensions *spheres
*)
875 :element-type
'(complex double-float
))))
876 (destructuring-bind (z y x
)
877 (array-dimensions *spheres
*)
878 (do-box (k j i
0 z
0 y
0 x
)
879 (setf (aref sli k j i
)
880 (aref *spheres
* k j i
)))
881 (let ((k (* 5 (vec-i-z (aref *centers
* 30)))))
882 (do-rectangle (j i
0 y
0 x
)
883 (setf (aref sli k j i
)
884 (* 10 (aref sli k j i
)))))
885 (defparameter *sli
* sli
))
886 (save-stack-ub8 "/home/martin/tmp/spheres" (normalize-vol *sli
*)))
891 (let ((a (sb-ext:array-storage-vector
*slice
*)))
892 (reduce #'max
(map 'vector
#'abs a
)))
897 #+nil
;; model with unscaled spheres
898 (defparameter *blobs
*
899 (destructuring-bind (z y x
)
901 (draw-spheres 7d0
*centers
* (* 5 z
) y x
)))
904 #+nil
;; print ft of angular psf
905 (time (let* ((radius .5d0
)
907 (psf (angular-psf x
0d0 radius
)))
908 (write-pgm (normalize-img (cross-section-xz (fftshift3 (ft3 psf
))))
909 "/home/martin/tmp/cut-intens.pgm")))
911 (let* ((intens (psf:intensity-psf
64 64 64 10d0
5d0
))
912 (k0 intens
#+nil
(fftshift3 (ft3 intens
))))
913 (save-stack "/home/martin/tmp/intens1" k0
914 :function
#'(lambda (x) (* 1d-5
(abs x
))))
915 (write-pgm (convert-img
916 (cross-section-xz k0
)
917 #'(lambda (z) (* 1d-4
(abs z
))))
918 "/home/martin/tmp/intens1xz.pgm"))
922 (destructuring-bind (z y x
)
923 (array-dimensions *blobs
*)
924 (save-stack "/home/martin/tmp/blobs"
929 #+nil
;; clean up the garbage
934 (sb-vm:memory-usage
:print-spaces t
:count-spaces t
)
939 (sb-vm:instance-usage
:dynamic
)
942 (sb-vm:list-allocated-objects
:dynamic
)
945 (sb-vm:print-allocated-objects
:dynamic
)
948 (format t
"~a~%" (sb-vm::type-breakdown
:dynamic
))
951 (declaim (ftype (function (double-float)
952 (values double-float
&optional
))
958 (declaim (ftype (function ((array double-float
*))
959 (values double-float
&optional
))
961 (defun rosenbrock (p)
962 (let* ((x (aref p
0))
964 (result (+ (sq (- 1 x
))
965 (* 100 (sq (- y
(sq x
)))))))
966 (format t
"~a~%" (list 'rosenbrock p result
))
969 (rosenbrock (make-array 2 :element-type
'double-float
970 :initial-contents
(list 1.5d0
1.5d0
)))
971 ;; run the following code to test the downhill simplex optimizer on a
981 ;; |-------------+-------+------- <- z
986 (time (let ((start (make-array 2 :element-type
'double-float
987 :initial-contents
(list 1.5d0
1.5d0
))))
988 (simplex-anneal:anneal
(simplex-anneal:make-simplex start
1d0
)
992 (defun draw-ray-into-vol (x-mm y-mm bfp-ratio-x bfp-ratio-y vol
995 (destructuring-bind (z y x
)
996 (array-dimensions vol
)
997 (let* ((f (lens:focal-length-from-magnification
63d0
))
1000 (bfp-radius (lens:back-focal-plane-radius f na
))
1001 (obj (lens:make-thin-objective
:normal
(v 0d0
0d0 -
1d0
)
1005 :numerical-aperture na
1006 :immersion-index ri
))
1007 (theta (lens:find-inverse-ray-angle x-mm y-mm obj
))
1008 (phi (atan y-mm x-mm
))
1009 (start (lens:v
(* bfp-ratio-x bfp-radius
)
1010 (* bfp-ratio-y bfp-radius
)
1013 (cz (* .5d0 z
)) ;; position that is in the center of front focal plane
1017 (macrolet ((plane (direction position
)
1018 ;; for defining a plane that is perpendicular to an
1019 ;; axis and crosses it at POSITION
1020 (declare (type (member :x
:y
:z
) direction
))
1021 (let* ((normal (ecase direction
1023 (:y
(lens:v
0d0
1d0
))
1024 (:z
(lens:v
0d0
0d0
1d0
)))))
1025 `(let* ((pos ,position
)
1026 (center (lens::v
* ,normal pos
))
1027 (outer-normal (lens::normalize center
)))
1028 (declare (type double-float pos
))
1029 (lens::make-disk
:normal outer-normal
:center center
)))))
1030 ;; define the borders of the viewing volume, distances in mm
1031 (let ((p+z
(plane :z
(- (* dx
(- z cz
))
1033 (p-z (plane :z
(- (* dx
(- (- z cz
)))
1035 (p+y
(plane :y
(* dx
(- y cy
))))
1036 (p-y (plane :y
(* dx
(- (- y cy
)))))
1037 (p+x
(plane :x
(* dx
(- x cx
))))
1038 (p-x (plane :x
(* dx
(- (- x cx
))))))
1039 (multiple-value-bind (ro s
)
1040 (lens:thin-objective-ray obj
1042 (lens::v
* (lens:v
(* (cos phi
) (sin theta
))
1043 (* (sin phi
) (sin theta
))
1046 (setf s
(lens::v
+ s
(lens:v
0d0
0d0
(* dx shift-z
))))
1047 (let* ((nro (lens::normalize ro
)))
1048 (macrolet ((hit (plane)
1049 ;; (declare (type lens::disk plane))
1050 ;; find intersection between plane and the ray
1051 `(multiple-value-bind (dir hit-point
)
1052 (lens::plane-ray
,plane
1053 ;; shift start of vector a bit
1056 (declare (ignore dir
))
1059 ;; convert coordinates from mm into integer pixel positions
1060 `(let ((h ,hit-expr
))
1061 (declare (type (or null lens
::vec
) h
))
1064 :z
(floor (+ cz
(/ (+ (aref h
2) nf
) dx
)))
1065 :y
(floor (+ cy
(/ (aref h
1) dx
)))
1066 :x
(floor (+ cx
(/ (aref h
0) dx
))))))))
1067 (let* ((h+z
(pixel (hit p
+z
)))
1068 (h-z (pixel (hit p-z
)))
1069 (h+y
(pixel (hit p
+y
)))
1070 (h-y (pixel (hit p-y
)))
1071 (h+x
(pixel (hit p
+x
)))
1072 (h-x (pixel (hit p-x
)))
1073 ;; make a list of all the points
1074 (hlist (list h
+z h-z h
+y h-y h
+x h-x
))
1075 ;; throw away points that are nil or that contain
1076 ;; coordinates outside of the array dimensions
1077 (filtered-hlist (remove-if-not #'(lambda (v)
1079 (and (< -
1 (vec-i-x v
) x
)
1080 (< -
1 (vec-i-y v
) y
)
1081 (< -
1 (vec-i-z v
) z
))
1083 ;; sort best points by x
1084 (choice (sort filtered-hlist
#'< :key
(lambda (v) (vec-i-x v
)))))
1085 (format t
"~a~%" (list 'choice choice
))
1092 (let ((vol (make-array (list 128 128 128) :element-type
'(unsigned-byte 8))))
1093 (loop for i in
'(4.0d-3 -
.2d-3
) do
1094 (draw-ray-into-vol i
0d0
.99d0
.0d0 vol
)
1095 (draw-ray-into-vol i
0d0 -
.99d0
.0d0 vol
)
1096 (draw-ray-into-vol i
0d0
0d0
.99d0 vol
)
1097 (draw-ray-into-vol i
0d0
0d0 -
.99d0 vol
))
1099 (save-stack-ub8 "/home/martin/tmp/line"
1104 (let ((vol (make-array (list 128 128 128) :element-type
'(unsigned-byte 8))))
1105 (draw-line3 (make-vec-i :x
108 :y
112 :z
103)
1106 (make-vec-i :x
82 :y
102 :z
10)
1109 (declaim (ftype (function (fixnum fixnum fixnum
1110 fixnum fixnum fixnum
1111 (simple-array (unsigned-byte 8) 3))
1112 (values (simple-array (unsigned-byte 8) 3) &optional
))
1113 scan-convert-line3x scan-convert-line3y scan-convert-line3z
))
1115 (defun scan-convert-line3x (x1 y1 z1 x2 y2 z2 vol
)
1116 ;; x2 - x1 has to be the biggest difference between endpoint
1120 ;; initialization for y
1124 (ysign (signum ddy
))
1125 (dy (- (* 2 dely
) delx
)) ;; decision variable along y
1126 (yinc1 (* 2 dely
)) ;; increment along y for dy<0
1127 (yinc2 (* 2 (- dely delx
))) ;; inc along y for dy>=0
1128 ;; same initialization for z
1132 (zsign (signum ddz
))
1133 (dz (- (* 2 delz
) delx
))
1135 (zinc2 (* 2 (- delz delx
))))
1137 (error "x2 is <= x1."))
1138 (setf (aref vol z y x
) 255)
1139 (loop while
(< x x2
) do
1140 (incf x
) ;; step in x
1141 (if (< dy
0) ;; then no change in y
1142 (incf dy yinc1
) ;; update dy
1144 (incf dy yinc2
) ;; update dy, and
1145 (incf y ysign
)));; increment/decrement y
1152 (setf (aref vol z y x
) 255)))
1154 ;; start from scan-convert-line3x and replace x->$, y->x, $->y
1155 (defun scan-convert-line3y (x1 y1 z1 x2 y2 z2 vol
)
1161 (xsign (signum ddx
))
1162 (dx (- (* 2 delx
) dely
))
1164 (xinc2 (* 2 (- delx dely
)))
1168 (zsign (signum ddz
))
1169 (dz (- (* 2 delz
) dely
))
1171 (zinc2 (* 2 (- delz dely
))))
1173 (error "y2 is <= y1."))
1174 (setf (aref vol z y x
) 255)
1175 (loop while
(< y y2
) do
1187 (setf (aref vol z y x
) 255)))
1189 ;; replace x->$, z->x, $->z
1190 (defun scan-convert-line3z (x1 y1 z1 x2 y2 z2 vol
)
1196 (ysign (signum ddy
))
1197 (dy (- (* 2 dely
) delz
))
1199 (yinc2 (* 2 (- dely delz
)))
1203 (xsign (signum ddx
))
1204 (dx (- (* 2 delx
) delz
))
1206 (xinc2 (* 2 (- delx delz
))))
1208 (error "z2 is <= z1."))
1209 (setf (aref vol z y x
) 255)
1210 (loop while
(< z z2
) do
1223 (setf (aref vol z y x
) 255)))
1226 (declaim (ftype (function (vec-i vec-i
(simple-array (unsigned-byte 8) 3))
1227 (values (simple-array (unsigned-byte 8) 3) &optional
))
1228 scan-convert-line3
))
1229 (defun scan-convert-line3 (start end vol
)
1230 (let* ((diff (v--i end start
))
1231 (ls (list (list (vec-i-x diff
) 2)
1232 (list (vec-i-y diff
) 1)
1233 (list (vec-i-z diff
) 0)))
1234 (diffa (mapcar #'(lambda (e) (list (abs (first e
))
1236 ;; find the direction with the biggest difference
1237 (sorted-diff-a (sort diffa
#'> :key
#'car
))
1238 (main-direction (second (first sorted-diff-a
))) ;; 2 corresponds to x, 1->y, 0->z
1239 ;; find the order in which to deliver the points
1240 (main-diff (aref diff main-direction
))
1241 ;; we have to swap the points when main-diff is negative
1242 (swap-points?
(< main-diff
0))
1243 ;; create the function name to dispatch to
1244 (function (intern (format nil
"SCAN-CONVERT-LINE3~a" (ecase main-direction
1248 (when (eq 0 main-diff
)
1249 (error "start and end point are the same."))
1271 (let ((vol (make-array (list 128 128 128) :element-type
'(unsigned-byte 8))))
1272 (save-stack-ub8 "/home/martin/tmp/line"
1273 (scan-convert-line3 (make-vec-i :x
0 :y
0 :z
0)
1274 (make-vec-i :x
120 :y
127 :z
127)