2

Consider this C code from OpenCV Tutorial 8 - Chapter 9

// Learn the background statistics for one more frame
void accumulateBackground( IplImage *I ){
    static int first = 1;
    cvCvtScale( I, Iscratch, 1, 0 );
    if( !first ){
        cvAcc( Iscratch, IavgF );
        cvAbsDiff( Iscratch, IprevF, Iscratch2 );
        cvAcc( Iscratch2, IdiffF );
        Icount += 1.0;
    }
    first = 0;
    cvCopy( Iscratch, IprevF );
}

It seems the way the code is designed that because of

if( !first )

the program will never execute:

cvAcc( Iscratch, IavgF );
cvAbsDiff( Iscratch, IprevF, Iscratch2 );
cvAcc( Iscratch2, IdiffF );
Icount += 1.0;

In Lisp I'm trying to translate this as:

(defun accumulate-background (i)
  (setf 1st 1)
  (cvt-scale i i-scratch-1 1 0) ;; To float
  (if (not 1st) 
      (progn (acc i-scratch-1 i-avg-f)
             (abs-diff i-scratch-1 i-prev-f i-scratch-2)
             (acc i-scratch-2 i-diff-f)
             (setf i-count (+ i-count 1.0))))
  (setf 1st 0)
  (copy i-scratch-1 i-prev-f))

For the equivalent function, with (not 1st) for !first, and I think that's correct. In C++ I do:

static int first = 1;

if( first ){
  cout << "reached this part of code " << endl << " " << first << endl << endl;
} 

but never produce any output because of the code design, it seems. Why would the designer of the tutorial code like this? He is copying from Learning OpenCV.

Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353

3 Answers3

5

The variable first in the C code is static which means that there is only one instance of it, and that it's shared between all the calls to the function. (See the accepted answer to What does "static" mean? for more information about static in C.) This is sort of like having a global variable, except that other functions don't have access to it (because it's not in their scope). You could simulate this in Common Lisp using a global variable defined with defvar or defparameter, but I think a more straightforward translation would keep it local to the translated function by wrapping the entire defun in let.

First, let's look at something with similar structure. This code does something the first time, but not on subsequent calls:

(let ((firstp t))
  (defun frob (bar)
    (when firstp
      (print 'initialized)
      (setf firstp nil))
    (print (list 'frobbed bar)))
    nil)

Now, when we run this the first time, firstp is true, so we'll see initialized in the output, but on subsequent runs, we won't:

CL-USER> (frob 'bar3)
INITIALIZED            ; printed output
(FROBBED BAR3)         ; printed output
;=> NIL

CL-USER> (frob 'bar5)
(FROBBED BAR5)         ; printed output
;=> NIL

The C code that you've got is actually doing something on every call except the first. You could alternatively phrase this as, “unless it's the first time, do something.” The “unless” there is meant to be suggestive of unless, which you can you use to clean up your code a bit. Along with the let-wrapping-defun and proper indentation we have:

(let ((first t))
  (defun accumulate-background (i)
    (cvt-scale i i-scratch-1 1 0) ;; To float
    (unless first
      (acc i-scratch-1 i-avg-f)
      (abs-diff i-scratch-1 i-prev-f i-scratch-2)
      (acc i-scratch-2 i-diff-f)
      (setf i-count (+ i-count 1.0)))
    (setf first nil)
    (copy i-scratch-1 i-prev-f)))
Community
  • 1
  • 1
Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
  • No, the `(setf first nil)` cannot be moved into the `unless` block, because then the `unless` block will never be executed. Also, "it only needs to execute once" is not a good reason to move anything into the `unless` block, because that block is meant to be executed on every call except for one. – Rörd Sep 28 '13 at 23:19
  • @Rörd Yes, I did mess that up! I'd tried to keep too much from the first example that I gave. I've removed that last incorrect code block and paragraph. – Joshua Taylor Sep 29 '13 at 01:54
  • @Joshua Taylor thank you Joshua Taylor and everyone ......else for helping me with this.... should i include my working code if i got it figured out? –  Oct 01 '13 at 14:16
  • @user2735131 If you want to add it as an update to your question as a sort of appendix (but leave the original code in place, so that they question still makes sense), and you think it will help people in the future who find this question, I suppose you could. If it's quite similar to the code in this answer, it's probably not necessary, though. – Joshua Taylor Oct 01 '13 at 14:43
1

I don't know what's going on with your Lisp or even exactly what your question is but the original code is going to skip the the code in the ! first block the first time the function is called and will be executed every time the function is called thereafter.

What I think you are missing is static int first = 1; Because the variable first is static (i.e. not stored on the stack) it will retain it's value across calls of the function. Therefore first will be 0 (that is, not first) for all calls after the first one.

Duck
  • 26,924
  • 5
  • 64
  • 92
  • More information about `static` can be found in [What does “static” mean in a C program?](http://stackoverflow.com/q/572547/1281433) – Joshua Taylor Sep 28 '13 at 12:04
0

This is probably a matter of opinion, but I don't like the original approach of the C code. I would much prefer if a function's state depended on the arguments it received then on some globally modified state.

So, IMO, a good way to rewrite this function (no matter the language) would be something like this:

(defun accumulate-background (impl-image &key firstp) ...)

or, if possible:

(defun accumulate-background (impl-image)
  (labels ((%accumulate-background (firstp) ...))
    (%accumulate-background t)))

There is yet another way to avoid global variables like so:

(let (firstp)
  (defun accumulate-background (impl-image) ...))

Finally, if for some reason neither is rendered practical, the state can be persisted by using structs or classes, it would be too much to write a complete example here, but you can read about it here.

Lastly, some times you would indeed find that a package-level special variable is desired, though many would consider it preferable to wrap such code in a macro that hides the variable from the user, something like this:

(defparameter *firstp* t)
(defmacro with-first (&body body)
  `(let (*firstp*) ,@body))