home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
vis-ftp.cs.umass.edu
/
vis-ftp.cs.umass.edu.tar
/
vis-ftp.cs.umass.edu
/
pub
/
Software
/
ASCENDER
/
ascendMar8.tar
/
UMass
/
BoldtNew
/
canny-boldt.lisp
< prev
next >
Wrap
Lisp/Scheme
|
1996-03-08
|
12KB
|
298 lines
(in-package 'boldt)
;; CANNY-BOLDT.LISP - runs the boldt line linking algorithm on canny edgels
;; Bob Collins Tue Jan 23 11:22:14 EST 1996
;; Copyright: University of Massachusetts, 1996
;; relies on code in $CME/code/CME-6d/UMass/LineFinder/topdown-line-finder.lisp
;; which relies on $CMEHOME/ic/canny.lisp
(defun write-boldt-edgel (stream u v gradx grady mag)
"Write out boldt edgel info: x1 y1 x2 y2 theta contrast length."
(let ((x u)(y v))
;;length of edgel is 1.4 so that diagonal lines get grouped OK
;;note: grouping wasn't working for them when the length was 1.0
(let* ((dx (* 1.4 (/ grady mag 2.0)))
(dy (* 1.4 (/ (- gradx) mag 2.0)))
(theta (atan (- dy) dx)))
(when (minusp theta) (setf theta (+ theta pi pi)))
(format stream "~,2f ~,2f ~,2f ~,2f ~,5f ~,2f 1.4~%"
(- x dx) (- y dy) (+ x dx) (+ y dy)
theta mag))))
(defun edges-to-boldt-file (edges filename &optional
(startx 0)(starty 0)
(endx (1- (ic::image-x-dim (cme::edgeimg-bit edges))))
(endy (1- (ic::image-y-dim (cme::edgeimg-bit edges))))
(xdim (ic::image-x-dim (cme::edgeimg-bit edges)))
(ydim (ic::image-y-dim (cme::edgeimg-bit edges))))
"Write edges out to a file to be input by the Boldt linking algorithm."
;first count number of edges
(let ((edgebits (cme::edgeimg-bit edges))
(gradx (cme::edgeimg-gradx edges))
(grady (cme::edgeimg-grady edges))
(gradmag (cme::edgeimg-mag edges))
(numedges 0))
(setf startx (max 0 startx) starty (max 0 starty)
endx (min (1- (ic::image-x-dim edgebits)) endx)
endy (min (1- (ic::image-y-dim edgebits)) endy))
(ic::with-image-elements (edgebits) ;;FIRST COUNT NUMBER OF EDGELS
(do ((y starty (1+ y)))
((> y endy) nil)
(do ((x startx (1+ x)))
((> x endx) nil)
(when (= (ic::iref edgebits x y) 1)
(incf numedges)))))
(with-open-file (file filename :direction :output)
;;WRITE OUT HEADER
(format file "~d ~d ~d ~d ~d~%" numedges 0 0 xdim ydim)
;;THEN LOOP THROUGH EDGELS AND WRITE THEM OUT ONE BY ONE
(ic::with-image-elements (edgebits gradx grady gradmag)
(do ((y starty (1+ y)))
((> y endy) nil)
(do ((x startx (1+ x)))
((> x endx) nil)
(when (= (ic::iref edgebits x y) 1)
;;WRITE OUT THE EDGEL
(write-boldt-edgel file
(+ x 0.5) (+ y 0.5)
(ic::iref gradx x y) (ic::iref grady x y)
(ic::iref gradmag x y)))))))
numedges))
(defun read-lines-into-fs (stream fs world &key (transform nil) (swap-xy nil))
"Reads in a set of ascii lines from a stream into a feature set."
(let ((numlines (read stream))
(namestring (string (cme::name world))))
(read-line stream) ;;skip rest of header
(multiple-value-bind (ignore tksname) (cme::get-or-make-ISR-tokenset fs)
ignore
(cme::read-ascii-lines-into-isr
tksname stream numlines :docstring namestring
:transform transform :swap-xy swap-xy))
(cme::process-object-updates) ;;BobC 2/20/96
(map 'nil #'cme::refresh-view (cme::view-list world))
fs))
(defun sensitivity-params (&optional (sensitivity (cadr '(:low :medium :high))))
" Return parameters are canny mask size, lo threshold, high threshold,
and final line length threshold."
(ecase sensitivity
(:low (list 4 2 4 10))
(:medium (list 4 1 4 5))
(:high (list 4 1 2 3))))
(defun full-filename (string &optional (dir user::*temp-directory*))
(cme::translated-unix-path (format nil "~a~a" dir string)))
(defun boldt-filename (string)
(full-filename string user::*boldt-directory*))
(defun temp-filename (string)
(full-filename string user::*temp-directory*))
(defvar *max-block* 300)
(defun canny-boldt-uv (image u1 v1 u2 v2 fs &key (sensitivity :medium)
(minlength nil))
" Run Canny-Boldt line extraction on the given image, within the
bounding box (u1,v1)-(u2,v2), specified in image coordinates.
Resulting lines are put in the feature set specified by fs.
Sensitivity can be :low, :medium (default), or :high."
(when (> u1 u2) (rotatef u1 u2))
(when (> v1 v2) (rotatef v1 v2))
(let ((xdim (ic::image-x-dim image))
(ydim (ic::image-y-dim image)))
(setf u1 (min (max u1 0) xdim) v1 (min (max v1 0) ydim)
u2 (max 0 (min u2 (1- xdim))) v2 (max 0 (min v2 (1- ydim))))
(multiple-value-bind (mask-size low-thresh high-thresh length-thresh)
(values-list (sensitivity-params sensitivity))
(when (> minlength length-thresh) (setf length-thresh minlength))
(let* ((du (- u2 u1))(dv (- v2 v1))(pixsize (* du dv))
(Ublocks (ceiling du *max-block*))
(Vblocks (ceiling dv *max-block*))
(pixsofar 0)(pixthistime 0))
;; (print (list u1 v1 u2 v2 du dv Ublocks vblocks))
(ic::noting-progress ("Boldt" pixsize :progress-var bvar)
(do ((Vcnt 1 (1+ vcnt))
(vstart v1 (+ vstart *max-block*))
(vend (min v2 (+ v1 *max-block*))
(min v2 (+ vend *max-block*))))
((> Vcnt Vblocks) nil)
(do ((ucnt 1 (1+ ucnt))
(ustart u1 (+ ustart *max-block*))
(uend (min u2 (+ u1 *max-block*))
(min u2 (+ uend *max-block*))))
((> ucnt ublocks) nil)
(setf pixthistime (* (- uend ustart) (- vend vstart)))
(let* ((edges (cme::compute-imageuv-canny-edges
image ustart vstart uend vend
:mask-size mask-size
:lo-threshold low-thresh
:hi-threshold high-thresh))
(xdim (ic::image-x-dim (cme::edgeimg-image edges)))
(ydim (ic::image-y-dim (cme::edgeimg-image edges)))
(halfsize (1+ (ash mask-size -1))))
(ic::note-progress (+ pixsofar (* 0.2 pixthistime)) bvar)
(edges-to-boldt-file
edges (temp-filename "cannyedges.asc")
halfsize halfsize (- xdim halfsize 2) (- ydim halfsize 2))
(ic::note-progress (+ pixsofar (* 0.4 pixthistime)) bvar)
(let ((trans (cme::image-to-2d-transform
(cme::edgeimg-image edges))))
(cme::free-edgeimg edges)
(unless (zerop (shell (format nil "~a ~a ~d ~d ~d"
(boldt-filename "runboldt")
(temp-filename "")
xdim ydim length-thresh)))
(warn "Error calling Boldt line algorithm"))
(ic::note-progress (+ pixsofar (* 0.8 pixthistime)) bvar)
(with-open-file (file (temp-filename "boldtlines.asc")
:direction :input)
(read-lines-into-fs file fs (cme::2d-world image)
:transform trans :swap-xy t))
(incf pixsofar pixthistime)
(ic::note-progress pixsofar bvar))))))
fs))))
(defun canny-boldt (image x1 y1 x2 y2 fs &key (sensitivity :medium)
(minlength nil))
" Run Canny-Boldt line extraction on the given image, within the
bounding box (x1,y1)-(x2,y2), specified in 2d-world coordinates.
Resulting lines are put in the feature set specified by fs.
Sensitivity can be :low, :medium (default), or :high."
(when (> x1 x2) (rotatef x1 x2))
(when (> y1 y2) (rotatef y1 y2))
(multiple-value-bind (u1 v1 u2 v2)
(cme::transform-2dworld-bounding-box image x1 y1 x2 y2)
(canny-boldt-uv image u1 v1 u2 v2 fs
:sensitivity sensitivity :minlength minlength)))
(defun run-boldt-from-menu ()
(ic::with-cvv-items
(((sens "Sensitivity" :assoc :alist
(("Low" :low "Low sensitivity")
("Medium" :medium "Medium sensitivity")
("High" :high "High sensitivity"))
:documentation "Choose a sensitivity setting"
:initial-value :medium)
(minlength "Min Length" :float :initial-value 5.0
:documentation "Minimum desired line length")
(maxres "Max Resolution"
:yes-or-no :initial-value t
:documentation "use highest available image resolution?"))
:label "Boldt Lines")
(multiple-value-bind (bbox panechoice) (cme::pick-bounding-box-and-pane)
(let* ((topview (cme::top-view panechoice))
(image (if maxres
(ic::top-of-image-hierarchy (cme::view-image topview))
(cme::view-image topview)))
(world (cme::2d-world image))
(fs (cme::get-or-make-2d-feature-set world cme::*2d-line-fsname*))
(2dtoim-trans (cme::inverse-transform
(cme::image-to-2d-transform image)))
(winto2d-trans (cme::inverse-transform
(cme::2d-to-window-transform topview)))
(wintoim-trans (cme::make-composite-coordinate-transform
(list winto2d-trans 2dtoim-trans))))
(multiple-value-bind (u1 v1 u2 v2)
(apply #'cme::transform-2d-bounding-box wintoim-trans bbox)
(canny-boldt-uv image u1 v1 u2 v2 fs
:sensitivity sens :minlength minlength))))))
#|======================================================================
(defun test-canny-boldt (&key (sensitivity (cadr '(:low :medium :high))))
(multiple-value-bind (bbox panechoice) (cme::pick-bounding-box-and-pane)
(let* ((topview (cme::top-view panechoice))
(image (ic::top-of-image-hierarchy (cme::view-image topview)))
(world (cme::2d-world image))
(fs (cme::find-fs-named world cme::*2d-line-fsname*))
(pane-trans (cme::inverse-transform
(cme::2d-to-window-transform topview)))
(world-bbox (multiple-value-list
(apply #'cme::transform-2d-bounding-box pane-trans bbox)))
(sensparams (sensitivity-params sensitivity))
(mask-size (car sensparams))
(low-thresh (cadr sensparams))
(high-thresh (third sensparams))
(length-thresh (fourth sensparams))
(halfsize (1+ (ash mask-size -1)))
(edges nil)(xdim nil) (ydim nil) (trans nil))
(setf edges (cme::compute-2dworld-canny-edges
image (car world-bbox) (cadr world-bbox)
(third world-bbox) (fourth world-bbox)
:mask-size mask-size
:lo-threshold low-thresh
:hi-threshold high-thresh))
(setf xdim (ic::image-x-dim (cme::edgeimg-image edges)))
(setf ydim (ic::image-y-dim (cme::edgeimg-image edges)))
(edges-to-boldt-file edges (temp-filename "cannyedges.asc")
halfsize halfsize
(- xdim halfsize 2) (- ydim halfsize 2))
(setf trans (cme::image-to-2d-transform (cme::edgeimg-image edges)))
(cme::free-edgeimg edges)
(shell (format nil "~a ~a ~d ~d ~d" (boldt-filename "runboldt")
(temp-filename "") xdim ydim length-thresh))
(read-lines-into-fs (temp-filename "boldtlines.asc") trans fs world)
t)))
|#
#|
(defun cme::cl ()
(load (compile-file (boldt::boldt-filename "canny-boldt.lisp"))))
(defun foo (imax)
(ic::noting-progress ("Test" imax :progress-var my-progress)
(dotimes (i imax)
(print (list i (log (+ 1.0 (sqrt i)))))
(sleep 0.5)
(ic::note-progress i my-progress ))))
(defun write-lines-from-fs (stream fs)
"Writes a set of ascii lines from a feature set to a stream."
(let ((numlines 0))
(dolist (obj (cme::inferiors fs))
(when (eq (type-of obj) 'cme::2d-curve)
(incf numlines)))
(format stream "~d curves~%" numlines)
(dolist (obj (cme::inferiors fs) fs)
(when (eq (type-of obj) 'cme::2d-curve)
(let ((verts (cme::make-vertex-list-from-vertex-array
(cme::vertices obj))))
(let ((x1 (car (car verts)))
(y1 (cadr (car verts)))
(x2 (car (cadr verts)))
(y2 (cadr (cadr verts)))
(cont 0.0))
(format stream "~,4f ~,4f ~,4f ~,4f ~,4f~%" x1 y1 x2 y2 cont)))))))
(defun convert-isr-tokens-to-cme-curves (tokenset fs)
(let ((world (2d-world fs)))
(isr2::for-every-token (tok tokenset (x1 y1 x2 y2))
(let ((vx1 (isr2::value x1))
(vy1 (isr2::value y1))
(vx2 (isr2::value x2))
(vy2 (isr2::value y2)))
(add-object
(make-2d-curve
:vertices (cme::make-vertex-array-from-vertex-list
(list (list vx1 vy1 0.0)
(list vx2 vy2 0.0)))
:closed-p t
:world world)
fs)))
fs))
|#