;;; -*- Mode: Lisp; Syntax: Common-lisp; Package: MU; Base: 10.; -*-

;;; Copyright (c) 1988, Massachusetts Institute of Technology
;;; Authors: Mike Drumheller, Walter E. Gillett

(in-package :mu)

;;; Edge extraction for the stereo code.

;;;****************************************************************************************************

;;; Returns signed edges, where the sign indicates whether the edge transition is
;;; from dark to light or vice versa (scanning the image in the x direction).
;;; A plus sign indicates dark to light and a minus sign indicates light to dark.
;;; Another way of saying this: plus sign => x component of gradient is positive.
;;; See the documentation for canny-edges!! for an explanation of the arguments.
;;; Signed edges are used in stereomatching, where plus edges are only allowed to
;;; match plus edges and minus edges can match only minus edges.
;;; (WEG 10/27/87)
(*defunc SIGNED-CANNY-EDGES!!
	 (sigma image!!
		&optional smoothed-pixel!! ddx!! ddy!! grad-mag!! grad-angle!!
		&key (boundary-condition ':reflect) (border-constant 128)
		(low-threshold cmv::*low-threshold-factor*)
		(high-threshold cmv::*high-threshold-factor*)
		(noise-percentage cmv::*noise-percentage*))
  (cmv::with-temp-pvars
    (setq ddx!! (or ddx!! (*lx:allocate-signed-pvar (1+ cmv::*smoothed-pixel-bits*))))
    (*let ((signed-edges!! (!! 0))
	   ;; extract unsigned edges
	   (edges!! (cmv::canny-edges!! sigma image!! smoothed-pixel!! ddx!! ddy!!
					grad-mag!! grad-angle!!
					:boundary-condition boundary-condition
					:border-constant border-constant
					:low-threshold low-threshold
					:high-threshold high-threshold
					:noise-percentage noise-percentage)))
      (declare (type (signed-pvar 2) signed-edges!!))
      (declare (type (field-pvar 1) edges!!))
      ;; set the sign of the edge to match the sign of ddx!!
      (*when (plusp!! edges!!)
	(*set signed-edges!!
	      (if!! (plusp!! ddx!!) (!! 1) (!! -1))))
      signed-edges!!)))
  
;;; Find edges.  If gradients-symbol has been provided and we are using the Canny edge
;;; detector, then compute and save the intensity gradient.  We go through some annoying
;;; acrobatics to minimize the space consumption.
(*defunc EDGES!! (image &optional canny-edges? gradients-symbol
			&aux clipped-ddx!! clipped-ddy!!)
  (*let ((edges!! (!! 0)))
    (declare (type (signed-pvar 2) edges!!))
    (if canny-edges?
	(if gradients-symbol
	    ;; compute and save gradients
	    (*let ((ddx!! (!! 0)) (ddy!! (!! 0)))
	      (declare (type (signed-pvar (1+ cmv::*smoothed-pixel-bits*)) ddx!! ddy!!))
	      (*set edges!! (cmv::canny-edges!! *sigma* image nil ddx!! ddy!! nil nil
						:noise-percentage *canny-noise-percentage*))
	      (setq clipped-ddx!! (allocate!! (!! 0) 'ddx!! `(signed-pvar ,*gradient-bits*))
		    clipped-ddy!! (allocate!! (!! 0) 'ddy!! `(signed-pvar ,*gradient-bits*)))
	      (setf (symbol-value gradients-symbol) (list clipped-ddx!! clipped-ddy!!))
	      ;; truncate and save the gradient components
	      (*resize ddx!! clipped-ddx!!)
	      (*resize ddy!! clipped-ddy!!))
	    ;; don't bother with gradients
	    (*set edges!! (signed-canny-edges!! *sigma* image nil nil nil nil nil
						:noise-percentage *canny-noise-percentage*)))
	(*set edges!! (zcs!! image *sigma*)))
    edges!!))

;;; If not *CANNY-EDGES?* then it finds zero-crossings (same sigma).
(*defunc *EDGE-FINDING (dest-left-edges dest-right-edges source-left-image source-right-image
					&optional canny-edges? save-gradients? pause)
  (format t "~%Finding edges...")
  ;; Edges are -1 or +1, where +1 indicates that the x component of the gradient is positive.
  ;; Only edges with the same polarity are allowed to match.  If *match-gradients?* is t, then
  ;; we use a better constraint (similar to one suggested by Eric Grimson) - the gradient
  ;; directions must be the same, within a parameterized tolerance (the default is 30 degrees).
;  (tv:noting-progress ("Finding edges")
    (*set dest-left-edges (edges!! source-left-image canny-edges? (if save-gradients? '*left-gradients*)))
    (*set dest-right-edges (edges!! source-right-image canny-edges? (if save-gradients? '*right-gradients*)))
;  (format t "done.")
    ;; frame gets clipped on top and bottom, don't use edges from clipped area
    (*let ((boolean-t-where-edges-should-survive-clipping
	     (not!! (context-rectangle!! *top-edges-clip* 0 0 *bottom-edges-clip*))))
      (*if boolean-t-where-edges-should-survive-clipping (*set dest-left-edges (!! 0)))
      (*if boolean-t-where-edges-should-survive-clipping (*set dest-right-edges (!! 0))))
    (cond (*display?*
	   (*show-pvar dest-left-edges :x *stereo-x0-offset* :y *stereo-y-offset*)
	   (*show-pvar dest-right-edges :x *stereo-x1-offset* :y *stereo-y-offset*)
	   (if pause (pause)))))
;)
