BUG: switchfilter option broken - no motion detected at all
Many have reported that the switchfilter option disables the motion detection completely
Test case
Activate feature and try and detect motion
Environment
Motion version: |
3.2.3 |
ffmpeg version: |
N/A |
Shared libraries: |
ffmpeg, mysql, postgresql |
Server OS: |
N/A |
--
KennethLavrsen - 05 Oct 2005
Follow up
This is the code - what the heck is it supposed to do?
/*
* Comments added by Bill
* Note: Since there were absolutely no comments initially, the added comments
* really only show what I think is actually being done (which may not
* be what the author(s) really intended)
*
* Parameters:
* cnt pointer to motion context structure
* diffs number of pixels in new image which have changed
* newimg pointer to the latest image received
*/
int alg_switchfilter (struct context *cnt, int diffs, unsigned char *newimg)
{
int linediff = diffs / cnt->imgs.height; /* average # diffs per line */
unsigned char *out = cnt->imgs.out; /* points to a buffer containing non-
zero values wherever motion has occurred. */
int y, x, line;
/*
* 'lines' will be total number of lines in image with significant change ( > 2*average )
* 'vertlines' will be total number with > 5% non-black (i.e. 'moving') pixels
*/
int lines=0, vertlines=0;
/* Check each line in the motion image and count how many have moving (non-black) data */
for (y=0; y < cnt->imgs.height; y++) {
line=0; /* assume the line is all black */
for (x=0; x < cnt->imgs.width; x++) {
if (*(out++)) { /* if there is any moving pixel in this */
line++; /* line increment our working variable */
}
}
if (line > cnt->imgs.width/18) { /* if # moving pixels > ~5% */
vertlines++; /* increment # lines to consider */
}
if (line > linediff*2) { /* if the number of moving pixels in */
/* this line of the motion image is more than */
/* double the average 'per-line' difference in */
lines++; /* the new image, increment our cumulative count */
}
}
/*
* We have all the data, now we make a decision based upon that data.
*/
if (vertlines > cnt->imgs.height/10 && /* If more than 10% of the lines have some
/* moving pixels */
lines < vertlines/3 && /* and less than 1/3 of those lines have */
/* well-above-average interesting pixels */
(vertlines > cnt->imgs.height/4 || /* and either more than 25% of the lines each
/* contain > 5% moving pixels */
lines - vertlines > lines/2)) { /* or
(this one I'm really not clear on - mathematically
I think the expression can be simplified to become
vertlines < lines/2, which I guess would be
"if the total number of lines with > 5% moving pixels
is less than half of the number of lines with
well-above-average interesting pixels") */
/* overlay the counts as text onto the new image if requested */
if (cnt->conf.text_changes) {
char tmp[80];
sprintf(tmp, "%d %d", lines, vertlines);
draw_text(newimg, cnt->imgs.width-10, 20, cnt->imgs.width, tmp, cnt->conf.text_double);
}
return diffs; /* return with number of diffs */
}
return 0; /* if not enough lines meet our criteria, return 0 (i.e. no diffs detected ) */
}
I added it to have a place to disect it. Feel free to contribute.
Kenneth
I enhanced the comments. The symptom "disables completely" would imply that this routine always returns with a zero, i.e. the decision enclosed by the horrible 'if' is always "No".
--
BillBrack - 06 Oct 2005
I have been looking at the code before switchfilter to see if something dangerous is happening.
The following things happen that affects the switchfilter function. switchfilter is only run when Motion has been detected.
- alg_diff calls alg_diff_standard which creates the initial imgs.out.
- The imgs.out is in YUV420P format. The UV part is set so anything added in Y becomes gray.
- Each pixel in imgs.out is black (0) where no image is detected and the corresponding pixel in imgs.image_virgin (called new inside alg_diff_standard - I will change that for readability). So we now have a picture where anything that moved is shown in b/w on a black background. It also means that any pixel where something moved is non-zero and rest are 0.
- We now run the alg_despeckle function
- Runs mix of erode9, erode5, dilate9, dilate5 which removes and adds pixels round the detected motion pixels in imgs.out. When something is added it is the adjacent pixel value which is copied.
- Runs labelling which does not affect imgs.out yet (the largest label overlay shown in blue is added to img.out after any detection features - this was not the case until recently though).
- Runs lightswitch which does not alter imgs.out
- Runs switchfilter.
So it must be the switchfilter that causes the trouble. But it can be because the algoritm is not really made to be run AFTER despeckle including labelling.
--
KennethLavrsen - 06 Oct 2005
I think you are correct, in that the actual trouble comes only when the despeckle feature (which changes imgs.out) is performed before the switchfilter function. Could we possibly re-arrange the motion-loop logic to do the switchfilter first? Note that switchfilter doesn't actually change any data, it only analyses the motion differences and returns either precisely the number of differences which were present on entry, or else 0 (i.e. no differences to look at).
--
BillBrack - 06 Oct 2005
I think that both lightswitch and switchfilter suffers under the despeckle feature. Both features were designed to look at a raw motion image with no filtering to remove noise pixels. This probably also means that areas with scattered pixels of Motion gets cleaned out. And this kind of pixels is what the lightswitch and switchfilter features were designed to detect as false Motion.
So I moved BOTH algos up before the alg_despeckle call. This change will be in the 06 Oct 2005 daily snap.
--
KennethLavrsen - 06 Oct 2005
Fix record
The above fix should work. At least in my setup it no longer prevents general Motion detection.
The fix is in
MotionRelease3x2x4snap3
--
KennethLavrsen - 08 Oct 2005
Released in 3.2.4
--
KennethLavrsen - 18 Dec 2005