2003-03-26 20:03:37 +08:00
//
// ZoneMinder Zone Class Implementation, $Date$, $Revision$
2008-07-25 17:33:23 +08:00
// Copyright (C) 2001-2008 Philip Coombes
2003-03-26 20:03:37 +08:00
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
2016-12-26 23:23:16 +08:00
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
2003-03-26 20:03:37 +08:00
//
2018-06-15 00:24:58 +08:00
# define __STDC_FORMAT_MACROS 1
# include <cinttypes>
2003-03-26 20:03:37 +08:00
# include "zm.h"
# include "zm_db.h"
# include "zm_zone.h"
# include "zm_image.h"
# include "zm_monitor.h"
2019-05-17 03:37:03 +08:00
# include "zm_fifo.h"
2003-03-26 20:03:37 +08:00
2018-06-15 00:24:58 +08:00
2017-05-20 21:41:13 +08:00
void Zone : : Setup (
Monitor * p_monitor ,
int p_id ,
const char * p_label ,
ZoneType p_type ,
const Polygon & p_polygon ,
const Rgb p_alarm_rgb ,
CheckMethod p_check_method ,
int p_min_pixel_threshold ,
int p_max_pixel_threshold ,
int p_min_alarm_pixels ,
int p_max_alarm_pixels ,
const Coord & p_filter_box ,
int p_min_filter_pixels ,
int p_max_filter_pixels ,
int p_min_blob_pixels ,
int p_max_blob_pixels ,
int p_min_blobs ,
int p_max_blobs ,
int p_overload_frames ,
int p_extend_alarm_frames
) {
2016-04-04 22:11:48 +08:00
monitor = p_monitor ;
id = p_id ;
label = new char [ strlen ( p_label ) + 1 ] ;
2020-04-27 06:19:30 +08:00
strcpy ( label , p_label ) ;
2016-04-04 22:11:48 +08:00
type = p_type ;
polygon = p_polygon ;
alarm_rgb = p_alarm_rgb ;
check_method = p_check_method ;
min_pixel_threshold = p_min_pixel_threshold ;
max_pixel_threshold = p_max_pixel_threshold ;
min_alarm_pixels = p_min_alarm_pixels ;
max_alarm_pixels = p_max_alarm_pixels ;
filter_box = p_filter_box ;
min_filter_pixels = p_min_filter_pixels ;
max_filter_pixels = p_max_filter_pixels ;
min_blob_pixels = p_min_blob_pixels ;
max_blob_pixels = p_max_blob_pixels ;
min_blobs = p_min_blobs ;
max_blobs = p_max_blobs ;
overload_frames = p_overload_frames ;
2016-09-09 22:07:13 +08:00
extend_alarm_frames = p_extend_alarm_frames ;
2003-03-26 20:03:37 +08:00
2017-08-01 03:49:27 +08:00
//Debug( 1, "Initialised zone %d/%s - %d - %dx%d - Rgb:%06x, CM:%d, MnAT:%d, MxAT:%d, MnAP:%d, MxAP:%d, FB:%dx%d, MnFP:%d, MxFP:%d, MnBS:%d, MxBS:%d, MnB:%d, MxB:%d, OF: %d, AF: %d", id, label, type, polygon.Width(), polygon.Height(), alarm_rgb, check_method, min_pixel_threshold, max_pixel_threshold, min_alarm_pixels, max_alarm_pixels, filter_box.X(), filter_box.Y(), min_filter_pixels, max_filter_pixels, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs, overload_frames, extend_alarm_frames );
2016-04-04 22:11:48 +08:00
alarmed = false ;
2019-06-24 22:28:11 +08:00
was_alarmed = false ;
2016-04-04 22:11:48 +08:00
pixel_diff = 0 ;
alarm_pixels = 0 ;
alarm_filter_pixels = 0 ;
alarm_blob_pixels = 0 ;
alarm_blobs = 0 ;
min_blob_size = 0 ;
max_blob_size = 0 ;
image = 0 ;
score = 0 ;
overload_count = 0 ;
extend_alarm_count = 0 ;
2020-04-27 06:19:30 +08:00
pg_image = new Image ( monitor - > Width ( ) , monitor - > Height ( ) , 1 , ZM_SUBPIX_ORDER_NONE ) ;
2016-04-04 22:11:48 +08:00
pg_image - > Clear ( ) ;
2020-04-27 06:19:30 +08:00
pg_image - > Fill ( 0xff , polygon ) ;
pg_image - > Outline ( 0xff , polygon ) ;
2016-04-04 22:11:48 +08:00
ranges = new Range [ monitor - > Height ( ) ] ;
2017-05-20 21:41:13 +08:00
for ( unsigned int y = 0 ; y < monitor - > Height ( ) ; y + + ) {
2016-04-04 22:11:48 +08:00
ranges [ y ] . lo_x = - 1 ;
ranges [ y ] . hi_x = 0 ;
ranges [ y ] . off_x = 0 ;
const uint8_t * ppoly = pg_image - > Buffer ( 0 , y ) ;
2017-05-20 21:41:13 +08:00
for ( unsigned int x = 0 ; x < monitor - > Width ( ) ; x + + , ppoly + + ) {
if ( * ppoly ) {
if ( ranges [ y ] . lo_x = = - 1 ) {
2016-04-04 22:11:48 +08:00
ranges [ y ] . lo_x = x ;
}
2017-05-20 21:41:13 +08:00
if ( ( unsigned int ) ranges [ y ] . hi_x < x ) {
2016-04-04 22:11:48 +08:00
ranges [ y ] . hi_x = x ;
}
}
}
}
2017-05-20 21:41:13 +08:00
if ( config . record_diag_images ) {
2020-04-27 06:19:30 +08:00
snprintf ( diag_path , sizeof ( diag_path ) ,
config . record_diag_images_fifo ? " %s/diagpipe-%d-poly.jpg " : " %s/diag-%d-poly.jpg " ,
monitor - > getStorage ( ) - > Path ( ) , id ) ;
if ( config . record_diag_images_fifo )
2019-06-24 22:28:11 +08:00
FifoStream : : fifo_create_if_missing ( diag_path ) ;
2019-05-17 03:37:03 +08:00
pg_image - > WriteJpeg ( diag_path , config . record_diag_images_fifo ) ;
2018-04-24 02:36:46 +08:00
} else {
2019-06-24 22:28:11 +08:00
diag_path [ 0 ] = 0 ;
}
2020-07-23 05:30:39 +08:00
} // end Zone::Setup
2003-03-26 20:03:37 +08:00
2017-05-24 03:07:50 +08:00
Zone : : ~ Zone ( ) {
2016-04-04 22:11:48 +08:00
delete [ ] label ;
delete image ;
delete pg_image ;
delete [ ] ranges ;
2003-03-26 20:03:37 +08:00
}
2020-07-23 05:30:39 +08:00
void Zone : : RecordStats ( const Event * event ) {
2017-05-24 03:07:50 +08:00
static char sql [ ZM_SQL_MED_BUFSIZ ] ;
2018-03-28 21:12:38 +08:00
db_mutex . lock ( ) ;
2019-06-24 22:28:11 +08:00
snprintf ( sql , sizeof ( sql ) ,
" INSERT INTO Stats SET MonitorId=%d, ZoneId=%d, EventId=% " PRIu64 " , FrameId=%d, PixelDiff=%d, AlarmPixels=%d, FilterPixels=%d, BlobPixels=%d, Blobs=%d, MinBlobSize=%d, MaxBlobSize=%d, MinX=%d, MinY=%d, MaxX=%d, MaxY=%d, Score=%d " ,
monitor - > Id ( ) , id , event - > Id ( ) , event - > Frames ( ) + 1 , pixel_diff , alarm_pixels , alarm_filter_pixels , alarm_blob_pixels , alarm_blobs , min_blob_size , max_blob_size , alarm_box . LoX ( ) , alarm_box . LoY ( ) , alarm_box . HiX ( ) , alarm_box . HiY ( ) , score
) ;
if ( mysql_query ( & dbconn , sql ) ) {
Error ( " Can't insert event stats: %s " , mysql_error ( & dbconn ) ) ;
}
2018-03-28 21:12:38 +08:00
db_mutex . unlock ( ) ;
2020-07-23 05:30:39 +08:00
} // end void Zone::RecordStats( const Event *event )
2013-03-17 07:45:21 +08:00
2017-05-24 03:07:50 +08:00
bool Zone : : CheckOverloadCount ( ) {
if ( overload_count ) {
2018-04-24 02:36:46 +08:00
Debug ( 4 , " In overload mode, %d frames of %d remaining " , overload_count , overload_frames ) ;
2017-05-24 03:07:50 +08:00
overload_count - - ;
2018-04-24 02:36:46 +08:00
return false ;
2017-05-24 03:07:50 +08:00
}
return true ;
2020-07-23 05:30:39 +08:00
} // end bool Zone::CheckOverloadCount()
2013-03-17 07:45:21 +08:00
2017-05-24 03:07:50 +08:00
void Zone : : SetScore ( unsigned int nScore ) {
score = nScore ;
2020-07-23 05:30:39 +08:00
} // end void Zone::SetScore(unsigned int nScore)
2013-03-17 07:45:21 +08:00
2017-05-24 03:07:50 +08:00
void Zone : : SetAlarmImage ( const Image * srcImage ) {
delete image ;
image = new Image ( * srcImage ) ;
2020-07-23 05:30:39 +08:00
} // end void Zone::SetAlarmImage( const Image* srcImage )
2013-03-17 07:45:21 +08:00
2017-05-24 03:07:50 +08:00
int Zone : : GetOverloadCount ( ) {
return overload_count ;
2020-07-23 05:30:39 +08:00
} // end int Zone::GetOverloadCount()
2013-03-17 07:45:21 +08:00
2017-05-24 03:07:50 +08:00
void Zone : : SetOverloadCount ( int nOverCount ) {
overload_count = nOverCount ;
2020-07-23 05:30:39 +08:00
} // end void Zone::SetOverloadCount(int nOverCount )
2013-03-17 07:45:21 +08:00
2017-05-24 03:07:50 +08:00
int Zone : : GetOverloadFrames ( ) {
return overload_frames ;
2020-07-23 05:30:39 +08:00
} // end int Zone::GetOverloadFrames
2014-03-10 00:05:39 +08:00
2017-05-24 03:07:50 +08:00
int Zone : : GetExtendAlarmCount ( ) {
return extend_alarm_count ;
2020-07-23 05:30:39 +08:00
} // end int Zone::GetExtendAlarmCount()
2014-03-10 00:05:39 +08:00
2017-05-24 03:07:50 +08:00
void Zone : : SetExtendAlarmCount ( int nExtendAlarmCount ) {
extend_alarm_count = nExtendAlarmCount ;
2020-07-23 05:30:39 +08:00
} // end void Zone::SetExtendAlarmCount( int nExtendAlarmCount )
2014-03-10 00:05:39 +08:00
2017-05-24 03:07:50 +08:00
int Zone : : GetExtendAlarmFrames ( ) {
return extend_alarm_frames ;
2020-07-23 05:30:39 +08:00
} // end int Zone::GetExtendAlarmFrames()
2014-03-10 00:05:39 +08:00
2017-05-24 03:07:50 +08:00
bool Zone : : CheckExtendAlarmCount ( ) {
2018-04-24 02:36:46 +08:00
Info ( " ExtendAlarm count: %d, ExtendAlarm frames: %d " , extend_alarm_count , extend_alarm_frames ) ;
2017-05-24 03:07:50 +08:00
if ( extend_alarm_count ) {
2018-04-24 02:36:46 +08:00
Debug ( 3 , " In extend mode, %d frames of %d remaining " , extend_alarm_count , extend_alarm_frames ) ;
2017-05-24 03:07:50 +08:00
extend_alarm_count - - ;
2018-04-24 02:36:46 +08:00
return true ;
2017-05-24 03:07:50 +08:00
}
return false ;
2020-07-23 05:30:39 +08:00
} // end bool Zone::CheckExtendAlarmCount
2014-03-10 00:05:39 +08:00
2018-04-24 02:36:46 +08:00
bool Zone : : CheckAlarms ( const Image * delta_image ) {
2016-04-04 22:11:48 +08:00
ResetStats ( ) ;
2003-03-26 20:03:37 +08:00
2017-05-20 21:41:13 +08:00
if ( overload_count ) {
2018-04-24 02:36:46 +08:00
Info ( " In overload mode, %d frames of %d remaining " , overload_count , overload_frames ) ;
2016-04-04 22:11:48 +08:00
overload_count - - ;
2018-04-24 02:36:46 +08:00
return false ;
2016-04-04 22:11:48 +08:00
}
2007-06-05 22:12:14 +08:00
2016-04-04 22:11:48 +08:00
delete image ;
// Get the difference image
2018-04-24 02:36:46 +08:00
Image * diff_image = image = new Image ( * delta_image ) ;
2016-04-04 22:11:48 +08:00
int diff_width = diff_image - > Width ( ) ;
uint8_t * diff_buff = ( uint8_t * ) diff_image - > Buffer ( ) ;
uint8_t * pdiff ;
unsigned int pixel_diff_count = 0 ;
int alarm_lo_x = 0 ;
int alarm_hi_x = 0 ;
int alarm_lo_y = 0 ;
int alarm_hi_y = 0 ;
int alarm_mid_x = - 1 ;
int alarm_mid_y = - 1 ;
2017-05-20 21:41:13 +08:00
2016-04-04 22:11:48 +08:00
unsigned int lo_y = polygon . LoY ( ) ;
unsigned int lo_x = polygon . LoX ( ) ;
unsigned int hi_x = polygon . HiX ( ) ;
unsigned int hi_y = polygon . HiY ( ) ;
2018-04-24 02:36:46 +08:00
Debug ( 4 , " Checking alarms for zone %d/%s in lines %d -> %d " , id , label , lo_y , hi_y ) ;
2017-05-20 21:41:13 +08:00
2020-07-20 05:50:47 +08:00
/* if(config.cpu_extensions && sse_version >= 20) {
2017-05-20 21:41:13 +08:00
sse2_alarmedpixels ( diff_image , pg_image , & alarm_pixels , & pixel_diff_count ) ;
} else {
std_alarmedpixels ( diff_image , pg_image , & alarm_pixels , & pixel_diff_count ) ;
} */
2016-04-04 22:11:48 +08:00
std_alarmedpixels ( diff_image , pg_image , & alarm_pixels , & pixel_diff_count ) ;
2017-05-20 21:41:13 +08:00
2018-04-24 02:36:46 +08:00
if ( config . record_diag_images )
2019-05-17 03:37:03 +08:00
diff_image - > WriteJpeg ( diag_path , config . record_diag_images_fifo ) ;
2003-03-26 20:03:37 +08:00
2016-04-04 22:11:48 +08:00
if ( pixel_diff_count & & alarm_pixels )
pixel_diff = pixel_diff_count / alarm_pixels ;
2018-08-22 23:14:00 +08:00
Debug ( 5 , " Got %d alarmed pixels, need %d -> %d, avg pixel diff %d " ,
alarm_pixels , min_alarm_pixels , max_alarm_pixels , pixel_diff ) ;
2016-04-04 22:11:48 +08:00
2019-06-24 22:28:11 +08:00
if ( config . record_diag_images_fifo ) {
FifoDebug ( 5 , " { \" zone \" :%d, \" type \" : \" ALRM \" , \" pixels \" :%d, \" avg_diff \" :%d} " ,
id , alarm_pixels , pixel_diff ) ;
}
2019-05-17 03:37:03 +08:00
2018-04-24 02:36:46 +08:00
if ( alarm_pixels ) {
if ( min_alarm_pixels & & ( alarm_pixels < ( unsigned int ) min_alarm_pixels ) ) {
2016-04-04 22:11:48 +08:00
/* Not enough pixels alarmed */
2018-04-24 02:36:46 +08:00
return false ;
} else if ( max_alarm_pixels & & ( alarm_pixels > ( unsigned int ) max_alarm_pixels ) ) {
2016-04-04 22:11:48 +08:00
/* Too many pixels alarmed */
overload_count = overload_frames ;
2018-04-24 02:36:46 +08:00
return false ;
2016-04-04 22:11:48 +08:00
}
} else {
/* No alarmed pixels */
2018-04-24 02:36:46 +08:00
return false ;
2016-04-04 22:11:48 +08:00
}
2003-03-26 20:03:37 +08:00
2019-06-24 22:28:11 +08:00
if ( max_alarm_pixels ! = 0 )
2018-08-23 00:58:26 +08:00
score = ( 100 * alarm_pixels ) / max_alarm_pixels ;
else
score = ( 100 * alarm_pixels ) / polygon . Area ( ) ;
2017-05-20 21:41:13 +08:00
if ( score < 1 )
2016-04-04 22:11:48 +08:00
score = 1 ; /* Fix for score of 0 when frame meets thresholds but alarmed area is not big enough */
2018-04-24 02:36:46 +08:00
Debug ( 5 , " Current score is %d " , score ) ;
2017-05-20 21:41:13 +08:00
if ( check_method > = FILTERED_PIXELS ) {
2016-04-04 22:11:48 +08:00
int bx = filter_box . X ( ) ;
int by = filter_box . Y ( ) ;
int bx1 = bx - 1 ;
int by1 = by - 1 ;
2018-04-24 02:36:46 +08:00
Debug ( 5 , " Checking for filtered pixels " ) ;
2017-05-20 21:41:13 +08:00
if ( bx > 1 | | by > 1 ) {
2016-04-04 22:11:48 +08:00
// Now remove any pixels smaller than our filter size
unsigned char * cpdiff ;
int ldx , hdx , ldy , hdy ;
bool block ;
2017-05-20 21:41:13 +08:00
for ( unsigned int y = lo_y ; y < = hi_y ; y + + ) {
2016-04-04 22:11:48 +08:00
int lo_x = ranges [ y ] . lo_x ;
int hi_x = ranges [ y ] . hi_x ;
2019-06-24 22:28:11 +08:00
pdiff = ( uint8_t * ) diff_image - > Buffer ( lo_x , y ) ;
2016-04-04 22:11:48 +08:00
2017-05-20 21:41:13 +08:00
for ( int x = lo_x ; x < = hi_x ; x + + , pdiff + + ) {
if ( * pdiff = = WHITE ) {
2016-04-04 22:11:48 +08:00
// Check participation in an X block
ldx = ( x > = ( lo_x + bx1 ) ) ? - bx1 : lo_x - x ;
hdx = ( x < = ( hi_x - bx1 ) ) ? 0 : ( ( hi_x - x ) - bx1 ) ;
ldy = ( y > = ( lo_y + by1 ) ) ? - by1 : lo_y - y ;
hdy = ( y < = ( hi_y - by1 ) ) ? 0 : ( ( hi_y - y ) - by1 ) ;
block = false ;
2017-05-20 21:41:13 +08:00
for ( int dy = ldy ; ! block & & dy < = hdy ; dy + + ) {
for ( int dx = ldx ; ! block & & dx < = hdx ; dx + + ) {
2016-04-04 22:11:48 +08:00
block = true ;
2017-05-20 21:41:13 +08:00
for ( int dy2 = 0 ; block & & dy2 < by ; dy2 + + ) {
for ( int dx2 = 0 ; block & & dx2 < bx ; dx2 + + ) {
2016-04-04 22:11:48 +08:00
cpdiff = diff_buff + ( ( ( y + dy + dy2 ) * diff_width ) + ( x + dx + dx2 ) ) ;
2017-05-20 21:41:13 +08:00
if ( ! * cpdiff ) {
2016-04-04 22:11:48 +08:00
block = false ;
}
}
}
}
}
2017-05-20 21:41:13 +08:00
if ( ! block ) {
2016-04-04 22:11:48 +08:00
* pdiff = BLACK ;
continue ;
}
alarm_filter_pixels + + ;
2018-04-24 02:36:46 +08:00
} // end if white
} // end for x
} // end foreach y line
2017-05-20 21:41:13 +08:00
} else {
2016-04-04 22:11:48 +08:00
alarm_filter_pixels = alarm_pixels ;
}
2005-12-02 00:34:20 +08:00
2018-04-24 02:36:46 +08:00
if ( config . record_diag_images )
2019-05-17 03:37:03 +08:00
diff_image - > WriteJpeg ( diag_path , config . record_diag_images_fifo ) ;
2004-02-16 04:02:41 +08:00
2018-08-22 23:14:00 +08:00
Debug ( 5 , " Got %d filtered pixels, need %d -> %d " ,
alarm_filter_pixels , min_filter_pixels , max_filter_pixels ) ;
2017-05-20 21:41:13 +08:00
2019-06-24 22:28:11 +08:00
if ( config . record_diag_images_fifo )
FifoDebug ( 5 , " { \" zone \" :%d, \" type \" : \" FILT \" , \" pixels \" :%d} " , id , alarm_filter_pixels ) ;
2019-05-17 03:37:03 +08:00
2018-04-24 02:36:46 +08:00
if ( alarm_filter_pixels ) {
if ( min_filter_pixels & & ( alarm_filter_pixels < min_filter_pixels ) ) {
2016-04-04 22:11:48 +08:00
/* Not enough pixels alarmed */
2018-04-24 02:36:46 +08:00
return false ;
} else if ( max_filter_pixels & & ( alarm_filter_pixels > max_filter_pixels ) ) {
2016-04-04 22:11:48 +08:00
/* Too many pixels alarmed */
overload_count = overload_frames ;
2018-04-24 02:36:46 +08:00
return false ;
2016-04-04 22:11:48 +08:00
}
} else {
/* No filtered pixels */
2018-04-24 02:36:46 +08:00
return false ;
2016-04-04 22:11:48 +08:00
}
2005-02-24 18:43:29 +08:00
2019-06-24 22:28:11 +08:00
if ( max_filter_pixels ! = 0 )
2018-08-23 04:34:29 +08:00
score = ( 100 * alarm_filter_pixels ) / max_filter_pixels ;
2018-08-23 00:58:26 +08:00
else
score = ( 100 * alarm_filter_pixels ) / polygon . Area ( ) ;
2017-05-20 21:41:13 +08:00
if ( score < 1 )
2016-04-04 22:11:48 +08:00
score = 1 ; /* Fix for score of 0 when frame meets thresholds but alarmed area is not big enough */
2018-04-24 02:36:46 +08:00
Debug ( 5 , " Current score is %d " , score ) ;
2016-04-04 22:11:48 +08:00
2017-05-20 21:41:13 +08:00
if ( check_method > = BLOBS ) {
2018-04-24 02:36:46 +08:00
Debug ( 5 , " Checking for blob pixels " ) ;
2016-04-04 22:11:48 +08:00
typedef struct { unsigned char tag ; int count ; int lo_x ; int hi_x ; int lo_y ; int hi_y ; } BlobStats ;
BlobStats blob_stats [ 256 ] ;
2018-04-24 02:36:46 +08:00
memset ( blob_stats , 0 , sizeof ( BlobStats ) * 256 ) ;
2016-04-04 22:11:48 +08:00
uint8_t * spdiff ;
uint8_t last_x , last_y ;
BlobStats * bsx , * bsy ;
BlobStats * bsm , * bss ;
2017-05-20 21:41:13 +08:00
for ( unsigned int y = lo_y ; y < = hi_y ; y + + ) {
2016-04-04 22:11:48 +08:00
int lo_x = ranges [ y ] . lo_x ;
int hi_x = ranges [ y ] . hi_x ;
pdiff = ( uint8_t * ) diff_image - > Buffer ( lo_x , y ) ;
2017-05-20 21:41:13 +08:00
for ( int x = lo_x ; x < = hi_x ; x + + , pdiff + + ) {
if ( * pdiff = = WHITE ) {
2018-04-24 02:36:46 +08:00
Debug ( 9 , " Got white pixel at %d,%d (%p) " , x , y , pdiff ) ;
2016-04-04 22:11:48 +08:00
//last_x = (x>lo_x)?*(pdiff-1):0;
//last_y = (y>lo_y&&x>=last_lo_x&&x<=last_hi_x)?*(pdiff-diff_width):0;
2017-05-20 21:41:13 +08:00
2016-04-04 22:11:48 +08:00
last_x = 0 ;
2018-04-24 02:36:46 +08:00
if ( x > 0 ) {
if ( ( x - 1 ) > = lo_x ) {
2016-04-04 22:11:48 +08:00
last_x = * ( pdiff - 1 ) ;
}
}
2017-05-20 21:41:13 +08:00
2016-04-04 22:11:48 +08:00
last_y = 0 ;
2018-04-24 02:36:46 +08:00
if ( y > 0 ) {
if ( ( y - 1 ) > = lo_y & & ranges [ ( y - 1 ) ] . lo_x < = x & & ranges [ ( y - 1 ) ] . hi_x > = x ) {
2016-04-04 22:11:48 +08:00
last_y = * ( pdiff - diff_width ) ;
}
}
2017-05-20 21:41:13 +08:00
if ( last_x ) {
2018-04-24 02:36:46 +08:00
Debug ( 9 , " Left neighbour is %d " , last_x ) ;
2016-04-04 22:11:48 +08:00
bsx = & blob_stats [ last_x ] ;
2017-05-20 21:41:13 +08:00
if ( last_y ) {
2018-04-24 02:36:46 +08:00
Debug ( 9 , " Top neighbour is %d " , last_y ) ;
2016-04-04 22:11:48 +08:00
bsy = & blob_stats [ last_y ] ;
2017-05-20 21:41:13 +08:00
if ( last_x = = last_y ) {
2018-04-24 02:36:46 +08:00
Debug ( 9 , " Matching neighbours, setting to %d " , last_x ) ;
2016-04-04 22:11:48 +08:00
// Add to the blob from the x side (either side really)
* pdiff = last_x ;
alarm_blob_pixels + + ;
bsx - > count + + ;
if ( x > bsx - > hi_x ) bsx - > hi_x = x ;
if ( ( int ) y > bsx - > hi_y ) bsx - > hi_y = y ;
2017-05-20 21:41:13 +08:00
} else {
2016-04-04 22:11:48 +08:00
// Aggregate blobs
bsm = bsx - > count > = bsy - > count ? bsx : bsy ;
bss = bsm = = bsx ? bsy : bsx ;
2018-04-24 02:36:46 +08:00
Debug ( 9 ,
2019-06-24 22:28:11 +08:00
" Different neighbours, setting pixels of %d to %d \n "
" Master blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d \n "
" Slave blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d \n " ,
bss - > tag , bsm - > tag ,
bsm - > tag , bsm - > count , bsm - > lo_x , bsm - > hi_x , bsm - > lo_y , bsm - > hi_y ,
bss - > tag , bss - > count , bss - > lo_x , bss - > hi_x , bss - > lo_y , bss - > hi_y
) ;
2016-04-04 22:11:48 +08:00
// Now change all those pixels to the other setting
int changed = 0 ;
2018-04-24 02:36:46 +08:00
for ( int sy = bss - > lo_y ; sy < = bss - > hi_y ; sy + + ) {
2016-04-04 22:11:48 +08:00
int lo_sx = bss - > lo_x > = ranges [ sy ] . lo_x ? bss - > lo_x : ranges [ sy ] . lo_x ;
int hi_sx = bss - > hi_x < = ranges [ sy ] . hi_x ? bss - > hi_x : ranges [ sy ] . hi_x ;
2018-04-24 02:36:46 +08:00
Debug ( 9 ,
2019-06-24 22:28:11 +08:00
" Changing %d, %d->%d Range %d->%d " ,
sy , lo_sx , hi_sx , ranges [ sy ] . lo_x , ranges [ sy ] . hi_x
) ;
2016-04-04 22:11:48 +08:00
spdiff = diff_buff + ( ( diff_width * sy ) + lo_sx ) ;
2017-05-20 21:41:13 +08:00
for ( int sx = lo_sx ; sx < = hi_sx ; sx + + , spdiff + + ) {
2018-04-24 02:36:46 +08:00
Debug ( 9 , " Pixel at %d,%d (%p) is %d " , sx , sy , spdiff , * spdiff ) ;
2017-05-20 21:41:13 +08:00
if ( * spdiff = = bss - > tag ) {
2018-04-24 02:36:46 +08:00
Debug ( 9 , " Setting pixel " ) ;
2016-04-04 22:11:48 +08:00
* spdiff = bsm - > tag ;
changed + + ;
}
}
}
* pdiff = bsm - > tag ;
alarm_blob_pixels + + ;
2017-05-20 21:41:13 +08:00
if ( ! changed ) {
2018-04-24 02:36:46 +08:00
Info (
2019-06-24 22:28:11 +08:00
" Master blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d \n "
" Slave blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d " ,
bsm - > tag , bsm - > count , bsm - > lo_x , bsm - > hi_x , bsm - > lo_y , bsm - > hi_y ,
bss - > tag , bss - > count , bss - > lo_x , bss - > hi_x , bss - > lo_y , bss - > hi_y
) ;
2018-04-24 02:36:46 +08:00
Error ( " No pixels changed, exiting " ) ;
exit ( - 1 ) ;
2016-04-04 22:11:48 +08:00
}
// Merge the slave blob into the master
bsm - > count + = bss - > count + 1 ;
if ( x > bsm - > hi_x ) bsm - > hi_x = x ;
if ( ( int ) y > bsm - > hi_y ) bsm - > hi_y = y ;
if ( bss - > lo_x < bsm - > lo_x ) bsm - > lo_x = bss - > lo_x ;
if ( bss - > lo_y < bsm - > lo_y ) bsm - > lo_y = bss - > lo_y ;
if ( bss - > hi_x > bsm - > hi_x ) bsm - > hi_x = bss - > hi_x ;
if ( bss - > hi_y > bsm - > hi_y ) bsm - > hi_y = bss - > hi_y ;
alarm_blobs - - ;
2018-08-22 23:14:00 +08:00
Debug ( 6 , " Merging blob %d with %d at %d,%d, %d current blobs " ,
bss - > tag , bsm - > tag , x , y , alarm_blobs ) ;
2016-04-04 22:11:48 +08:00
// Clear out the old blob
bss - > tag = 0 ;
bss - > count = 0 ;
bss - > lo_x = 0 ;
bss - > lo_y = 0 ;
bss - > hi_x = 0 ;
bss - > hi_y = 0 ;
}
2017-05-20 21:41:13 +08:00
} else {
2018-04-24 02:36:46 +08:00
Debug ( 9 , " Setting to left neighbour %d " , last_x ) ;
2016-04-04 22:11:48 +08:00
// Add to the blob from the x side
* pdiff = last_x ;
alarm_blob_pixels + + ;
bsx - > count + + ;
if ( x > bsx - > hi_x ) bsx - > hi_x = x ;
if ( ( int ) y > bsx - > hi_y ) bsx - > hi_y = y ;
}
2017-05-20 21:41:13 +08:00
} else {
if ( last_y ) {
2018-04-24 02:36:46 +08:00
Debug ( 9 , " Top neighbour is %d " , last_y ) ;
2017-05-20 21:41:13 +08:00
2016-04-04 22:11:48 +08:00
// Add to the blob from the y side
BlobStats * bsy = & blob_stats [ last_y ] ;
* pdiff = last_y ;
alarm_blob_pixels + + ;
bsy - > count + + ;
if ( x > bsy - > hi_x ) bsy - > hi_x = x ;
if ( ( int ) y > bsy - > hi_y ) bsy - > hi_y = y ;
2017-05-20 21:41:13 +08:00
} else {
2016-04-04 22:11:48 +08:00
// Create a new blob
int i ;
2017-05-20 21:41:13 +08:00
for ( i = ( WHITE - 1 ) ; i > 0 ; i - - ) {
2016-04-04 22:11:48 +08:00
BlobStats * bs = & blob_stats [ i ] ;
// See if we can recycle one first, only if it's at least two rows up
2017-05-20 21:41:13 +08:00
if ( bs - > count & & bs - > hi_y < ( int ) ( y - 1 ) ) {
2018-08-22 23:14:00 +08:00
if (
( min_blob_pixels & & bs - > count < min_blob_pixels )
| |
( max_blob_pixels & & bs - > count > max_blob_pixels )
) {
2020-07-07 01:22:41 +08:00
if ( ( monitor - > GetOptSaveJPEGs ( ) > 1 ) | | config . record_diag_images ) {
2017-05-20 21:41:13 +08:00
for ( int sy = bs - > lo_y ; sy < = bs - > hi_y ; sy + + ) {
2016-04-04 22:11:48 +08:00
spdiff = diff_buff + ( ( diff_width * sy ) + bs - > lo_x ) ;
2017-05-20 21:41:13 +08:00
for ( int sx = bs - > lo_x ; sx < = bs - > hi_x ; sx + + , spdiff + + ) {
if ( * spdiff = = bs - > tag ) {
2016-04-04 22:11:48 +08:00
* spdiff = BLACK ;
}
}
}
}
alarm_blobs - - ;
alarm_blob_pixels - = bs - > count ;
2017-05-20 21:41:13 +08:00
2018-04-24 02:36:46 +08:00
Debug ( 6 , " Eliminated blob %d, %d pixels (%d,%d - %d,%d), %d current blobs " ,
2019-06-24 22:28:11 +08:00
i , bs - > count , bs - > lo_x , bs - > lo_y , bs - > hi_x , bs - > hi_y , alarm_blobs ) ;
2016-04-04 22:11:48 +08:00
bs - > tag = 0 ;
bs - > count = 0 ;
bs - > lo_x = 0 ;
bs - > lo_y = 0 ;
bs - > hi_x = 0 ;
bs - > hi_y = 0 ;
}
}
2017-05-20 21:41:13 +08:00
if ( ! bs - > count ) {
2018-04-24 02:36:46 +08:00
Debug ( 9 , " Creating new blob %d " , i ) ;
2016-04-04 22:11:48 +08:00
* pdiff = i ;
alarm_blob_pixels + + ;
bs - > tag = i ;
bs - > count + + ;
bs - > lo_x = bs - > hi_x = x ;
bs - > lo_y = bs - > hi_y = y ;
alarm_blobs + + ;
2018-04-24 02:36:46 +08:00
Debug ( 6 , " Created blob %d at %d,%d, %d current blobs " , bs - > tag , x , y , alarm_blobs ) ;
2016-04-04 22:11:48 +08:00
break ;
}
}
2017-05-20 21:41:13 +08:00
if ( i = = 0 ) {
2018-04-24 02:36:46 +08:00
Warning ( " Max blob count reached. Unable to allocate new blobs so terminating. Zone settings may be too sensitive. " ) ;
2016-04-04 22:11:48 +08:00
x = hi_x + 1 ;
y = hi_y + 1 ;
}
}
}
}
}
}
2019-06-24 22:28:11 +08:00
2018-04-24 02:36:46 +08:00
if ( config . record_diag_images )
2019-05-17 03:37:03 +08:00
diff_image - > WriteJpeg ( diag_path , config . record_diag_images_fifo ) ;
2016-04-04 22:11:48 +08:00
2017-05-20 21:41:13 +08:00
if ( ! alarm_blobs ) {
2018-04-24 02:36:46 +08:00
return false ;
2016-04-04 22:11:48 +08:00
}
2017-05-20 21:41:13 +08:00
2018-04-24 02:36:46 +08:00
Debug ( 5 , " Got %d raw blob pixels, %d raw blobs, need %d -> %d, %d -> %d " ,
2019-06-24 22:28:11 +08:00
alarm_blob_pixels , alarm_blobs , min_blob_pixels , max_blob_pixels , min_blobs , max_blobs ) ;
2016-04-04 22:11:48 +08:00
2019-06-24 22:28:11 +08:00
if ( config . record_diag_images_fifo ) {
FifoDebug ( 5 , " { \" zone \" :%d, \" type \" : \" RBLB \" , \" pixels \" :%d, \" blobs \" :%d} " ,
id , alarm_blob_pixels , alarm_blobs ) ;
}
2019-05-17 03:37:03 +08:00
2016-04-04 22:11:48 +08:00
// Now eliminate blobs under the threshold
2017-05-20 21:41:13 +08:00
for ( int i = 1 ; i < WHITE ; i + + ) {
2016-04-04 22:11:48 +08:00
BlobStats * bs = & blob_stats [ i ] ;
2017-05-20 21:41:13 +08:00
if ( bs - > count ) {
if ( ( min_blob_pixels & & bs - > count < min_blob_pixels ) | | ( max_blob_pixels & & bs - > count > max_blob_pixels ) ) {
2020-07-07 01:22:41 +08:00
if ( ( monitor - > GetOptSaveJPEGs ( ) > 1 ) | | config . record_diag_images ) {
2017-05-20 21:41:13 +08:00
for ( int sy = bs - > lo_y ; sy < = bs - > hi_y ; sy + + ) {
2016-04-04 22:11:48 +08:00
spdiff = diff_buff + ( ( diff_width * sy ) + bs - > lo_x ) ;
2017-05-20 21:41:13 +08:00
for ( int sx = bs - > lo_x ; sx < = bs - > hi_x ; sx + + , spdiff + + ) {
if ( * spdiff = = bs - > tag ) {
2016-04-04 22:11:48 +08:00
* spdiff = BLACK ;
}
}
}
}
alarm_blobs - - ;
alarm_blob_pixels - = bs - > count ;
2017-05-20 21:41:13 +08:00
2018-04-24 02:36:46 +08:00
Debug ( 6 , " Eliminated blob %d, %d pixels (%d,%d - %d,%d), %d current blobs " ,
2019-06-24 22:28:11 +08:00
i , bs - > count , bs - > lo_x , bs - > lo_y , bs - > hi_x , bs - > hi_y , alarm_blobs ) ;
2016-04-04 22:11:48 +08:00
bs - > tag = 0 ;
bs - > count = 0 ;
bs - > lo_x = 0 ;
bs - > lo_y = 0 ;
bs - > hi_x = 0 ;
bs - > hi_y = 0 ;
2017-05-20 21:41:13 +08:00
} else {
2018-04-24 02:36:46 +08:00
Debug ( 6 , " Preserved blob %d, %d pixels (%d,%d - %d,%d), %d current blobs " ,
2019-06-24 22:28:11 +08:00
i , bs - > count , bs - > lo_x , bs - > lo_y , bs - > hi_x , bs - > hi_y , alarm_blobs ) ;
2016-04-04 22:11:48 +08:00
if ( ! min_blob_size | | bs - > count < min_blob_size ) min_blob_size = bs - > count ;
if ( ! max_blob_size | | bs - > count > max_blob_size ) max_blob_size = bs - > count ;
}
2018-04-24 02:36:46 +08:00
} // end if bs_count
} // end for i < WHITE
2019-06-24 22:28:11 +08:00
2018-04-24 02:36:46 +08:00
if ( config . record_diag_images )
2019-05-17 03:37:03 +08:00
diff_image - > WriteJpeg ( diag_path , config . record_diag_images_fifo ) ;
2017-05-20 21:41:13 +08:00
2018-04-24 02:36:46 +08:00
Debug ( 5 , " Got %d blob pixels, %d blobs, need %d -> %d, %d -> %d " ,
2019-06-24 22:28:11 +08:00
alarm_blob_pixels , alarm_blobs , min_blob_pixels , max_blob_pixels , min_blobs , max_blobs ) ;
if ( config . record_diag_images_fifo ) {
FifoDebug ( 5 , " { \" zone \" :%d, \" type \" : \" FBLB \" , \" pixels \" :%d, \" blobs \" :%d} " ,
id , alarm_blob_pixels , alarm_blobs ) ;
}
2018-04-24 02:36:46 +08:00
if ( alarm_blobs ) {
if ( min_blobs & & ( alarm_blobs < min_blobs ) ) {
2016-04-04 22:11:48 +08:00
/* Not enough pixels alarmed */
2018-04-24 02:36:46 +08:00
return false ;
} else if ( max_blobs & & ( alarm_blobs > max_blobs ) ) {
2016-04-04 22:11:48 +08:00
/* Too many pixels alarmed */
overload_count = overload_frames ;
2018-04-24 02:36:46 +08:00
return false ;
2016-04-04 22:11:48 +08:00
}
} else {
/* No blobs */
2018-04-24 02:36:46 +08:00
return false ;
2016-04-04 22:11:48 +08:00
}
2018-08-23 00:58:26 +08:00
2019-06-24 22:28:11 +08:00
if ( max_blob_pixels ! = 0 )
2018-08-23 00:58:26 +08:00
score = ( 100 * alarm_blob_pixels ) / ( max_blob_pixels ) ;
else
score = ( 100 * alarm_blob_pixels ) / polygon . Area ( ) ;
2017-05-20 21:41:13 +08:00
if ( score < 1 )
2016-04-04 22:11:48 +08:00
score = 1 ; /* Fix for score of 0 when frame meets thresholds but alarmed area is not big enough */
2018-04-24 02:36:46 +08:00
Debug ( 5 , " Current score is %d " , score ) ;
2016-04-04 22:11:48 +08:00
alarm_lo_x = polygon . HiX ( ) + 1 ;
alarm_hi_x = polygon . LoX ( ) - 1 ;
alarm_lo_y = polygon . HiY ( ) + 1 ;
alarm_hi_y = polygon . LoY ( ) - 1 ;
2017-05-20 21:41:13 +08:00
for ( int i = 1 ; i < WHITE ; i + + ) {
2016-04-04 22:11:48 +08:00
BlobStats * bs = & blob_stats [ i ] ;
2017-05-20 21:41:13 +08:00
if ( bs - > count ) {
if ( bs - > count = = max_blob_size ) {
if ( config . weighted_alarm_centres ) {
2016-04-04 22:11:48 +08:00
unsigned long x_total = 0 ;
unsigned long y_total = 0 ;
2017-05-20 21:41:13 +08:00
for ( int sy = bs - > lo_y ; sy < = bs - > hi_y ; sy + + ) {
2016-04-04 22:11:48 +08:00
spdiff = diff_buff + ( ( diff_width * sy ) + bs - > lo_x ) ;
2017-05-20 21:41:13 +08:00
for ( int sx = bs - > lo_x ; sx < = bs - > hi_x ; sx + + , spdiff + + ) {
if ( * spdiff = = bs - > tag ) {
2016-04-04 22:11:48 +08:00
x_total + = sx ;
y_total + = sy ;
}
}
}
alarm_mid_x = int ( round ( x_total / bs - > count ) ) ;
alarm_mid_y = int ( round ( y_total / bs - > count ) ) ;
2017-05-20 21:41:13 +08:00
} else {
2016-04-04 22:11:48 +08:00
alarm_mid_x = int ( ( bs - > hi_x + bs - > lo_x + 1 ) / 2 ) ;
alarm_mid_y = int ( ( bs - > hi_y + bs - > lo_y + 1 ) / 2 ) ;
}
}
if ( alarm_lo_x > bs - > lo_x ) alarm_lo_x = bs - > lo_x ;
if ( alarm_lo_y > bs - > lo_y ) alarm_lo_y = bs - > lo_y ;
if ( alarm_hi_x < bs - > hi_x ) alarm_hi_x = bs - > hi_x ;
if ( alarm_hi_y < bs - > hi_y ) alarm_hi_y = bs - > hi_y ;
2017-05-20 21:41:13 +08:00
} // end if bs->count
} // end for i < WHITE
} else {
2016-04-04 22:11:48 +08:00
alarm_mid_x = int ( ( alarm_hi_x + alarm_lo_x + 1 ) / 2 ) ;
alarm_mid_y = int ( ( alarm_hi_y + alarm_lo_y + 1 ) / 2 ) ;
}
}
2003-03-26 20:03:37 +08:00
2017-05-20 21:41:13 +08:00
if ( type = = INCLUSIVE ) {
2016-04-04 22:11:48 +08:00
// score >>= 1;
score / = 2 ;
2017-05-20 21:41:13 +08:00
} else if ( type = = EXCLUSIVE ) {
2016-04-04 22:11:48 +08:00
// score <<= 1;
score * = 2 ;
}
2018-04-24 02:36:46 +08:00
Debug ( 5 , " Adjusted score is %d " , score ) ;
2016-04-04 22:11:48 +08:00
// Now outline the changed region
2017-05-20 21:41:13 +08:00
if ( score ) {
2018-04-24 02:36:46 +08:00
alarm_box = Box ( Coord ( alarm_lo_x , alarm_lo_y ) , Coord ( alarm_hi_x , alarm_hi_y ) ) ;
2016-04-04 22:11:48 +08:00
//if ( monitor->followMotion() )
2017-05-20 21:41:13 +08:00
if ( true ) {
2018-04-24 02:36:46 +08:00
alarm_centre = Coord ( alarm_mid_x , alarm_mid_y ) ;
2017-05-20 21:41:13 +08:00
} else {
2016-04-04 22:11:48 +08:00
alarm_centre = alarm_box . Centre ( ) ;
}
2020-07-07 01:22:41 +08:00
if ( ( type < PRECLUSIVE ) & & ( check_method > = BLOBS ) & & ( monitor - > GetOptSaveJPEGs ( ) > 1 ) ) {
2016-04-04 22:11:48 +08:00
// First mask out anything we don't want
2017-05-20 21:41:13 +08:00
for ( unsigned int y = lo_y ; y < = hi_y ; y + + ) {
2016-04-04 22:11:48 +08:00
pdiff = diff_buff + ( ( diff_width * y ) + lo_x ) ;
int lo_x2 = ranges [ y ] . lo_x ;
int hi_x2 = ranges [ y ] . hi_x ;
int lo_gap = lo_x2 - lo_x ;
2017-05-20 21:41:13 +08:00
if ( lo_gap > 0 ) {
if ( lo_gap = = 1 ) {
2016-04-04 22:11:48 +08:00
* pdiff + + = BLACK ;
2017-05-20 21:41:13 +08:00
} else {
2019-06-24 22:28:11 +08:00
memset ( pdiff , BLACK , lo_gap ) ;
2016-04-04 22:11:48 +08:00
pdiff + = lo_gap ;
}
}
2019-06-24 22:28:11 +08:00
const uint8_t * ppoly = pg_image - > Buffer ( lo_x2 , y ) ;
2017-05-20 21:41:13 +08:00
for ( int x = lo_x2 ; x < = hi_x2 ; x + + , pdiff + + , ppoly + + ) {
if ( ! * ppoly ) {
2016-04-04 22:11:48 +08:00
* pdiff = BLACK ;
}
}
int hi_gap = hi_x - hi_x2 ;
2017-05-20 21:41:13 +08:00
if ( hi_gap > 0 ) {
if ( hi_gap = = 1 ) {
2016-04-04 22:11:48 +08:00
* pdiff = BLACK ;
2017-05-20 21:41:13 +08:00
} else {
2019-06-24 22:28:11 +08:00
memset ( pdiff , BLACK , hi_gap ) ;
2016-04-04 22:11:48 +08:00
}
}
2019-06-24 22:28:11 +08:00
} // end for y
2017-05-20 21:41:13 +08:00
if ( monitor - > Colours ( ) = = ZM_COLOUR_GRAY8 ) {
2018-04-24 02:36:46 +08:00
image = diff_image - > HighlightEdges ( alarm_rgb , ZM_COLOUR_RGB24 , ZM_SUBPIX_ORDER_RGB , & polygon . Extent ( ) ) ;
2016-04-04 22:11:48 +08:00
} else {
2018-04-24 02:36:46 +08:00
image = diff_image - > HighlightEdges ( alarm_rgb , monitor - > Colours ( ) , monitor - > SubpixelOrder ( ) , & polygon . Extent ( ) ) ;
2016-04-04 22:11:48 +08:00
}
2017-05-20 21:41:13 +08:00
2016-04-04 22:11:48 +08:00
// Only need to delete this when 'image' becomes detached and points somewhere else
delete diff_image ;
2017-05-20 21:41:13 +08:00
} else {
2016-04-04 22:11:48 +08:00
delete image ;
image = 0 ;
}
2018-04-24 02:36:46 +08:00
Debug ( 1 , " %s: Pixel Diff: %d, Alarm Pixels: %d, Filter Pixels: %d, Blob Pixels: %d, Blobs: %d, Score: %d " ,
Label ( ) , pixel_diff , alarm_pixels , alarm_filter_pixels , alarm_blob_pixels , alarm_blobs , score ) ;
2016-04-04 22:11:48 +08:00
}
2018-04-24 02:36:46 +08:00
return true ;
2003-03-26 20:03:37 +08:00
}
2018-04-24 02:36:46 +08:00
bool Zone : : ParsePolygonString ( const char * poly_string , Polygon & polygon ) {
Debug ( 3 , " Parsing polygon string '%s' " , poly_string ) ;
2016-04-04 22:11:48 +08:00
char * str_ptr = new char [ strlen ( poly_string ) + 1 ] ;
char * str = str_ptr ;
2018-04-24 02:36:46 +08:00
strcpy ( str , poly_string ) ;
2016-04-04 22:11:48 +08:00
char * ws ;
int n_coords = 0 ;
int max_n_coords = strlen ( str ) / 4 ;
Coord * coords = new Coord [ max_n_coords ] ;
2017-05-20 21:41:13 +08:00
while ( true ) {
if ( * str = = ' \0 ' ) {
2016-04-04 22:11:48 +08:00
break ;
}
2018-04-24 02:36:46 +08:00
ws = strchr ( str , ' ' ) ;
2017-05-20 21:41:13 +08:00
if ( ws ) {
2016-04-04 22:11:48 +08:00
* ws = ' \0 ' ;
}
2018-04-24 02:36:46 +08:00
char * cp = strchr ( str , ' , ' ) ;
2017-05-20 21:41:13 +08:00
if ( ! cp ) {
2018-04-24 02:36:46 +08:00
Error ( " Bogus coordinate %s found in polygon string " , str ) ;
2016-04-04 22:11:48 +08:00
delete [ ] coords ;
delete [ ] str_ptr ;
2018-04-24 02:36:46 +08:00
return false ;
2017-05-20 21:41:13 +08:00
} else {
2016-04-04 22:11:48 +08:00
* cp = ' \0 ' ;
char * xp = str ;
char * yp = cp + 1 ;
int x = atoi ( xp ) ;
int y = atoi ( yp ) ;
2018-04-24 02:36:46 +08:00
Debug ( 3 , " Got coordinate %d,%d from polygon string " , x , y ) ;
2005-11-30 01:51:06 +08:00
#if 0
2019-06-24 22:28:11 +08:00
if ( x < 0 )
x = 0 ;
else if ( x > = width )
x = width - 1 ;
if ( y < 0 )
y = 0 ;
else if ( y > = height )
y = height - 1 ;
2005-11-30 01:51:06 +08:00
# endif
2019-06-24 22:28:11 +08:00
coords [ n_coords + + ] = Coord ( x , y ) ;
}
if ( ws )
str = ws + 1 ;
else
break ;
}
polygon = Polygon ( n_coords , coords ) ;
Debug ( 3 , " Successfully parsed polygon string " ) ;
//printf( "Area: %d\n", pg.Area() );
//printf( "Centre: %d,%d\n", pg.Centre().X(), pg.Centre().Y() );
delete [ ] coords ;
delete [ ] str_ptr ;
return true ;
2005-11-30 01:51:06 +08:00
}
2018-04-24 02:36:46 +08:00
bool Zone : : ParseZoneString ( const char * zone_string , int & zone_id , int & colour , Polygon & polygon ) {
Debug ( 3 , " Parsing zone string '%s' " , zone_string ) ;
2005-11-30 01:51:06 +08:00
2016-04-04 22:11:48 +08:00
char * str_ptr = new char [ strlen ( zone_string ) + 1 ] ;
char * str = str_ptr ;
2018-04-24 02:36:46 +08:00
strcpy ( str , zone_string ) ;
2005-11-30 01:51:06 +08:00
2018-04-24 02:36:46 +08:00
char * ws = strchr ( str , ' ' ) ;
2017-05-20 21:41:13 +08:00
if ( ! ws ) {
2018-04-24 02:36:46 +08:00
Debug ( 3 , " No initial whitespace found in zone string '%s', finishing " , str ) ;
2016-04-04 22:11:48 +08:00
}
2018-04-24 02:36:46 +08:00
zone_id = strtol ( str , 0 , 10 ) ;
Debug ( 3 , " Got zone %d from zone string " , zone_id ) ;
2017-05-20 21:41:13 +08:00
if ( ! ws ) {
2017-06-14 22:54:21 +08:00
delete [ ] str_ptr ;
2018-04-24 02:36:46 +08:00
return true ;
2016-04-04 22:11:48 +08:00
}
2005-11-30 01:51:06 +08:00
2016-04-04 22:11:48 +08:00
* ws = ' \0 ' ;
str = ws + 1 ;
2005-11-30 01:51:06 +08:00
2018-04-24 02:36:46 +08:00
ws = strchr ( str , ' ' ) ;
2017-05-20 21:41:13 +08:00
if ( ! ws ) {
2018-04-24 02:36:46 +08:00
Debug ( 3 , " No secondary whitespace found in zone string '%s', finishing " , zone_string ) ;
2016-04-04 22:11:48 +08:00
}
2018-04-24 02:36:46 +08:00
colour = strtol ( str , 0 , 16 ) ;
Debug ( 3 , " Got colour %06x from zone string " , colour ) ;
2017-05-20 21:41:13 +08:00
if ( ! ws ) {
2017-06-14 22:54:21 +08:00
delete [ ] str_ptr ;
2018-04-24 02:36:46 +08:00
return true ;
2016-04-04 22:11:48 +08:00
}
* ws = ' \0 ' ;
str = ws + 1 ;
2005-11-30 01:51:06 +08:00
2018-04-24 02:36:46 +08:00
bool result = ParsePolygonString ( str , polygon ) ;
2005-11-30 01:51:06 +08:00
2016-04-04 22:11:48 +08:00
//printf( "Area: %d\n", pg.Area() );
//printf( "Centre: %d,%d\n", pg.Centre().X(), pg.Centre().Y() );
2005-11-30 01:51:06 +08:00
2016-04-04 22:11:48 +08:00
delete [ ] str_ptr ;
2005-11-30 01:51:06 +08:00
2018-04-24 02:36:46 +08:00
return result ;
2005-11-30 01:51:06 +08:00
}
2018-04-24 02:36:46 +08:00
int Zone : : Load ( Monitor * monitor , Zone * * & zones ) {
2016-04-04 22:11:48 +08:00
static char sql [ ZM_SQL_MED_BUFSIZ ] ;
2018-05-02 00:19:34 +08:00
db_mutex . lock ( ) ;
2018-04-24 02:36:46 +08:00
snprintf ( sql , sizeof ( sql ) , " select Id,Name,Type+0,Units,Coords,AlarmRGB,CheckMethod+0,MinPixelThreshold,MaxPixelThreshold,MinAlarmPixels,MaxAlarmPixels,FilterX,FilterY,MinFilterPixels,MaxFilterPixels,MinBlobPixels,MaxBlobPixels,MinBlobs,MaxBlobs,OverloadFrames,ExtendAlarmFrames from Zones where MonitorId = %d order by Type, Id " , monitor - > Id ( ) ) ;
if ( mysql_query ( & dbconn , sql ) ) {
Error ( " Can't run query: %s " , mysql_error ( & dbconn ) ) ;
2018-05-02 00:19:34 +08:00
db_mutex . unlock ( ) ;
2019-06-24 22:28:11 +08:00
return 0 ;
2016-04-04 22:11:48 +08:00
}
2003-03-26 20:03:37 +08:00
2016-04-04 22:11:48 +08:00
MYSQL_RES * result = mysql_store_result ( & dbconn ) ;
2017-05-20 21:41:13 +08:00
if ( ! result ) {
2018-04-24 02:36:46 +08:00
Error ( " Can't use query result: %s " , mysql_error ( & dbconn ) ) ;
2018-05-02 00:19:34 +08:00
db_mutex . unlock ( ) ;
2018-04-24 02:36:46 +08:00
return 0 ;
2016-04-04 22:11:48 +08:00
}
2018-05-02 00:19:34 +08:00
db_mutex . unlock ( ) ;
2018-04-24 02:36:46 +08:00
int n_zones = mysql_num_rows ( result ) ;
Debug ( 1 , " Got %d zones for monitor %s " , n_zones , monitor - > Name ( ) ) ;
2016-04-04 22:11:48 +08:00
delete [ ] zones ;
zones = new Zone * [ n_zones ] ;
2018-04-24 02:36:46 +08:00
for ( int i = 0 ; MYSQL_ROW dbrow = mysql_fetch_row ( result ) ; i + + ) {
2016-04-04 22:11:48 +08:00
int col = 0 ;
int Id = atoi ( dbrow [ col + + ] ) ;
const char * Name = dbrow [ col + + ] ;
int Type = atoi ( dbrow [ col + + ] ) ;
const char * Units = dbrow [ col + + ] ;
const char * Coords = dbrow [ col + + ] ;
int AlarmRGB = dbrow [ col ] ? atoi ( dbrow [ col ] ) : 0 ; col + + ;
int CheckMethod = atoi ( dbrow [ col + + ] ) ;
int MinPixelThreshold = dbrow [ col ] ? atoi ( dbrow [ col ] ) : 0 ; col + + ;
int MaxPixelThreshold = dbrow [ col ] ? atoi ( dbrow [ col ] ) : 0 ; col + + ;
int MinAlarmPixels = dbrow [ col ] ? atoi ( dbrow [ col ] ) : 0 ; col + + ;
int MaxAlarmPixels = dbrow [ col ] ? atoi ( dbrow [ col ] ) : 0 ; col + + ;
int FilterX = dbrow [ col ] ? atoi ( dbrow [ col ] ) : 0 ; col + + ;
int FilterY = dbrow [ col ] ? atoi ( dbrow [ col ] ) : 0 ; col + + ;
int MinFilterPixels = dbrow [ col ] ? atoi ( dbrow [ col ] ) : 0 ; col + + ;
int MaxFilterPixels = dbrow [ col ] ? atoi ( dbrow [ col ] ) : 0 ; col + + ;
int MinBlobPixels = dbrow [ col ] ? atoi ( dbrow [ col ] ) : 0 ; col + + ;
int MaxBlobPixels = dbrow [ col ] ? atoi ( dbrow [ col ] ) : 0 ; col + + ;
int MinBlobs = dbrow [ col ] ? atoi ( dbrow [ col ] ) : 0 ; col + + ;
int MaxBlobs = dbrow [ col ] ? atoi ( dbrow [ col ] ) : 0 ; col + + ;
int OverloadFrames = dbrow [ col ] ? atoi ( dbrow [ col ] ) : 0 ; col + + ;
int ExtendAlarmFrames = dbrow [ col ] ? atoi ( dbrow [ col ] ) : 0 ; col + + ;
2017-05-20 21:41:13 +08:00
2016-04-04 22:11:48 +08:00
/* HTML colour code is actually BGR in memory, we want RGB */
AlarmRGB = rgb_convert ( AlarmRGB , ZM_SUBPIX_ORDER_BGR ) ;
2018-04-24 02:36:46 +08:00
Debug ( 5 , " Parsing polygon %s " , Coords ) ;
2016-04-04 22:11:48 +08:00
Polygon polygon ;
2018-04-24 02:36:46 +08:00
if ( ! ParsePolygonString ( Coords , polygon ) ) {
Error ( " Unable to parse polygon string '%s' for zone %d/%s for monitor %s, ignoring " , Coords , Id , Name , monitor - > Name ( ) ) ;
2017-03-16 22:55:13 +08:00
n_zones - = 1 ;
2016-09-09 22:07:13 +08:00
continue ;
}
2006-05-08 20:46:23 +08:00
2016-04-04 22:11:48 +08:00
if ( polygon . LoX ( ) < 0 | | polygon . HiX ( ) > = ( int ) monitor - > Width ( )
2017-05-20 21:41:13 +08:00
| | polygon . LoY ( ) < 0 | | polygon . HiY ( ) > = ( int ) monitor - > Height ( ) ) {
2018-04-24 02:36:46 +08:00
Error ( " Zone %d/%s for monitor %s extends outside of image dimensions, (%d,%d), (%d,%d), ignoring " ,
2019-06-24 22:28:11 +08:00
Id , Name , monitor - > Name ( ) , polygon . LoX ( ) , polygon . LoY ( ) , polygon . HiX ( ) , polygon . HiY ( ) ) ;
2017-03-16 22:55:13 +08:00
n_zones - = 1 ;
2016-09-09 22:07:13 +08:00
continue ;
}
2005-11-30 01:51:06 +08:00
2017-05-20 21:41:13 +08:00
if ( false & & ! strcmp ( Units , " Percent " ) ) {
2016-04-04 22:11:48 +08:00
MinAlarmPixels = ( MinAlarmPixels * polygon . Area ( ) ) / 100 ;
MaxAlarmPixels = ( MaxAlarmPixels * polygon . Area ( ) ) / 100 ;
MinFilterPixels = ( MinFilterPixels * polygon . Area ( ) ) / 100 ;
MaxFilterPixels = ( MaxFilterPixels * polygon . Area ( ) ) / 100 ;
MinBlobPixels = ( MinBlobPixels * polygon . Area ( ) ) / 100 ;
MaxBlobPixels = ( MaxBlobPixels * polygon . Area ( ) ) / 100 ;
}
2003-03-26 20:03:37 +08:00
2017-05-20 21:41:13 +08:00
if ( atoi ( dbrow [ 2 ] ) = = Zone : : INACTIVE ) {
2018-04-24 02:36:46 +08:00
zones [ i ] = new Zone ( monitor , Id , Name , polygon ) ;
2017-05-20 21:41:13 +08:00
} else if ( atoi ( dbrow [ 2 ] ) = = Zone : : PRIVACY ) {
2018-04-24 02:36:46 +08:00
zones [ i ] = new Zone ( monitor , Id , Name , ( Zone : : ZoneType ) Type , polygon ) ;
2016-04-04 22:11:48 +08:00
}
2018-04-24 02:36:46 +08:00
zones [ i ] = new Zone ( monitor , Id , Name , ( Zone : : ZoneType ) Type , polygon , AlarmRGB , ( Zone : : CheckMethod ) CheckMethod , MinPixelThreshold , MaxPixelThreshold , MinAlarmPixels , MaxAlarmPixels , Coord ( FilterX , FilterY ) , MinFilterPixels , MaxFilterPixels , MinBlobPixels , MaxBlobPixels , MinBlobs , MaxBlobs , OverloadFrames , ExtendAlarmFrames ) ;
} // end foreach row
mysql_free_result ( result ) ;
return n_zones ;
} // end int Zone::Load(Monitor *monitor, Zone **&zones)
2003-03-26 20:03:37 +08:00
2018-04-24 02:36:46 +08:00
bool Zone : : DumpSettings ( char * output , bool /*verbose*/ ) {
2016-04-04 22:11:48 +08:00
output [ 0 ] = 0 ;
sprintf ( output + strlen ( output ) , " Id : %d \n " , id ) ;
sprintf ( output + strlen ( output ) , " Label : %s \n " , label ) ;
sprintf ( output + strlen ( output ) , " Type: %d - %s \n " , type ,
2017-05-20 21:41:13 +08:00
type = = ACTIVE ? " Active " : (
type = = INCLUSIVE ? " Inclusive " : (
type = = EXCLUSIVE ? " Exclusive " : (
type = = PRECLUSIVE ? " Preclusive " : (
type = = INACTIVE ? " Inactive " : (
type = = PRIVACY ? " Privacy " : " Unknown "
) ) ) ) ) ) ;
2016-04-04 22:11:48 +08:00
sprintf ( output + strlen ( output ) , " Shape : %d points \n " , polygon . getNumCoords ( ) ) ;
2017-05-20 21:41:13 +08:00
for ( int i = 0 ; i < polygon . getNumCoords ( ) ; i + + ) {
2016-04-04 22:11:48 +08:00
sprintf ( output + strlen ( output ) , " %i: %d,%d \n " , i , polygon . getCoord ( i ) . X ( ) , polygon . getCoord ( i ) . Y ( ) ) ;
}
sprintf ( output + strlen ( output ) , " Alarm RGB : %06x \n " , alarm_rgb ) ;
sprintf ( output + strlen ( output ) , " Check Method: %d - %s \n " , check_method ,
2017-05-20 21:41:13 +08:00
check_method = = ALARMED_PIXELS ? " Alarmed Pixels " : (
check_method = = FILTERED_PIXELS ? " FilteredPixels " : (
check_method = = BLOBS ? " Blobs " : " Unknown "
) ) ) ;
2016-04-04 22:11:48 +08:00
sprintf ( output + strlen ( output ) , " Min Pixel Threshold : %d \n " , min_pixel_threshold ) ;
sprintf ( output + strlen ( output ) , " Max Pixel Threshold : %d \n " , max_pixel_threshold ) ;
sprintf ( output + strlen ( output ) , " Min Alarm Pixels : %d \n " , min_alarm_pixels ) ;
sprintf ( output + strlen ( output ) , " Max Alarm Pixels : %d \n " , max_alarm_pixels ) ;
sprintf ( output + strlen ( output ) , " Filter Box : %d,%d \n " , filter_box . X ( ) , filter_box . Y ( ) ) ;
sprintf ( output + strlen ( output ) , " Min Filter Pixels : %d \n " , min_filter_pixels ) ;
sprintf ( output + strlen ( output ) , " Max Filter Pixels : %d \n " , max_filter_pixels ) ;
sprintf ( output + strlen ( output ) , " Min Blob Pixels : %d \n " , min_blob_pixels ) ;
sprintf ( output + strlen ( output ) , " Max Blob Pixels : %d \n " , max_blob_pixels ) ;
sprintf ( output + strlen ( output ) , " Min Blobs : %d \n " , min_blobs ) ;
sprintf ( output + strlen ( output ) , " Max Blobs : %d \n " , max_blobs ) ;
2020-07-23 05:30:39 +08:00
return true ;
2003-03-26 20:03:37 +08:00
}
2020-07-23 05:30:39 +08:00
void Zone : : std_alarmedpixels (
Image * pdiff_image ,
const Image * ppoly_image ,
unsigned int * pixel_count ,
unsigned int * pixel_sum ) {
2016-04-04 22:11:48 +08:00
uint32_t pixelsalarmed = 0 ;
uint32_t pixelsdifference = 0 ;
uint8_t calc_max_pixel_threshold = 255 ;
unsigned int lo_y ;
unsigned int hi_y ;
2017-05-20 21:41:13 +08:00
2018-04-24 02:36:46 +08:00
if ( max_pixel_threshold )
2016-04-04 22:11:48 +08:00
calc_max_pixel_threshold = max_pixel_threshold ;
2017-05-20 21:41:13 +08:00
2016-04-04 22:11:48 +08:00
lo_y = polygon . LoY ( ) ;
hi_y = polygon . HiY ( ) ;
2017-05-20 21:41:13 +08:00
for ( unsigned int y = lo_y ; y < = hi_y ; y + + ) {
2017-11-19 05:00:10 +08:00
unsigned int lo_x = ranges [ y ] . lo_x ;
unsigned int hi_x = ranges [ y ] . hi_x ;
2017-05-20 21:41:13 +08:00
2018-04-24 02:36:46 +08:00
Debug ( 7 , " Checking line %d from %d -> %d " , y , lo_x , hi_x ) ;
uint8_t * pdiff = ( uint8_t * ) pdiff_image - > Buffer ( lo_x , y ) ;
const uint8_t * ppoly = ppoly_image - > Buffer ( lo_x , y ) ;
2017-05-20 21:41:13 +08:00
for ( unsigned int x = lo_x ; x < = hi_x ; x + + , pdiff + + , ppoly + + ) {
if ( * ppoly & & ( * pdiff > min_pixel_threshold ) & & ( * pdiff < = calc_max_pixel_threshold ) ) {
2016-04-04 22:11:48 +08:00
pixelsalarmed + + ;
pixelsdifference + = * pdiff ;
* pdiff = WHITE ;
2017-05-20 21:41:13 +08:00
} else {
2016-04-04 22:11:48 +08:00
* pdiff = BLACK ;
}
}
}
2017-05-20 21:41:13 +08:00
2016-04-04 22:11:48 +08:00
/* Store the results */
* pixel_count = pixelsalarmed ;
* pixel_sum = pixelsdifference ;
2017-09-26 04:23:27 +08:00
Debug ( 7 , " STORED pixelsalarmed(%d), pixelsdifference(%d) " , pixelsalarmed , pixelsdifference ) ;
2011-07-05 23:23:02 +08:00
}