1 #.
(progn (require :asdf
)
6 (require :simplex-anneal
)
12 (:use
:cl
:vector
:vol
:raytrace
19 cp
/home
/martin
/0519/MedianofCelegans-10-02-09-LSM700-t58.tif ~
/tmp
/med.tif
22 for i in
*.tif
; do tifftopnm $i > `basename $i .tif`.pgm;done
26 (defun draw-sphere-ub8 (radius z y x
)
27 (declare (double-float radius
)
29 (values (simple-array (unsigned-byte 8) 3)
31 (let ((sphere (make-array (list z y x
)
32 :element-type
'(unsigned-byte 8))))
33 (let ((xh (floor x
2))
36 (radius2 (* radius radius
)))
37 (do-box (k j i
0 z
0 y
0 x
)
38 (let ((r2 (+ (expt (* 1d0
(- i xh
)) 2)
39 (expt (* 1d0
(- j yh
)) 2)
40 (expt (* 1d0
(- k zh
)) 2))))
41 (setf (aref sphere k j i
)
46 (count-non-zero-ub8 (draw-sphere-ub8 1d0
41 58 70))
48 (let ((a (draw-sphere-ub8 1d0
54 (destructuring-bind (z y x
)
56 (do-box (k j i
0 z
0 y
0 x
)
57 (when (eq 1 (aref a k j i
))
58 (setf res
(list k j i
))))
61 (defun draw-oval-ub8 (radius z y x
)
62 (declare (double-float radius
)
64 (values (simple-array (unsigned-byte 8) 3)
66 (let ((sphere (make-array (list z y x
)
67 :element-type
'(unsigned-byte 8)))
69 (do-box (k j i
0 z
0 y
0 x
)
70 (let ((r (sqrt (+ (square (- i
(* .5d0 x
)))
71 (square (- j
(* .5d0 y
)))
72 (square (* scale-z
(- k
(* .5d0 z
))))))))
73 (setf (aref sphere k j i
)
79 (declaim (ftype (function ()
80 (values (simple-array vec-i
1)
81 (simple-array double-float
1)
86 ;; to find centers of cells do a convolution with a sphere
87 (defun find-centers ()
88 (let* ((stack-byte (read-stack "/home/martin/tmp/xa*.pgm"))
89 (stack (make-array (array-dimensions stack-byte
)
90 :element-type
'(complex double-float
))))
91 (destructuring-bind (z y x
)
92 (array-dimensions stack
)
96 (let ((v (+ (* .43745d0 k
)
97 (aref stack-byte k j i
))))
99 (aref stack-byte k j i
) (clamp (floor v
))
100 (aref stack k j i
) (complex v
))))))
101 #+nil
(setf *stack
* stack
)
102 ;; find centers of cells by convolving with sphere, actually an
103 ;; oval because the z resolution is smaller than the transversal
104 (let* ((sphere (convert3-ub8/cdf-complex
(draw-oval-ub8 11d0 z y x
)))
105 (conv (convolve3-circ stack
(fftshift3 sphere
)))
106 (conv-byte (make-array (list y x
)
107 :element-type
'(unsigned-byte 8)))
108 (centers (make-array 0 :element-type
'vec-i
109 :initial-element
(make-vec-i)
112 (center-heights (make-array 0 :element-type
'double-float
115 (loop for k from
6 below
(- z
3) do
116 (loop for j from
1 below
(1- y
) do
117 (loop for i from
1 below
(1- x
) do
118 (let ((v (abs (aref conv k j i
))))
119 (setf (aref conv-byte j i
)
120 (if (and (< (abs (aref conv k j
(1- i
))) v
)
121 (< (abs (aref conv k j
(1+ i
))) v
)
122 (< (abs (aref conv k
(1- j
) i
)) v
)
123 (< (abs (aref conv k
(1+ j
) i
)) v
)
124 (< (abs (aref conv
(1- k
) j i
)) v
)
125 (< (abs (aref conv
(1+ k
) j i
)) v
))
128 (make-vec-i :z k
:y j
:x i
)
130 (vector-push-extend v center-heights
)
132 (clamp (floor (/ v
(* 4e2 x y z
)))))))))
133 #+nil
(write-pgm conv-byte
134 (format nil
"/home/martin/tmp/conv~3,'0d.pgm" k
)))
135 (let ((c (make-array (length centers
)
137 :initial-contents centers
))
138 (ch (make-array (length center-heights
)
139 :element-type
'double-float
140 :initial-contents center-heights
)))
141 (values c ch
(array-dimensions stack
)))))))
144 (declaim (ftype (function (fixnum)
145 (values fixnum
&optional
))
147 (defun ensure-even (x)
152 (declaim (ftype (function (double-float (simple-array vec-i
1)
153 &key
(:div-x double-float
)
154 (:div-y double-float
)
155 (:div-z double-float
))
156 (values (simple-array (complex double-float
) 3)
158 draw-scaled-spheres
))
159 ;; put points into the centers of nuclei and convolve a sphere around each
160 (defun draw-scaled-spheres (radius centers
&key
(div-x 5d0
)
163 (let* ((max-x (floor (reduce #'max
164 (map '(simple-array fixnum
1) #'vec-i-x
166 (max-y (floor (reduce #'max
167 (map '(simple-array fixnum
1) #'vec-i-y
169 (max-z (floor (reduce #'max
170 (map '(simple-array fixnum
1) #'vec-i-z
172 (cr (ceiling radius
))
173 (rh (floor radius
2))
174 (x (ensure-even (+ max-x cr
)))
175 (y (ensure-even (+ max-y cr
)))
176 (z (ensure-even (+ max-z cr
)))
178 (points (make-array dims
179 :element-type
'(complex double-float
))))
180 (loop for c across centers do
182 (- (floor (vec-i-z c
) div-z
) rh
)
183 (- (floor (vec-i-y c
) div-y
) rh
)
184 (- (floor (vec-i-x c
) div-x
) rh
))
186 (convolve3-circ points
187 (convert3-ub8/cdf-complex
(draw-sphere-ub8 radius z y x
)))))
191 (declaim (ftype (function (double-float (simple-array vec-i
1)
194 (values (simple-array (complex double-float
) 3)
196 draw-spheres draw-ovals
))
197 ;; put points into the centers of nuclei and convolve a sphere around each
198 (defun draw-spheres (radius centers z y x
)
199 (let* ((dims (list z y x
))
200 (points (make-array dims
201 :element-type
'(complex double-float
)))
202 (n (length centers
)))
204 (let ((c (aref centers i
)))
210 (convolve3-circ points
(fftshift3 (convert3-ub8/cdf-complex
211 (draw-sphere-ub8 radius z y x
))))))
213 (defun draw-ovals (radius centers z y x
)
214 (let* ((dims (list z y x
))
215 (points (make-array dims
216 :element-type
'(complex double-float
)))
217 (n (length centers
)))
219 (let ((c (aref centers i
)))
225 (convolve3-circ points
(fftshift3 (convert3-ub8/cdf-complex
226 (draw-oval-ub8 radius z y x
))))))
232 (defparameter *merge
*
233 (let ((a (make-array (array-dimensions *stack
*)
234 :element-type
'(unsigned-byte 8))))
235 (destructuring-bind (z y x
)
236 (array-dimensions *stack
*)
237 (do-box (k j i
0 z
0 y
0 x
)
239 (clamp (if (eq 0 (aref *blobs
*
241 (* (aref *stack
* k j i
) 2)
244 (save-stack-ub "/home/martin/tmp/merge" *merge
*))
246 ;; (- z k 1) (- y j 1) (- x i 1)
250 #+nil
;; model with isotropic pixels
251 (save-stack-ub "/home/martin/tmp/iso/iso"
252 (convert-vol (draw-scaled-spheres 2d0
*centers
*)))
255 (save-stack-ub "/home/martin/tmp/blobs" *blobs
*)
258 (save-scaled-stack 100 100 "/home/martin/tmp/sca" *blobs
*)
260 #+nil
;; find maximum
261 (reduce #'max
(map 'vector
#'abs
(sb-ext:array-storage-vector
*stack
*)))
264 (destructuring-bind (z y x
)
265 (array-dimensions *stack
*)
266 (do-box (k j i
0 z
0 y
0 x
)
267 (setf (aref *stack
* k j i
)
268 (/ (aref *stack
* k j i
) 257d0
))))
271 (save-stack "/home/martin/tmp/stack" *stack
*)
274 #+nil
;; make a text image of the psf
275 (let ((numerical-aperture 1.38d0
))
276 (psf:init
:numerical-aperture numerical-aperture
)
277 (multiple-value-bind (u v
)
278 (psf:get-uv
0 1.5 3 :numerical-aperture numerical-aperture
)
281 (a (psf:integ-all nu nv
(/ u nu
) (/ v nv
)))
284 (destructuring-bind (uu vv
)
289 (format t
"~2d" (truncate (* scale
(aref a u v
)))))
296 (save-stack "/home/martin/tmp/psf"
297 (fftshift3 (ft3 (sim-psf 128 128 128 z
(* .5d0 z
))))
298 :function
#'(lambda (x) (* .01d0
(abs x
))))))
300 ;; worm stack 0.198 um in X and Y and 1 um in Z
303 (array-dimensions *blobs
*)
305 #+nil
;; write ft of object
307 (save-stack "/home/martin/tmp/kblobs" (fftshift3 (ft3 *blobs
*))
308 :function
#'(lambda (x) (* 1d-4
(abs x
)))))
310 #+nil
;; write ft of psf
312 (destructuring-bind (z y x
)
313 (array-dimensions *blobs
*)
314 (save-stack "/home/martin/tmp/otf"
315 (fftshift3 (ft3 (sim-psf z y x
318 (ceiling (* (sqrt 2d0
) (max y x
)))))))
319 :function
#'(lambda (x) (* 1d-1
(abs x
))))))
321 (declaim (ftype (function ((simple-array (complex double-float
) (* * *)))
322 (values (simple-array (complex double-float
) (* * *))
326 (let ((out (make-array (array-dimensions in
)
327 :element-type
'(complex double-float
))))
328 (destructuring-bind (w2 w1 w0
)
329 (array-dimensions in
)
333 (let* ((kk (if (> k
(/ w2
2))
334 (+ w2
(/ w2
2) (- k
))
336 (setf (aref out k j i
)
345 (destructuring-bind (z y x
)
346 (array-dimensions *blobs
*)
347 (let ((psf (sim-psf z y x
348 (* .198d0 z
) (* .198d0
(ceiling (* (sqrt 2d0
) (max y x
)))))))
349 (save-stack "/home/martin/tmp/impsf"
350 (convolve3 *blobs
* psf
)
351 :function
#'(lambda (x) (* 1d-8
(realpart x
)))))))
355 #+nil
;; compare intensity and |e-field|^2
360 (multiple-value-bind (e0 e1 e2
)
361 (psf:electric-field-psf z x y
10d0
5d0
)
362 (let ((intens (make-array (array-dimensions e0
)
363 :element-type
'(complex double-float
))))
364 (do-box (k j i
0 z
0 y
0 x
)
365 (setf (aref intens k j i
) (complex (+ (psf::abs2
(aref e0 k j i
))
366 (psf::abs2
(aref e1 k j i
))
367 (psf::abs2
(aref e2 k j i
))))))
368 (let* ((k0 (fftshift3 (ft3 intens
)))
369 (k1 (fftshift3 (ft3 (psf:intensity-psf z y x
10d0
5d0
))))
370 (k- (make-array (array-dimensions k0
)
371 :element-type
'(complex double-float
))))
372 (do-box (k j i
0 z
0 y
0 x
)
373 (setf (aref k- k j i
) (- (aref k0 k j i
)
375 (save-stack "/home/martin/tmp/intens0"
377 :function
#'(lambda (x) (* 1d-1
(abs x
))))
378 (write-pgm (convert-img (cross-section-xz k-
)
379 #'(lambda (z) (* 1e-1 (abs z
))))
380 "/home/martin/tmp/intens0xz.pgm"))))))
384 #+nil
;; find centers of nuclei 12.5s 3.1s
386 (multiple-value-bind (c ch dims
)
388 (defparameter *centers
* c
)
389 (defparameter *center-heights
* ch
)
390 (defparameter *dims
* dims
)
391 (sb-ext:gc
:full t
)))
393 #+nil
;; draw the spheres (squeezed in z) 9.7s 1.8s
396 (destructuring-bind (z y x
)
398 (draw-ovals 7d0
*centers
* z y x
))))
399 (setf *spheres
* spheres
)
400 #+nil
(save-stack-ub8 "/home/martin/tmp/spheres" (normalize-vol *spheres
*))
401 (write-pgm (normalize-img (cross-section-xz *spheres
*
402 (vec-i-y (elt *centers
* 31))))
403 "/home/martin/tmp/spheres-cut.pgm")
404 (sb-ext:gc
:full t
)))
406 #+nil
;; draw the spheres (squeezed in z) and emphasize one of them
409 (destructuring-bind (z y x
)
411 (let* ((dims (list z y x
))
412 (points (make-array dims
413 :element-type
'(complex double-float
)))
416 (n (length centers
)))
418 (let ((c (aref centers i
)))
423 (complex (if (eq i
31)
426 (convolve3-circ points
(fftshift3 (draw-oval radius z y x
)))))))
427 (save-stack-ub8 "/home/martin/tmp/spheres" (normalize-ub8 spheres
))
428 (sb-ext:gc
:full t
)))
430 #+nil
;; construct LCOS image
431 (let ((coord (aref *centers
* 31))
433 (slice (make-array (array-dimensions *spheres
*)
434 :element-type
'(complex double-float
))))
435 (destructuring-bind (z y x
)
436 (array-dimensions *spheres
*)
437 ;; draw only the center sphere
438 (let* ((xc (vec-i-x coord
))
442 (do-rectangle (j i
0 y
0 x
)
443 (let ((r (sqrt (+ (square (* 1d0
(- i xc
)))
444 (square (* 1d0
(- j yc
)))
445 (square (* 1d0
(- k zc
)))))))
446 (setf (aref slice k j i
)
450 (defparameter *slice
* slice
)
451 #+nil
(save-stack-ub8 "/home/martin/tmp/slice" (convert-vol slice
))
452 (write-pgm (normalize-img (cross-section-xz slice
(vec-i-y coord
)))
453 "/home/martin/tmp/slice-cut.pgm")
456 (defparameter *bfp-circ-radius
* .3d0
)
457 (defparameter *bfp-circ-center-x
* .4d0
#+nil
(- .999d0
*bfp-circ-radius
*))
462 (angular-psf :x
80 :z
90
463 :window-x
*bfp-circ-center-x
*
464 :window-y
0d0
:window-radius
*bfp-circ-radius
*
465 :numerical-aperture
1.38d0
466 :immersion-index
1.515d0
467 :pixel-size-x
.1d0
:pixel-size-z
.5d0
468 :integrand-evaluations
160
472 #+nil
;; light distribution in the specimen
473 ;; default resolution is isotropic 12 um /64 = 187.5 nm/pixel
482 (angular-psf :window-x
*bfp-circ-center-x
*
484 :window-radius
*bfp-circ-radius
*
485 :x
(* 2 xx
) :z
(* 2 zz
)
486 :pixel-size-x dx
:pixel-size-z dz
487 :integrand-evaluations
200)))
488 (dims (destructuring-bind (z y x
)
491 (write-pgm (normalize-img (cross-section-xz psf
))
492 "/home/martin/tmp/small-psf-cut.pgm")
494 (defparameter *slice-x-psf
* (convolve3 *slice
* psf
))
495 (sb-ext:gc
:full t
)))
498 (defparameter *slice-x-psf
* nil
)
502 (write-pgm (normalize-img
503 (cross-section-xz *slice-x-psf
*
504 (vec-i-y (elt *centers
* 31))))
505 "/home/martin/tmp/slice-x-psf-cut.pgm")
508 (save-stack-ub8 "/home/martin/tmp/psf" (normalize-ub8 *psf
*))
511 #+nil
;; draw lines into the light distribution in the specimen
512 (destructuring-bind (z y x
)
513 (array-dimensions *slice-x-psf
*)
514 (let ((coord (elt *centers
* 31))
515 (vol (normalize-ub8 *slice-x-psf
*))
518 #+nil
(draw-ray-into-vol (* dx
(- (floor x
2) (vec-i-x coord
)))
519 (* dx
(- (floor y
2) (vec-i-y coord
)))
521 (loop for pos in
(list (list (* (- (floor x
2) (- (vec-i-x coord
) 7)) dx
)
522 (* (- (floor y
2) (vec-i-y coord
)) dx
))
523 (list (* (- (floor x
2) (+ (vec-i-x coord
) 7)) dx
)
524 (* (- (floor y
2) (vec-i-y coord
)) dx
))) do
525 (loop for angle in
(list ;;-.010d0
527 ;;(- (- *bfp-circ-center-x* *bfp-circ-radius*))
530 (- *bfp-circ-center-x
*)
531 ;;(- (+ *bfp-circ-center-x* *bfp-circ-radius*))
533 (draw-ray-into-vol (first pos
) (second pos
)
536 :shift-z
(- (vec-i-z coord
)
539 #+nil
(write-pgm (normalize-img
540 (cross-section-xz vol
541 (vec-i-y (elt *centers
* 31))))
542 "/home/martin/tmp/slice-x-psf-lines-cut.pgm")
543 (save-stack-ub8 "/home/martin/tmp/slice-x-psf" vol
)))
546 #+nil
;; excited fluorophores
548 (setf *slice-x-psf-times-spheres
* (.
* *spheres
* *slice-x-psf
*))
549 (save-stack-ub8 "/home/martin/tmp/slice-x-psf-times-spheres"
550 (normalize-ub8 *slice-x-psf-times-spheres
*)))
553 #+nil
;; blur with detection psf
561 (psf (psf:intensity-psf zz yy xx
(* zz dx
) (* xx dx
)
562 :integrand-evaluations
100))
563 (dims (destructuring-bind (z y x
)
566 (psf-big (make-array dims
567 :element-type
'(complex double-float
))))
568 (setf *psf-big
* psf-big
)
569 (destructuring-bind (z y x
)
571 (let ((ox (- (floor x
2) (floor xx
2)))
572 (oy (- (floor y
2) (floor yy
2)))
573 (oz (- (floor z
2) (floor zz
2))))
574 (do-box (k j i
0 zz
0 yy
0 xx
)
575 (setf (aref psf-big
(+ oz k
) (+ oy j
) (+ ox i
))
577 (save-stack-ub8 "/home/martin/tmp/psf-detect-big" (normalize-ub8 psf-big
))
579 (defparameter *camera-volume
* (convolve3-circ *slice-x-psf-times-spheres
*
580 (fftshift3 psf-big
)))
581 (save-stack-ub8 "/home/martin/tmp/camera-volume"
582 (normalize-ub8 *camera-volume
*))
583 (sb-ext:gc
:full t
)))
587 #+nil
;; check convolution
589 (let ((a (make-array (list 64 64 64)
590 :element-type
'(complex double-float
)))
591 (b (psf:intensity-psf
64 64 64 20d0
20d0
) #+nil
(make-array (list 64 64 64)
592 :element-type
'(complex double-float
))))
593 (setf (aref a
12 12 12) (complex 255d0
))
594 #+nil
(setf (aref b
0 0 0) (complex 255d0
))
595 (save-stack-ub8 "/home/martin/tmp/conv-test" (normalize-ub8 (convolve3-circ a
(fftshift3 b
))))))
598 #+nil
;; output the xz cross section centered on a sphere in the middle
599 (let ((coord (aref *centers
* 30)))
600 (write-pgm (normalize-img (cross-section-xz *spheres
* (* 5 (vec-i-z coord
))))
601 "/home/martin/tmp/cut-spheres.pgm")
602 (write-pgm (normalize-img (cross-section-xz *psf-big
*))
603 "/home/martin/tmp/cut-psf-big.pgm")
604 (write-pgm (normalize-img (cross-section-xz *slice-x-psf
* (* 5 (vec-i-z coord
))))
605 "/home/martin/tmp/cut-slice-x-psf.pgm")
606 (write-pgm (normalize-img (cross-section-xz (.
* *spheres
* *slice-x-psf
*) (* 5 (vec-i-z coord
))))
607 "/home/martin/tmp/cut-exfluo.pgm"))
610 (save-stack-ub8 "/home/martin/tmp/spheres" (normalize-ub8 *spheres
*))
613 (let ((sli (make-array (array-dimensions *spheres
*)
614 :element-type
'(complex double-float
))))
615 (destructuring-bind (z y x
)
616 (array-dimensions *spheres
*)
617 (do-box (k j i
0 z
0 y
0 x
)
618 (setf (aref sli k j i
)
619 (aref *spheres
* k j i
)))
620 (let ((k (* 5 (vec-i-z (aref *centers
* 30)))))
621 (do-rectangle (j i
0 y
0 x
)
622 (setf (aref sli k j i
)
623 (* 10 (aref sli k j i
)))))
624 (defparameter *sli
* sli
))
625 (save-stack-ub8 "/home/martin/tmp/spheres" (normalize-ub8 *sli
*)))
630 (let ((a (sb-ext:array-storage-vector
*slice
*)))
631 (reduce #'max
(map 'vector
#'abs a
)))
636 #+nil
;; model with unscaled spheres
637 (defparameter *blobs
*
638 (destructuring-bind (z y x
)
640 (draw-spheres 7d0
*centers
* (* 5 z
) y x
)))
643 #+nil
;; print ft of angular psf
644 (time (let* ((radius .5d0
)
646 (psf (angular-psf x
0d0 radius
)))
647 (write-pgm (normalize-ub8 (cross-section-xz (fftshift3 (ft3 psf
))))
648 "/home/martin/tmp/cut-intens.pgm")))
650 (let* ((intens (psf:intensity-psf
64 64 64 10d0
5d0
))
651 (k0 intens
#+nil
(fftshift3 (ft3 intens
))))
652 (save-stack "/home/martin/tmp/intens1" k0
653 :function
#'(lambda (x) (* 1d-5
(abs x
))))
654 (write-pgm (convert-img
655 (cross-section-xz k0
)
656 #'(lambda (z) (* 1d-4
(abs z
))))
657 "/home/martin/tmp/intens1xz.pgm"))
661 (destructuring-bind (z y x
)
662 (array-dimensions *blobs
*)
663 (save-stack "/home/martin/tmp/blobs"
668 #+nil
;; clean up the garbage
673 (sb-vm:memory-usage
:print-spaces t
:count-spaces t
)
678 (sb-vm:instance-usage
:dynamic
)
681 (sb-vm:list-allocated-objects
:dynamic
)
684 (sb-vm:print-allocated-objects
:dynamic
)
687 (format t
"~a~%" (sb-vm::type-breakdown
:dynamic
))
690 (declaim (ftype (function (double-float)
691 (values double-float
&optional
))
697 (declaim (ftype (function ((array double-float
*))
698 (values double-float
&optional
))
700 (defun rosenbrock (p)
701 (let* ((x (aref p
0))
703 (result (+ (sq (- 1 x
))
704 (* 100 (sq (- y
(sq x
)))))))
705 (format t
"~a~%" (list 'rosenbrock p result
))
708 (rosenbrock (make-array 2 :element-type
'double-float
709 :initial-contents
(list 1.5d0
1.5d0
)))
710 ;; run the following code to test the downhill simplex optimizer on a
720 ;; |-------------+-------+------- <- z
725 (time (let ((start (make-array 2 :element-type
'double-float
726 :initial-contents
(list 1.5d0
1.5d0
))))
727 (simplex-anneal:anneal
(simplex-anneal:make-simplex start
1d0
)
731 (defun draw-ray-into-vol (x-mm y-mm bfp-ratio-x bfp-ratio-y vol
732 &key
(dx-mm .2d-3
) (dz-mm 1d-3
)
734 (destructuring-bind (z y x
)
735 (array-dimensions vol
)
736 (let* ((f (lens:focal-length-from-magnification
63d0
))
739 (bfp-radius (lens:back-focal-plane-radius f na
))
740 (obj (lens:make-thin-objective
:normal
(v 0d0
0d0 -
1d0
)
744 :numerical-aperture na
745 :immersion-index ri
))
746 (theta (lens:find-inverse-ray-angle x-mm y-mm obj
))
747 (phi (atan y-mm x-mm
))
748 (start (v (* bfp-ratio-x bfp-radius
)
749 (* bfp-ratio-y bfp-radius
)
753 (cz (* .5d0 z
)) ;; position that is in the center of front focal plane
757 (macrolet ((plane (direction position
)
758 ;; for defining a plane that is perpendicular to an
759 ;; axis and crosses it at POSITION
760 (declare (type (member :x
:y
:z
) direction
))
761 (let* ((normal (ecase direction
764 (:z
(v 0d0
0d0
1d0
)))))
765 `(let* ((pos ,position
)
766 (center (v* ,normal pos
))
767 (outer-normal (normalize center
)))
768 (declare (type double-float pos
))
769 (lens::make-disk
:normal outer-normal
:center center
)))))
770 ;; define the borders of the viewing volume, distances in mm
771 (let ((p+z
(plane :z
(- (* dz
(- z cz
))
773 (p-z (plane :z
(- (* dz
(- (- z cz
)))
775 (p+y
(plane :y
(* dx
(- y cy
))))
776 (p-y (plane :y
(* dx
(- (- y cy
)))))
777 (p+x
(plane :x
(* dx
(- x cx
))))
778 (p-x (plane :x
(* dx
(- (- x cx
))))))
779 (multiple-value-bind (ro s
)
780 (lens:thin-objective-ray obj
782 (v* (v (* (cos phi
) (sin theta
))
783 (* (sin phi
) (sin theta
))
786 (setf s
(v+ s
(v 0d0
0d0
(* dz shift-z
))))
787 (let* ((nro (normalize ro
)))
788 (macrolet ((hit (plane)
789 ;; (declare (type lens::disk plane))
790 ;; find intersection between plane and the ray
791 `(multiple-value-bind (dir hit-point
)
792 (lens::plane-ray
,plane
793 ;; shift start of vector a bit
796 (declare (ignore dir
))
799 ;; convert coordinates from mm into integer pixel positions
800 `(let ((h ,hit-expr
))
801 (declare (type (or null vec
) h
))
804 :z
(floor (+ cz
(/ (+ (aref h
2) nf
) dz
)))
805 :y
(floor (+ cy
(/ (aref h
1) dx
)))
806 :x
(floor (+ cx
(/ (aref h
0) dx
))))))))
807 (let* ((h+z
(pixel (hit p
+z
)))
808 (h-z (pixel (hit p-z
)))
809 (h+y
(pixel (hit p
+y
)))
810 (h-y (pixel (hit p-y
)))
811 (h+x
(pixel (hit p
+x
)))
812 (h-x (pixel (hit p-x
)))
813 ;; make a list of all the points
814 (hlist (list h
+z h-z h
+y h-y h
+x h-x
))
815 ;; throw away points that are nil or that contain
816 ;; coordinates outside of the array dimensions
817 (filtered-hlist (remove-if-not #'(lambda (v)
819 (and (< -
1 (vec-i-x v
) x
)
821 (< -
1 (vec-i-z v
) z
))
823 ;; sort best points by x
824 (choice (sort filtered-hlist
#'< :key
(lambda (v) (vec-i-x v
)))))
825 (format t
"~a~%" (list 'choice choice
))
832 (let ((vol (make-array (list 128 128 128) :element-type
'(unsigned-byte 8))))
833 (loop for i in
'(4.0d-3 -
.2d-3
) do
834 (draw-ray-into-vol i
0d0
.99d0
.0d0 vol
)
835 (draw-ray-into-vol i
0d0 -
.99d0
.0d0 vol
)
836 (draw-ray-into-vol i
0d0
0d0
.99d0 vol
)
837 (draw-ray-into-vol i
0d0
0d0 -
.99d0 vol
))
839 (save-stack-ub8 "/home/martin/tmp/line"
844 (let ((vol (make-array (list 128 128 128) :element-type
'(unsigned-byte 8))))
845 (draw-line3 (make-vec-i :x
108 :y
112 :z
103)
846 (make-vec-i :x
82 :y
102 :z
10)
852 ;; -/ h (3) | \--- (2) q_R=NA/ri*q_max
853 ;; -----------+------------/------------
857 ;; ---------+-----------------+-------
858 ;; | (0) / (1) q_max=1/(2*pixel)
860 ;; The resolution of the image has to be big enough to fit the top
861 ;; section of the k-sphere with radius |k|=2pi*q_max into the k space.
862 ;; q_max (see (1)) is due to the nyquist theorem and corresponds to 1
863 ;; over two sample widths. The radius of the backfocal plane
864 ;; corresponds to q_R (see (2) ri is the refractive index,
865 ;; e.g. 1.515). It is bigger for an objective with a high NA.
867 ;; A transform with uneven number of samples doesn't have a bin for
868 ;; the nyquist sampling (draw the unit circle and divide it into n
869 ;; equal bins starting from e^(i*0). For uneven n there will be no bin
870 ;; on e^-i (i.e. -1, 1, -1 ...), e.g. n=3). For even n there will be
871 ;; n/2+1 bins ontop of the real axis (e.g. 0=1, 1=e^(-i pi/2), 2=e^-i
872 ;; for n=4, the arguments to the exponential are (i 2 pi j/n) for the
873 ;; j-th bin) and n/2-1 bins below (e.g 3=e^(i pi/2)). In order to
874 ;; simplify fftshift3 I only consider transforms with even n.
875 ;; fftshift moves the n/2+1 bins from the front of the array to the
876 ;; back (for n=4: [0 1 2 3] -> [3 0 1 2]). In the shifted array the
877 ;; highest reverse frequency (bin 3) is mapped to index 0. The origin
878 ;; of k-space (see (0) in the sketch) is therefor mapped to bin n/2-1
879 ;; (bin 1 for n=4). The nyquist frequency is in the last bin n-1 (bin
882 ;; We now search for the right z-sampling dz to fit the top of the
883 ;; sphere below the nyquist bin (which corresponds to q_max=1/(2*dz)).
884 ;; |k|=2 pi/lambda = 2 pi q_max, with wavelength lambda
885 ;; lambda=2 dz -> dz = lambda/2.
887 ;; We could use the same sampling x and y to represent the electric
888 ;; field. For small numerical apertures the sampling distance can be
889 ;; increased. This time the radius q_R has to be smaller than the nyquist
891 ;; 1/(2*dx)=q_R=NA/ri * 1/lambda
892 ;; -> dx= lambda/2 * ri/NA= dz *ri/NA=dz*1.515/1.38
894 ;; The sampling distances dz and dx that I derived above are only good
895 ;; to represent the amplitude psf. When the intensity is to be
896 ;; calculated the sampling distance has to be changed to accomodate
897 ;; for the convolution in k space.
899 ;; The height of the sphere cap (h see (3) in sketch) is
900 ;; h=q_max-q_max*cos(alpha)=q_max ( 1-cos(alpha))
901 ;; =q_max*(1-sqrt(1-sin(alpha)^2))=q_max*(1-sqrt(1-(NA/ri)^2)) The z
902 ;; sample distance dz2 for the intensity psf should correspond to 1/(2
903 ;; dz2)=2 h, i.e. dz2=1/h=dz*2/(1-sqrt(1-(NA/ri)^2))>dz so the necessary z
904 ;; sampling distance for the intensity is in general bigger than for
907 ;; The radius of the convolved donut shape is 2 q_R. Therefor the
908 ;; transversal sampling distance for the intensity has to be smaller:
911 ;; As we are only interested in the intensity psf we can sample the
912 ;; amplitude psf with a sampling distance dz2. The sphere cap is
913 ;; possibly wrapped along the k_z direction. The transversal direction
914 ;; of the amplitude psf has to be oversampled with dx2.
916 ;; To get an angular illumination psf we multiply the values on the
917 ;; sphere with a k_z plane containing a disk that is centered at any
918 ;; k_x and k_y inside the back focal plane. Later I might want to
919 ;; replace this with a gaussian or a more elaborate window function.
921 ;; With a sampling dx2 the radius of the backfocal plane fills half of
922 ;; the k space. The coordinate calculations below are corrected for
923 ;; this. So setting cx to 1. and cy to 0. below would center the
924 ;; circle on the border of the bfp.
926 ;; For n=1.515 and NA=1.38 the ratio dz2/dx2 is ca. 6. Angular
927 ;; blocking allows to increase dz2 and dx2 a bit. Depending on which
928 ;; and how big an area of the BFP is transmitted. Calculating these
929 ;; smaller bounds seems to be quite complicated and I don't think it
930 ;; will speed things up considerably. Also it will be possible to
931 ;; calculate many different angular illuminations from an amplitude
932 ;; otf that has been sampled with dx2 and dz2 without reevalutation of
935 ;; I want to be able to set dz3 and dx3 to the same values that
936 ;; Jean-Yves used for the confocal stack. I have to introduce
937 ;; sx=dx2/dx3 to scale cx and cy into the back focal plane.
939 (declaim (ftype (function (&key
(:x fixnum
) (:y fixnum
) (:z fixnum
)
940 (:window-radius double-float
)
941 (:window-x double-float
)
942 (:window-y double-float
)
943 (:pixel-size-x
(or null double-float
))
944 (:pixel-size-z
(or null double-float
))
945 (:wavelength double-float
)
946 (:numerical-aperture double-float
)
947 (:immersion-index double-float
)
948 (:integrand-evaluations fixnum
)
950 (values (simple-array (complex double-float
) 3)))
953 (defun angular-psf (&key
(x 64) (y x
) (z 40)
955 (window-x (- 1d0 window-radius
))
960 (numerical-aperture 1.38d0
)
961 (immersion-index 1.515d0
)
962 (integrand-evaluations 30)
964 ;; changing z,y,x without touching dx or dz leaves the area that is
965 ;; shown in k space constant
966 (let* ((na numerical-aperture
)
970 (dz2 (* dz
(/ 2d0
(- 1d0
(sqrt (- 1d0
971 (let ((sinphi (/ na ri
)))
972 (* sinphi sinphi
))))))))
973 (dx (* dz
(/ ri na
)))
975 (dx3 (if pixel-size-x
977 #+nil
(unless (< pixel-size-x dx2
)
978 (error "pixel-size-x is ~a but should be smaller than ~a"
982 (dz3 (if pixel-size-z
984 #+nil
(unless (< pixel-size-z dz2
)
985 (error "pixel-size-z is ~a but should be smaller than ~a"
989 (multiple-value-bind (e0 e1 e2
)
990 (psf:electric-field-psf z y x
(* z dz3
) (* x dx3
)
991 :numerical-aperture na
994 :integrand-evaluations integrand-evaluations
)
996 (write-pgm (normalize-ub8 (cross-section-xz e0
))
997 "/home/martin/tmp/cut-0psf.pgm"))
998 (let ((k0 (fftshift3 (ft3 e0
)))
999 (k1 (fftshift3 (ft3 e1
)))
1000 (k2 (fftshift3 (ft3 e2
))))
1001 (when debug
(write-pgm (normalize-ub8 (cross-section-xz k0
))
1002 "/home/martin/tmp/cut-1psf-k.pgm"))
1003 (let* ((cr window-radius
)
1008 (window (make-array (list y x
)
1009 :element-type
'double-float
)))
1011 (do-rectangle (j i
0 y
0 x
)
1012 (let* ((xx (- (* sx
(* 4d0
(- (* i
(/ 1d0 x
)) .5d0
))) cx
))
1013 (yy (- (* sx
(* 4d0
(- (* j
(/ 1d0 y
)) .5d0
))) cy
))
1014 (r2 (+ (* xx xx
) (* yy yy
))))
1016 (setf (aref window j i
) 1d0
))))
1017 (do-box (k j i
0 z
0 y
0 x
)
1018 (setf (aref k0 k j i
) (* (aref k0 k j i
) (aref window j i
))
1019 (aref k1 k j i
) (* (aref k1 k j i
) (aref window j i
))
1020 (aref k2 k j i
) (* (aref k2 k j i
) (aref window j i
))))
1021 (when debug
(write-pgm (normalize-ub8 (cross-section-xz k0
))
1022 "/home/martin/tmp/cut-2psf-k-mul.pgm"))
1023 (let* ((e0 (ift3 (fftshift3 k0
)))
1024 (e1 (ift3 (fftshift3 k1
)))
1025 (e2 (ift3 (fftshift3 k2
)))
1026 (intens k0
)) ;; instead of allocating a new array we store into k0
1027 (do-box (k j i
0 z
0 y
0 x
)
1028 (setf (aref intens k j i
)
1029 (+ (* (aref e0 k j i
) (conjugate (aref e0 k j i
)))
1030 (* (aref e1 k j i
) (conjugate (aref e1 k j i
)))
1031 (* (aref e2 k j i
) (conjugate (aref e2 k j i
))))))
1033 (write-pgm (normalize-ub8 (cross-section-xz intens
))
1034 "/home/martin/tmp/cut-3psf-intens.pgm")
1035 (let ((k (fftshift3 (ft3 intens
))))
1036 (write-pgm (normalize-ub8 (cross-section-xz k
))
1037 "/home/martin/tmp/cut-4psf-intk.pgm")))
1042 (angular-psf :x
128 :z
64 :integrand-evaluations
120 :debug t
)
1045 #+nil
;; convert coordinates of spheres from integers into doubles,
1046 ;; corresponding to mm.
1049 (n (length *centers
*))
1050 (sph (make-array n
:element-type
'raytrace
::sphere
)))
1053 (make-sphere :center
(let ((a (elt *centers
* i
)))
1054 (v (* dx
(vec-i-x a
))
1056 (* dz
(vec-i-z a
))))
1057 :radius
(* dx
7d0
))))
1058 (defparameter *sphere-c-r
* sph
))
1061 (dotimes (i (length *centers
*))
1063 (raytrace::ray-spheres-intersection
(v) (v 0d0
0d0 -
1d0
) *sphere-c-r
* i
)))
1066 (declaim (ftype (function (vec)
1067 (values double-float
&optional
))
1070 (defun merit-function (vec)
1071 (raytrace:ray-spheres-intersection
1073 (normalize (direction (aref vec
0) (aref vec
1)))
1078 (let ((start (make-array 2 :element-type
'double-float
1079 :initial-contents
(list 100d0
100d0
))))
1080 (with-open-file (*standard-output
* "/dev/shm/anneal.log"
1082 :if-exists
:supersede
)
1083 (anneal (make-simplex start
1d0
)
1085 :start-temperature
3d0
)))
1088 (defun create-sphere-array (dims centers
)
1089 (declare (cons dims
)
1090 ((simple-array vec-i
1) centers
)
1091 (values (simple-array sphere
1) &optional
))
1092 (destructuring-bind (z y x
)
1094 (declare (fixnum z y x
))
1100 (n (length centers
))
1101 (result (make-array n
:element-type
'sphere
1102 :initial-contents
(loop for i below n collect
1104 (labels ((convert-point (point)
1105 (declare (vec-i point
)
1106 (values vec
&optional
))
1107 (v (* dx
(- (vec-i-x point
) xh
))
1108 (* dx
(- (vec-i-y point
) yh
))
1109 (* dz
(- (vec-i-z point
) zh
)))))
1111 (setf (aref result i
)
1112 (make-sphere :center
(convert-point (aref centers i
))
1113 :radius
(* dx
17d0
))))
1118 (defparameter *central-sphere
* 22)
1119 (defparameter *spheres-c-r
*
1120 (create-sphere-array *dims
* *centers
*)))
1124 ;; The merit function should get two parameters r and phi. if r isn't
1125 ;; inside the back focal plane radius (minus the diameter of the
1126 ;; aperture window) some high value is returned. Several rays should
1127 ;; be sent through the spheres starting from different positions on
1128 ;; the aperture window and targetting different positions in the
1129 ;; circle that should be illuminated in the sample.
1131 ;; Maybe later I can add the aperture size in the back focal plane as
1132 ;; another parameter. The bigger the aperture, the better for the
1135 ;; Possibly I shouldn't call it merit function as I try to minimize
1138 ;; get-ray-behind-objective takes a point on the back focal plane and
1139 ;; a point in the sample and calculates the ray direction ro that
1140 ;; leaves the objective. So its the same calculation that is used for
1141 ;; draw-ray-into-vol.
1142 (declaim (ftype (function (double-float double-float double-float double-float
)
1143 (values vec vec
&optional
))
1144 get-ray-behind-objective
))
1145 (defun get-ray-behind-objective (x-mm y-mm bfp-ratio-x bfp-ratio-y
)
1146 (let* ((f (lens:focal-length-from-magnification
63d0
))
1149 (bfp-radius (lens:back-focal-plane-radius f na
))
1150 (obj (lens:make-thin-objective
:normal
(v 0d0
0d0 -
1d0
)
1154 :numerical-aperture na
1155 :immersion-index ri
))
1156 (theta (lens:find-inverse-ray-angle x-mm y-mm obj
))
1157 (phi (atan y-mm x-mm
))
1158 (start (v (* bfp-ratio-x bfp-radius
)
1159 (* bfp-ratio-y bfp-radius
)
1161 (multiple-value-bind (ro s
)
1162 (lens:thin-objective-ray obj
1164 (v* (v (* (cos phi
) (sin theta
))
1165 (* (sin phi
) (sin theta
))
1171 (get-ray-behind-objective .1d0
.1d0
0d0
0d0
)
1173 ;; In *spheres-c-r* I stored the coordinates of all the nuclei
1174 ;; relative to the center of the initial stack of images. It also
1175 ;; contains the radius of each nuclieus. Now I consider how to
1176 ;; illuminate selected circles inside of the sample. The nucleus which
1177 ;; is beeing illuminated will be centered on the focal plane. The
1178 ;; length of the vector ro coming out of the objective is
1179 ;; nf=1.515*2.6mm~3000um and therefore a lot bigger than the z extent
1180 ;; of the stack (~40 um). It is not necessary to z-shift the nuclei
1181 ;; before intersecting them with the rays. So I will just use the
1182 ;; nucleus' x and y coordinates as arguments to
1183 ;; get-ray-behind-objective. I also supply the position in the back
1184 ;; focal plane from where the ray originates.
1186 (deftype direction
()
1187 `(member :left
:right
:top
:bottom
))
1189 (defun sample-circle (center radius direction
)
1190 "Given a circle CENTER and RADIUS return the point in the left,
1191 right, top or bottom of its periphery. CENTER and result are complex
1193 (declare ((complex double-float
) center
)
1194 (double-float radius
)
1195 (direction direction
)
1196 (values (complex double-float
) &optional
))
1197 (let ((phi (ecase direction
1201 (:bottom
(* 1.5 pi
)))))
1202 (+ center
(* radius
(exp (complex 0d0 phi
))))))
1205 (sample-circle (complex 1d0
1d0
) 1d0
:right
)
1207 (defun illuminate-ray
1208 (spheres-c-r illuminated-sphere-index
1210 bfp-center-x bfp-center-y
1211 bfp-radius bfp-position
)
1212 "Trace a ray from a point in the back focal plane through the disk
1213 that encompasses the nucleus with index
1214 ILLUMINATED-SPHERE-INDEX. SAMPLE-POSITION and BFP-POSITION can assume
1215 one of the four values :LEFT, :RIGHT, :TOP and :BOTTOM indicating
1216 which point on the periphery of the corresponding circle is meant."
1217 (declare (fixnum illuminated-sphere-index
)
1218 (direction sample-position bfp-position
)
1219 (double-float bfp-center-x bfp-center-y bfp-radius
)
1220 ((simple-array sphere
1) spheres-c-r
)
1221 (values double-float
&optional
))
1222 (with-slots (center radius
)
1223 (aref spheres-c-r illuminated-sphere-index
)
1224 (let* ((sample-pos (sample-circle (complex (vec-x center
) (vec-y center
))
1227 (bfp-pos (sample-circle (complex bfp-center-x bfp-center-y
)
1230 (multiple-value-bind (ro s
)
1231 (get-ray-behind-objective (realpart sample-pos
)
1232 (imagpart sample-pos
)
1236 (ray-spheres-intersection
1237 ;; shift by nf so that sample is in origin
1241 (* 1.515 (lens:focal-length-from-magnification
63d0
))))
1244 illuminated-sphere-index
)))
1248 (illuminate-ray *spheres-c-r
* 30 :bottom
1252 #+nil
;; scan the bfp
1254 (with-open-file (s "/home/martin/tmp/scan.dat"
1256 :if-exists
:supersede
1257 :if-does-not-exist
:create
)
1258 (let ((bfp-window-radius .08d0
)
1261 (let ((np (ceiling (1+ (* ir ir
)) 4)))
1264 (let* ((r (* ir
(/ (- .99d0 bfp-window-radius
) (1- nr
))))
1265 (phi (* (/ (* 2d0 pi
) np
) ip
))
1266 (z (* r
(exp (complex 0d0 phi
)))))
1267 (format s
"~4,4f ~4,4f ~4,4f~%" (realpart z
) (imagpart z
)
1269 (make-vec2 :x
(realpart z
)
1270 :y
(imagpart z
)))))))))))
1273 (with-open-file (s "/home/martin/tmp/scan.dat"
1275 :if-exists
:supersede
1276 :if-does-not-exist
:create
)
1278 (loop for x from -
1d0 upto
1d0 by dx do
1279 (loop for y from -
1d0 upto
1d0 by dx do
1280 (format s
"~4,4f ~4,4f ~4,4f~%"
1282 (make-vec2 :x x
:y y
))))
1285 (defvar *nucleus-index
* 26)
1286 (defvar *bfp-window-radius
* .1d0
)
1287 (defvar *spheres-c-r
* nil
)
1289 ;; the following global variable contain state for merit-function:
1290 ;; *bfp-window-radius* *nucleus-index* *spheres-c-r*
1291 (defun merit-function (vec2)
1292 (declare (vec2 vec2
)
1293 (values double-float
&optional
))
1294 (let* ((border-value .08d0
) ;; value to return when outside of bfp
1295 (border-width *bfp-window-radius
*) ;; in this range to the
1296 ;; border of the bfp
1297 ;; enforce bad merit
1300 (radius (norm2 vec2
)))
1301 (if (< radius
(- .99d0 border-width
))
1303 (loop for dirs in
'((:right
:left
)
1305 (loop for dir in dirs do
1306 (loop for bfp-dir in dirs do
1308 (illuminate-ray *spheres-c-r
* *nucleus-index
* dir
1309 (vec2-x vec2
) (vec2-y vec2
)
1312 ;; in the border-width or outside of bfp
1313 (incf sum border-value
))
1317 (let ((start (make-array 2 :element-type
'double-float
1318 :initial-contents
(list 100d0
100d0
))))
1319 (with-open-file (*standard-output
* "/dev/shm/anneal.log"
1321 :if-exists
:supersede
)
1322 (simplex-anneal:anneal
(simplex-anneal:make-simplex start
1d0
)
1324 :start-temperature
12d0
)))
1326 ;; scan over the full parameters space
1329 (with-open-file (s "/dev/shm/o.dat" :direction
:output
:if-exists
:supersede
)
1332 (dotimes (theta ntheta
)
1334 (let ((a (* 90 (/ theta ntheta
)))
1335 (b (* 180 (/ phi nphi
))))
1336 (format s
"~f ~f ~f~%" a b
1337 (ray-spheres-intersection (v) (direction a b
)))))
1339 (with-open-file (s "/dev/shm/p1.gp" :direction
:output
1340 :if-exists
:supersede
)
1341 (format s
"set term posts; set outp \"/dev/shm/p~2,'0d.ps\";set hidden
1342 set title \"nucleus nr. ~d\"
1344 splot \"/dev/shm/o.dat\" u 1:2:3 w l
1346 " *central-sphere
* *central-sphere
*)))
1350 (defun split-by-char (char string
)
1351 "Returns a list of substrings of string
1352 divided by ONE character CHAR each.
1353 Note: Two consecutive CHAR will be seen as
1354 if there were an empty string between them."
1355 (declare (character char
)
1357 (loop for i
= 0 then
(1+ j
)
1358 as j
= (position char string
:start i
)
1359 collect
(subseq string i j
)
1363 (split-by-char #\x
"12x124x42")
1365 (defun parse-raw-filename (fn)
1366 "Parses a filename like
1367 /home/martin/d0708/stacks/c-291x354x41x91_dx200_dz1000.raw and returns
1368 291 354 41 and 91 as multiple values."
1369 (declare (string fn
)
1370 (values (or null fixnum
) fixnum fixnum fixnum
&optional
))
1371 (let* ((p- (position #\- fn
:from-end t
))
1372 (part (subseq fn
(1+ p-
)))
1373 (p_ (position #\_ part
))
1374 (sizes (subseq part
0 p_
))
1375 (numlist (split-by-char #\x sizes
)))
1376 (unless (eq 4 (length numlist
))
1377 (error "didn't read 4 dimensions as expected."))
1378 (destructuring-bind (x y z time
)
1379 (mapcar #'read-from-string numlist
)
1380 (values x y z time
))))
1384 (parse-raw-filename "/home/martin/d0708/stacks/c-291x354x41x91_dx200_dz1000.raw")
1386 (defun read-raw-stack-video-frame (fn time
)
1387 (declare (string fn
)
1389 (values (simple-array (unsigned-byte 8) 3) &optional
))
1390 (multiple-value-bind (x y z maxtime
)
1391 (parse-raw-filename fn
)
1392 (unless (< time maxtime
)
1393 (error "requested time ~d is to big (must be <~d!)" time maxtime
))
1394 (let* ((vol (make-array (list z y x
)
1395 :element-type
'(unsigned-byte 8)))
1396 (vol1 (sb-ext:array-storage-vector vol
)))
1397 (with-open-file (s fn
:direction
:input
1398 :element-type
'(unsigned-byte 8))
1399 (file-position s
(* x y z time
))
1400 (read-sequence vol1 s
))
1404 (let* ((fn "/home/martin/d0708/stacks/c-291x354x41x91_dx200_dz1000_2.raw")
1405 (ao (decimate-xy-ub8 5
1406 (read-raw-stack-video-frame fn
0))))
1407 (destructuring-bind (z y x
)
1408 (array-dimensions ao
)
1409 (let* ((timestep 20)
1410 (o (loop for radius from
1 upto
10 collect
1411 (let* ((oval (draw-sphere-ub8 (* 1d0 radius
) z y x
))
1412 (volume (count-non-zero-ub8 oval
)))
1414 (ft3 (convert3-ub8/cdf-complex oval
)))))))
1415 (let* ((ao (decimate-xy-ub8 5
1416 (read-raw-stack-video-frame fn timestep
)))
1417 (a (convert3-ub8/cdf-complex ao
))
1420 (destructuring-bind (radius volume oval
)
1422 (let* ((dir (format nil
"/home/martin/tmp/o~d" radius
))
1423 (conv (fftshift3 (ift3 (.
* ka oval
))))
1424 (conv-df (convert3-cdf/df-realpart conv
)))
1426 (normalize-ub8-df/ub8-realpart conv-df
))
1427 (with-open-file (s (format nil
"~a/maxima" dir
)
1428 :if-exists
:supersede
1430 (loop for el in
(find-maxima3-df conv-df
) do
1431 (destructuring-bind (height pos
)
1433 (format s
"~f ~d ~a~%"
1437 (map 'vec-i
#'(lambda (x) (floor x
2)) pos
)
1443 (save-stack-ub8 "/home/martin/tmp/conv" conv
)
1449 (destructuring-bind (z y x
)
1450 (array-dimensions *a
*)
1451 (let ((b (draw-ovals 12d0
(find-maxima3 conv
) (ensure-even z
) (ensure-even y
) (ensure-even x
))))
1452 (write-pgm (convert-img (cross-section-xz b
42))
1453 "/home/martin/tmp/time0.pgm")))
1455 (defun find-maxima3-df (conv)
1456 (declare ((simple-array double-float
3) conv
)
1457 (values (simple-array * 1) &optional
))
1458 (destructuring-bind (z y x
)
1459 (array-dimensions conv
)
1460 (let ((centers nil
#+nil
(make-array 0 :element-type
'vec-i
1461 :initial-element
(make-vec-i)
1464 (do-box (k j i
6 (- z
3) 1 (1- y
) 1 (1- x
))
1465 (let ((v (aref conv k j i
)))
1466 (when (and (< (aref conv k j
(1- i
)) v
)
1467 (< (aref conv k j
(1+ i
)) v
)
1468 (< (aref conv k
(1- j
) i
) v
)
1469 (< (aref conv k
(1+ j
) i
) v
)
1470 (< (aref conv
(1- k
) j i
) v
)
1471 (< (aref conv
(1+ k
) j i
) v
))
1473 #+nil
(setf centers
(append centers
1474 (list (list v
(make-vec-i :z k
:y j
:x i
)))))
1476 #+nil
(setf centers
(nconc centers
1477 (list (list v
(make-vec-i :z k
:y j
:x i
)))))
1478 ;; I think push is the right thing to do
1479 (push (list v
(make-vec-i :z k
:y j
:x i
)) centers
)
1480 #+nil
(vector-push-extend
1481 (make-vec-i :z k
:y j
:x i
)
1483 ;; (nreverse centers)
1484 (coerce centers
'simple-vector
) ;; I saw this in raylisps load-obj
1485 #+nil
(make-array (length centers
)
1486 :element-type
'vec-i
1487 :initial-contents centers
))))