Initial implementation of learning, fixed scoring bug and Mark functions.
git-svn-id: http://svn.zoneminder.com/svn/zm/trunk@121 e3e1d417-86f3-4887-817a-d78f3d33393f
This commit is contained in:
parent
cdefac9af9
commit
db6e5103b9
171
src/zm.cpp
171
src/zm.cpp
|
@ -21,8 +21,10 @@
|
||||||
|
|
||||||
MYSQL dbconn;
|
MYSQL dbconn;
|
||||||
|
|
||||||
void Zone::Setup( int p_id, const char *p_label, ZoneType p_type, const Box &p_limits, const Rgb p_alarm_rgb, int p_alarm_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 )
|
void Zone::Setup( Monitor *p_monitor, int p_id, const char *p_label, ZoneType p_type, const Box &p_limits, const Rgb p_alarm_rgb, int p_alarm_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 )
|
||||||
{
|
{
|
||||||
|
monitor = p_monitor;
|
||||||
|
|
||||||
id = p_id;
|
id = p_id;
|
||||||
label = new char[strlen(p_label)+1];
|
label = new char[strlen(p_label)+1];
|
||||||
strcpy( label, p_label );
|
strcpy( label, p_label );
|
||||||
|
@ -45,6 +47,7 @@ void Zone::Setup( int p_id, const char *p_label, ZoneType p_type, const Box &p_l
|
||||||
alarmed = false;
|
alarmed = false;
|
||||||
alarm_pixels = 0;
|
alarm_pixels = 0;
|
||||||
alarm_filter_pixels = 0;
|
alarm_filter_pixels = 0;
|
||||||
|
alarm_blob_pixels = 0;
|
||||||
alarm_blobs = 0;
|
alarm_blobs = 0;
|
||||||
image = 0;
|
image = 0;
|
||||||
score = 0;
|
score = 0;
|
||||||
|
@ -56,10 +59,21 @@ Zone::~Zone()
|
||||||
delete image;
|
delete image;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Zone::Load( int monitor_id, int width, int height, Zone **&zones )
|
void Zone::RecordStats( const Event *event )
|
||||||
{
|
{
|
||||||
static char sql[256];
|
static char sql[256];
|
||||||
sprintf( sql, "select Id,Name,Type+0,Units,LoX,LoY,HiX,HiY,AlarmRGB,AlarmThreshold,MinAlarmPixels,MaxAlarmPixels,FilterX,FilterY,MinFilterPixels,MaxFilterPixels,MinBlobPixels,MaxBlobPixels,MinBlobs,MaxBlobs from Zones where MonitorId = %d order by Type, Id", monitor_id );
|
sprintf( sql, "insert into Stats set MonitorId=%d, ZoneId=%d, EventId=%d, FrameId=%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, 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: %s\n", mysql_error( &dbconn ) ));
|
||||||
|
exit( mysql_errno( &dbconn ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Zone::Load( Monitor *monitor, Zone **&zones )
|
||||||
|
{
|
||||||
|
static char sql[256];
|
||||||
|
sprintf( sql, "select Id,Name,Type+0,Units,LoX,LoY,HiX,HiY,AlarmRGB,AlarmThreshold,MinAlarmPixels,MaxAlarmPixels,FilterX,FilterY,MinFilterPixels,MaxFilterPixels,MinBlobPixels,MaxBlobPixels,MinBlobs,MaxBlobs from Zones where MonitorId = %d order by Type, Id", monitor->Id() );
|
||||||
if ( mysql_query( &dbconn, sql ) )
|
if ( mysql_query( &dbconn, sql ) )
|
||||||
{
|
{
|
||||||
Error(( "Can't run query: %s\n", mysql_error( &dbconn ) ));
|
Error(( "Can't run query: %s\n", mysql_error( &dbconn ) ));
|
||||||
|
@ -73,7 +87,7 @@ int Zone::Load( int monitor_id, int width, int height, Zone **&zones )
|
||||||
exit( mysql_errno( &dbconn ) );
|
exit( mysql_errno( &dbconn ) );
|
||||||
}
|
}
|
||||||
int n_zones = mysql_num_rows( result );
|
int n_zones = mysql_num_rows( result );
|
||||||
Info(( "Got %d zones for monitor %d\n", n_zones, monitor_id ));
|
Info(( "Got %d zones for monitor %s\n", n_zones, monitor->Name() ));
|
||||||
delete[] zones;
|
delete[] zones;
|
||||||
zones = new Zone *[n_zones];
|
zones = new Zone *[n_zones];
|
||||||
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ )
|
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ )
|
||||||
|
@ -101,25 +115,25 @@ int Zone::Load( int monitor_id, int width, int height, Zone **&zones )
|
||||||
|
|
||||||
if ( !strcmp( Units, "Percent" ) )
|
if ( !strcmp( Units, "Percent" ) )
|
||||||
{
|
{
|
||||||
LoX = (LoX*(width-1))/100;
|
LoX = (LoX*(monitor->Width()-1))/100;
|
||||||
LoY = (LoY*(height-1))/100;
|
LoY = (LoY*(monitor->Height()-1))/100;
|
||||||
HiX = (HiX*(width-1))/100;
|
HiX = (HiX*(monitor->Width()-1))/100;
|
||||||
HiY = (HiY*(height-1))/100;
|
HiY = (HiY*(monitor->Height()-1))/100;
|
||||||
MinAlarmPixels = (MinAlarmPixels*width*height)/100;
|
MinAlarmPixels = (MinAlarmPixels*monitor->Width()*monitor->Height())/100;
|
||||||
MaxAlarmPixels = (MaxAlarmPixels*width*height)/100;
|
MaxAlarmPixels = (MaxAlarmPixels*monitor->Width()*monitor->Height())/100;
|
||||||
MinFilterPixels = (MinFilterPixels*width*height)/100;
|
MinFilterPixels = (MinFilterPixels*monitor->Width()*monitor->Height())/100;
|
||||||
MaxFilterPixels = (MaxFilterPixels*width*height)/100;
|
MaxFilterPixels = (MaxFilterPixels*monitor->Width()*monitor->Height())/100;
|
||||||
MinBlobPixels = (MinBlobPixels*width*height)/100;
|
MinBlobPixels = (MinBlobPixels*monitor->Width()*monitor->Height())/100;
|
||||||
MaxBlobPixels = (MaxBlobPixels*width*height)/100;
|
MaxBlobPixels = (MaxBlobPixels*monitor->Width()*monitor->Height())/100;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( atoi(dbrow[2]) == Zone::INACTIVE )
|
if ( atoi(dbrow[2]) == Zone::INACTIVE )
|
||||||
{
|
{
|
||||||
zones[i] = new Zone( Id, Name, Box( LoX, LoY, HiX, HiY ) );
|
zones[i] = new Zone( monitor, Id, Name, Box( LoX, LoY, HiX, HiY ) );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
zones[i] = new Zone( Id, Name, (Zone::ZoneType)Type, Box( LoX, LoY, HiX, HiY ), AlarmRGB, AlarmThreshold, MinAlarmPixels, MaxAlarmPixels, Coord( FilterX, FilterY ), MinFilterPixels, MaxFilterPixels, MinBlobPixels, MaxBlobPixels, MinBlobs, MaxBlobs );
|
zones[i] = new Zone( monitor, Id, Name, (Zone::ZoneType)Type, Box( LoX, LoY, HiX, HiY ), AlarmRGB, AlarmThreshold, MinAlarmPixels, MaxAlarmPixels, Coord( FilterX, FilterY ), MinFilterPixels, MaxFilterPixels, MinBlobPixels, MaxBlobPixels, MinBlobs, MaxBlobs );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( mysql_errno( &dbconn ) )
|
if ( mysql_errno( &dbconn ) )
|
||||||
|
@ -514,11 +528,13 @@ Image *Image::Delta( const Image &image, bool absolute ) const
|
||||||
return( result );
|
return( result );
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Image::CheckAlarms( Zone *zone, const Image *delta_image ) const
|
bool Image::CheckAlarms( Zone *zone, const Image *delta_image ) const
|
||||||
{
|
{
|
||||||
bool alarm = false;
|
bool alarm = false;
|
||||||
unsigned int score = 0;
|
unsigned int score = 0;
|
||||||
|
|
||||||
|
zone->ResetStats();
|
||||||
|
|
||||||
delete zone->image;
|
delete zone->image;
|
||||||
Image *diff_image = zone->image = new Image( *delta_image );
|
Image *diff_image = zone->image = new Image( *delta_image );
|
||||||
|
|
||||||
|
@ -564,39 +580,6 @@ unsigned int Image::CheckAlarms( Zone *zone, const Image *delta_image ) const
|
||||||
for ( int x = lo_x; x <= hi_x; x++, pdiff++ )
|
for ( int x = lo_x; x <= hi_x; x++, pdiff++ )
|
||||||
{
|
{
|
||||||
if ( *pdiff == WHITE )
|
if ( *pdiff == WHITE )
|
||||||
{
|
|
||||||
if ( 0 )
|
|
||||||
{
|
|
||||||
int count;
|
|
||||||
int dx;
|
|
||||||
// Check participation in an X blob
|
|
||||||
int ldx = (x>=(lo_x+bx1))?-bx1:lo_x-x;
|
|
||||||
int hdx = (x<=(hi_x-bx1))?bx1:hi_x-x;
|
|
||||||
for ( count = 0, dx = ldx; count < bx && dx <= hdx; dx++ )
|
|
||||||
{
|
|
||||||
count = (*(pdiff+dx) == WHITE)?count+1:0;
|
|
||||||
}
|
|
||||||
if ( count < bx )
|
|
||||||
{
|
|
||||||
*pdiff = BLACK;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int dy;
|
|
||||||
// Check participation in a Y blob
|
|
||||||
int ldy = (y>=(lo_y+by1))?-by1:lo_y-y;
|
|
||||||
int hdy = (y<=(hi_y-by1))?by1:hi_y-y;
|
|
||||||
for ( count = 0, dy = ldy; count < by && dy <= hdy; dy++ )
|
|
||||||
{
|
|
||||||
count = (*(pdiff+(diff_image->width*dy)) == WHITE)?count+1:0;
|
|
||||||
}
|
|
||||||
if ( count < by )
|
|
||||||
{
|
|
||||||
*pdiff = BLACK;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
filter_pixels++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// Check participation in an X blob
|
// Check participation in an X blob
|
||||||
int ldx = (x>=(lo_x+bx1))?-bx1:lo_x-x;
|
int ldx = (x>=(lo_x+bx1))?-bx1:lo_x-x;
|
||||||
|
@ -633,7 +616,6 @@ unsigned int Image::CheckAlarms( Zone *zone, const Image *delta_image ) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//diff_image->WriteJpeg( "diff2.jpg" );
|
//diff_image->WriteJpeg( "diff2.jpg" );
|
||||||
|
|
||||||
|
@ -771,7 +753,6 @@ unsigned int Image::CheckAlarms( Zone *zone, const Image *delta_image ) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -781,6 +762,8 @@ unsigned int Image::CheckAlarms( Zone *zone, const Image *delta_image ) const
|
||||||
if ( !blobs ) return( false );
|
if ( !blobs ) return( false );
|
||||||
int blob_pixels = filter_pixels;
|
int blob_pixels = filter_pixels;
|
||||||
|
|
||||||
|
int min_blob_size = 0;
|
||||||
|
int max_blob_size = 0;
|
||||||
// Now eliminate blobs under the alarm_threshold
|
// Now eliminate blobs under the alarm_threshold
|
||||||
for ( int i = 1; i < WHITE; i++ )
|
for ( int i = 1; i < WHITE; i++ )
|
||||||
{
|
{
|
||||||
|
@ -809,6 +792,14 @@ unsigned int Image::CheckAlarms( Zone *zone, const Image *delta_image ) const
|
||||||
bs->hi_x = 0;
|
bs->hi_x = 0;
|
||||||
bs->hi_y = 0;
|
bs->hi_y = 0;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( bs->count )
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !blobs ) return( false );
|
if ( !blobs ) return( false );
|
||||||
|
@ -831,11 +822,14 @@ unsigned int Image::CheckAlarms( Zone *zone, const Image *delta_image ) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
zone->alarm_blobs = blobs;
|
|
||||||
zone->alarm_pixels = alarm_pixels;
|
zone->alarm_pixels = alarm_pixels;
|
||||||
zone->alarm_filter_pixels = filter_pixels;
|
zone->alarm_filter_pixels = filter_pixels;
|
||||||
|
zone->alarm_blob_pixels = blob_pixels;
|
||||||
|
zone->alarm_blobs = blobs;
|
||||||
|
zone->min_blob_size = min_blob_size;
|
||||||
|
zone->max_blob_size = max_blob_size;
|
||||||
zone->alarm_box = Box( Coord( alarm_lo_x, alarm_lo_y ), Coord( alarm_hi_x, alarm_hi_y ) );
|
zone->alarm_box = Box( Coord( alarm_lo_x, alarm_lo_y ), Coord( alarm_hi_x, alarm_hi_y ) );
|
||||||
score = zone->score = ((100*blob_pixels)/blobs)/(zone->limits.Size().X()*zone->limits.Size().Y());
|
zone->score = ((100*blob_pixels)/blobs)/(zone->limits.Size().X()*zone->limits.Size().Y());
|
||||||
if ( zone->Type() == Zone::INCLUSIVE )
|
if ( zone->Type() == Zone::INCLUSIVE )
|
||||||
{
|
{
|
||||||
zone->score /= 2;
|
zone->score /= 2;
|
||||||
|
@ -844,7 +838,7 @@ unsigned int Image::CheckAlarms( Zone *zone, const Image *delta_image ) const
|
||||||
{
|
{
|
||||||
zone->score *= 2;
|
zone->score *= 2;
|
||||||
}
|
}
|
||||||
//Info(( "%d - %d - %d - %.2f\n", zone->alarm_blobs, zone->alarm_pixels, zone->alarm_filter_pixels, zone->result ));
|
score = zone->score;
|
||||||
|
|
||||||
// Now outline the changed region
|
// Now outline the changed region
|
||||||
if ( zone->alarm_blobs )
|
if ( zone->alarm_blobs )
|
||||||
|
@ -879,9 +873,9 @@ unsigned int Image::CheckAlarms( Zone *zone, const Image *delta_image ) const
|
||||||
delete diff_image;
|
delete diff_image;
|
||||||
//high_image->WriteJpeg( "diff4.jpg" );
|
//high_image->WriteJpeg( "diff4.jpg" );
|
||||||
|
|
||||||
Info(( "%s: Alarm Pixels: %d, Filter Pixels: %d, Blobs: %d, Score: %d\n", zone->Label(), alarm_pixels, filter_pixels, blobs, score ));
|
Info(( "%s: Alarm Pixels: %d, Filter Pixels: %d, Blob Pixels: %d, Blobs: %d, Score: %d\n", zone->Label(), alarm_pixels, filter_pixels, blob_pixels, blobs, score ));
|
||||||
}
|
}
|
||||||
return( score );
|
return( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Image::Compare( const Image &image, int n_zones, Zone *zones[] ) const
|
unsigned int Image::Compare( const Image &image, int n_zones, Zone *zones[] ) const
|
||||||
|
@ -919,8 +913,6 @@ unsigned int Image::Compare( const Image &image, int n_zones, Zone *zones[] ) co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int zone_score = 0;
|
|
||||||
|
|
||||||
// Find all alarm pixels in active zones
|
// Find all alarm pixels in active zones
|
||||||
for ( int n_zone = 0; n_zone < n_zones; n_zone++ )
|
for ( int n_zone = 0; n_zone < n_zones; n_zone++ )
|
||||||
{
|
{
|
||||||
|
@ -930,12 +922,12 @@ unsigned int Image::Compare( const Image &image, int n_zones, Zone *zones[] ) co
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Debug( 3, ( "Checking active zone %s", zone->Label() ));
|
Debug( 3, ( "Checking active zone %s", zone->Label() ));
|
||||||
if ( zone_score = CheckAlarms( zone, delta_image ) )
|
if ( CheckAlarms( zone, delta_image ) )
|
||||||
{
|
{
|
||||||
alarm = true;
|
alarm = true;
|
||||||
score += zone_score;
|
score += zone->score;
|
||||||
zone->alarmed = true;
|
zone->alarmed = true;
|
||||||
Debug( 3, ( "Zone is alarmed, zone score = %d", zone_score ));
|
Debug( 3, ( "Zone is alarmed, zone score = %d", zone->score ));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -949,12 +941,12 @@ unsigned int Image::Compare( const Image &image, int n_zones, Zone *zones[] ) co
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Debug( 3, ( "Checking inclusive zone %s", zone->Label() ));
|
Debug( 3, ( "Checking inclusive zone %s", zone->Label() ));
|
||||||
if ( zone_score = CheckAlarms( zone, delta_image ) )
|
if ( CheckAlarms( zone, delta_image ) )
|
||||||
{
|
{
|
||||||
alarm = true;
|
alarm = true;
|
||||||
score += zone_score;
|
score += zone->score;
|
||||||
zone->alarmed = true;
|
zone->alarmed = true;
|
||||||
Debug( 3, ( "Zone is alarmed, zone score = %d", zone_score ));
|
Debug( 3, ( "Zone is alarmed, zone score = %d", zone->score ));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -969,18 +961,19 @@ unsigned int Image::Compare( const Image &image, int n_zones, Zone *zones[] ) co
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Debug( 3, ( "Checking exclusive zone %s", zone->Label() ));
|
Debug( 3, ( "Checking exclusive zone %s", zone->Label() ));
|
||||||
if ( zone_score = CheckAlarms( zone, delta_image ) )
|
if ( CheckAlarms( zone, delta_image ) )
|
||||||
{
|
{
|
||||||
alarm = true;
|
alarm = true;
|
||||||
score += zone_score;
|
score += zone->score;
|
||||||
zone->alarmed = true;
|
zone->alarmed = true;
|
||||||
Debug( 3, ( "Zone is alarmed, zone score = %d", zone_score ));
|
Debug( 3, ( "Zone is alarmed, zone score = %d", zone->score ));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delete delta_image;
|
delete delta_image;
|
||||||
return( score );
|
// This is a small and innocent hack to prevent scores of 0 being returned in alarm state
|
||||||
|
return( score?score:alarm );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::Annotate( const char *text, const Coord &coord, const Rgb colour )
|
void Image::Annotate( const char *text, const Coord &coord, const Rgb colour )
|
||||||
|
@ -1486,7 +1479,7 @@ Monitor::Monitor( int p_id, char *p_name, int p_function, int p_device, int p_ch
|
||||||
{
|
{
|
||||||
n_zones = 1;
|
n_zones = 1;
|
||||||
zones = new Zone *[1];
|
zones = new Zone *[1];
|
||||||
zones[0] = new Zone( 0, "All", Zone::ACTIVE, Box( width, height ), RGB_RED );
|
zones[0] = new Zone( this, 0, "All", Zone::ACTIVE, Box( width, height ), RGB_RED );
|
||||||
}
|
}
|
||||||
start_time = last_fps_time = time( 0 );
|
start_time = last_fps_time = time( 0 );
|
||||||
|
|
||||||
|
@ -1530,10 +1523,7 @@ Monitor::Monitor( int p_id, char *p_name, int p_function, int p_device, int p_ch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//if ( capture )
|
record_zone_stats = true;
|
||||||
//{
|
|
||||||
//Camera::Capture( ref_image );
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Monitor::~Monitor()
|
Monitor::~Monitor()
|
||||||
|
@ -1557,6 +1547,12 @@ Monitor::~Monitor()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Monitor::AddZones( int p_n_zones, Zone *p_zones[] )
|
||||||
|
{
|
||||||
|
n_zones = p_n_zones;
|
||||||
|
zones = p_zones;
|
||||||
|
}
|
||||||
|
|
||||||
Monitor::State Monitor::GetState() const
|
Monitor::State Monitor::GetState() const
|
||||||
{
|
{
|
||||||
return( shared_images->state );
|
return( shared_images->state );
|
||||||
|
@ -1649,14 +1645,20 @@ void Monitor::CheckFunction()
|
||||||
|
|
||||||
void Monitor::DumpZoneImage()
|
void Monitor::DumpZoneImage()
|
||||||
{
|
{
|
||||||
|
Mark();
|
||||||
int index = shared_images->last_write_index;
|
int index = shared_images->last_write_index;
|
||||||
|
Mark();
|
||||||
Snapshot *snap = &image_buffer[index];
|
Snapshot *snap = &image_buffer[index];
|
||||||
|
Mark();
|
||||||
Image *image = snap->image;
|
Image *image = snap->image;
|
||||||
|
Mark();
|
||||||
|
|
||||||
Image zone_image( *image );
|
Image zone_image( *image );
|
||||||
|
Mark();
|
||||||
zone_image.Colourise();
|
zone_image.Colourise();
|
||||||
for( int i = 0; i < n_zones; i++ )
|
for( int i = 0; i < n_zones; i++ )
|
||||||
{
|
{
|
||||||
|
Mark();
|
||||||
unsigned char *psrc = zone_image.buffer;
|
unsigned char *psrc = zone_image.buffer;
|
||||||
int lo_x = zones[i]->Limits().Lo().X();
|
int lo_x = zones[i]->Limits().Lo().X();
|
||||||
int lo_y = zones[i]->Limits().Lo().Y();
|
int lo_y = zones[i]->Limits().Lo().Y();
|
||||||
|
@ -1699,8 +1701,11 @@ void Monitor::DumpZoneImage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
char filename[64];
|
char filename[64];
|
||||||
|
Mark();
|
||||||
sprintf( filename, "%s-Zones.jpg", name );
|
sprintf( filename, "%s-Zones.jpg", name );
|
||||||
|
Mark();
|
||||||
zone_image.WriteJpeg( filename );
|
zone_image.WriteJpeg( filename );
|
||||||
|
Mark();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Monitor::DumpImage( Image *image ) const
|
void Monitor::DumpImage( Image *image ) const
|
||||||
|
@ -1785,6 +1790,10 @@ bool Monitor::Analyse()
|
||||||
if ( zones[i]->Alarmed() )
|
if ( zones[i]->Alarmed() )
|
||||||
{
|
{
|
||||||
alarm_image.Overlay( zones[i]->AlarmImage() );
|
alarm_image.Overlay( zones[i]->AlarmImage() );
|
||||||
|
if ( record_zone_stats )
|
||||||
|
{
|
||||||
|
zones[i]->RecordStats( event );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
event->AddFrame( now, image, &alarm_image, score );
|
event->AddFrame( now, image, &alarm_image, score );
|
||||||
|
@ -1812,7 +1821,7 @@ void Monitor::ReloadZones()
|
||||||
delete zones[i];
|
delete zones[i];
|
||||||
}
|
}
|
||||||
//delete[] zones;
|
//delete[] zones;
|
||||||
n_zones = Zone::Load( id, width, height, zones );
|
n_zones = Zone::Load( this, zones );
|
||||||
DumpZoneImage();
|
DumpZoneImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1845,9 +1854,10 @@ int Monitor::Load( int device, Monitor **&monitors, bool capture )
|
||||||
monitors = new Monitor *[n_monitors];
|
monitors = new Monitor *[n_monitors];
|
||||||
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ )
|
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ )
|
||||||
{
|
{
|
||||||
|
monitors[i] = new Monitor( atoi(dbrow[0]), dbrow[1], atoi(dbrow[2]), atoi(dbrow[3]), atoi(dbrow[4]), atoi(dbrow[5]), atoi(dbrow[6]), atoi(dbrow[7]), atoi(dbrow[8]), capture, dbrow[9], Coord( atoi(dbrow[10]), atoi(dbrow[11]) ), atoi(dbrow[12]), atoi(dbrow[13]), atoi(dbrow[14]), atoi(dbrow[15]), atoi(dbrow[16]), atoi(dbrow[17]), atoi(dbrow[18]) );
|
||||||
Zone **zones = 0;
|
Zone **zones = 0;
|
||||||
int n_zones = Zone::Load( atoi(dbrow[0]), atoi(dbrow[6]), atoi(dbrow[7]), zones );
|
int n_zones = Zone::Load( monitors[i], zones );
|
||||||
monitors[i] = new Monitor( atoi(dbrow[0]), dbrow[1], atoi(dbrow[2]), atoi(dbrow[3]), atoi(dbrow[4]), atoi(dbrow[5]), atoi(dbrow[6]), atoi(dbrow[7]), atoi(dbrow[8]), capture, dbrow[9], Coord( atoi(dbrow[10]), atoi(dbrow[11]) ), atoi(dbrow[12]), atoi(dbrow[13]), atoi(dbrow[14]), atoi(dbrow[15]), atoi(dbrow[16]), atoi(dbrow[17]), atoi(dbrow[18]), n_zones, zones );
|
monitors[i]->AddZones( n_zones, zones );
|
||||||
Info(( "Loaded monitor %d(%s), %d zones\n", atoi(dbrow[0]), dbrow[1], n_zones ));
|
Info(( "Loaded monitor %d(%s), %d zones\n", atoi(dbrow[0]), dbrow[1], n_zones ));
|
||||||
}
|
}
|
||||||
if ( mysql_errno( &dbconn ) )
|
if ( mysql_errno( &dbconn ) )
|
||||||
|
@ -1882,13 +1892,14 @@ Monitor *Monitor::Load( int id, bool load_zones )
|
||||||
Monitor *monitor = 0;
|
Monitor *monitor = 0;
|
||||||
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ )
|
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ )
|
||||||
{
|
{
|
||||||
Zone **zones = 0;
|
monitor = new Monitor( atoi(dbrow[0]), dbrow[1], atoi(dbrow[2]), atoi(dbrow[3]), atoi(dbrow[4]), atoi(dbrow[5]), atoi(dbrow[6]), atoi(dbrow[7]), atoi(dbrow[8]), false, dbrow[9], Coord( atoi(dbrow[10]), atoi(dbrow[11]) ), atoi(dbrow[12]), atoi(dbrow[13]), atoi(dbrow[14]), atoi(dbrow[15]), atoi(dbrow[16]), atoi(dbrow[17]), atoi(dbrow[18]) );
|
||||||
int n_zones = 0;
|
int n_zones = 0;
|
||||||
if ( load_zones )
|
if ( load_zones )
|
||||||
{
|
{
|
||||||
int n_zones = Zone::Load( atoi(dbrow[0]), atoi(dbrow[6]), atoi(dbrow[7]), zones );
|
Zone **zones = 0;
|
||||||
|
n_zones = Zone::Load( monitor, zones );
|
||||||
|
monitor->AddZones( n_zones, zones );
|
||||||
}
|
}
|
||||||
monitor = new Monitor( atoi(dbrow[0]), dbrow[1], atoi(dbrow[2]), atoi(dbrow[3]), atoi(dbrow[4]), atoi(dbrow[5]), atoi(dbrow[6]), atoi(dbrow[7]), atoi(dbrow[8]), false, dbrow[9], Coord( atoi(dbrow[10]), atoi(dbrow[11]) ), atoi(dbrow[12]), atoi(dbrow[13]), atoi(dbrow[14]), atoi(dbrow[15]), atoi(dbrow[16]), atoi(dbrow[17]), atoi(dbrow[18]), n_zones, zones );
|
|
||||||
Info(( "Loaded monitor %d(%s), %d zones\n", atoi(dbrow[0]), dbrow[1], n_zones ));
|
Info(( "Loaded monitor %d(%s), %d zones\n", atoi(dbrow[0]), dbrow[1], n_zones ));
|
||||||
}
|
}
|
||||||
if ( mysql_errno( &dbconn ) )
|
if ( mysql_errno( &dbconn ) )
|
||||||
|
|
60
src/zm.h
60
src/zm.h
|
@ -183,7 +183,11 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
inline const Coord &Lo() const { return( lo ); }
|
inline const Coord &Lo() const { return( lo ); }
|
||||||
|
inline int LoX() const { return( lo.X() ); }
|
||||||
|
inline int LoY() const { return( lo.Y() ); }
|
||||||
inline const Coord &Hi() const { return( hi ); }
|
inline const Coord &Hi() const { return( hi ); }
|
||||||
|
inline int HiX() const { return( hi.X() ); }
|
||||||
|
inline int HiY() const { return( hi.Y() ); }
|
||||||
inline const Coord &Size() const { return( size ); }
|
inline const Coord &Size() const { return( size ); }
|
||||||
inline int Width() const
|
inline int Width() const
|
||||||
{
|
{
|
||||||
|
@ -200,6 +204,9 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Monitor;
|
||||||
|
class Event;
|
||||||
|
|
||||||
class Zone
|
class Zone
|
||||||
{
|
{
|
||||||
friend class Image;
|
friend class Image;
|
||||||
|
@ -209,6 +216,8 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Inputs
|
// Inputs
|
||||||
|
Monitor *monitor;
|
||||||
|
|
||||||
int id;
|
int id;
|
||||||
char *label;
|
char *label;
|
||||||
ZoneType type;
|
ZoneType type;
|
||||||
|
@ -228,30 +237,33 @@ protected:
|
||||||
int min_blobs;
|
int min_blobs;
|
||||||
int max_blobs;
|
int max_blobs;
|
||||||
|
|
||||||
// Outputs
|
// Outputs/Statistics
|
||||||
bool alarmed;
|
bool alarmed;
|
||||||
int alarm_pixels;
|
int alarm_pixels;
|
||||||
int alarm_filter_pixels;
|
int alarm_filter_pixels;
|
||||||
|
int alarm_blob_pixels;
|
||||||
int alarm_blobs;
|
int alarm_blobs;
|
||||||
|
int min_blob_size;
|
||||||
|
int max_blob_size;
|
||||||
Box alarm_box;
|
Box alarm_box;
|
||||||
unsigned int score;
|
unsigned int score;
|
||||||
Image *image;
|
Image *image;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void Setup( int p_id, const char *p_label, ZoneType p_type, const Box &p_limits, const Rgb p_alarm_rgb, int p_alarm_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 );
|
void Setup( Monitor *p_monitor, int p_id, const char *p_label, ZoneType p_type, const Box &p_limits, const Rgb p_alarm_rgb, int p_alarm_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 );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Zone( int p_id, const char *p_label, ZoneType p_type, const Box &p_limits, const Rgb p_alarm_rgb, int p_alarm_threshold=15, int p_min_alarm_pixels=50, int p_max_alarm_pixels=75000, const Coord &p_filter_box=Coord( 3, 3 ), int p_min_filter_pixels=50, int p_max_filter_pixels=50000, int p_min_blob_pixels=10, int p_max_blob_pixels=0, int p_min_blobs=0, int p_max_blobs=0 )
|
Zone( Monitor *p_monitor, int p_id, const char *p_label, ZoneType p_type, const Box &p_limits, const Rgb p_alarm_rgb, int p_alarm_threshold=15, int p_min_alarm_pixels=50, int p_max_alarm_pixels=75000, const Coord &p_filter_box=Coord( 3, 3 ), int p_min_filter_pixels=50, int p_max_filter_pixels=50000, int p_min_blob_pixels=10, int p_max_blob_pixels=0, int p_min_blobs=0, int p_max_blobs=0 )
|
||||||
{
|
{
|
||||||
Setup( p_id, p_label, p_type, p_limits, p_alarm_rgb, p_alarm_threshold, p_min_alarm_pixels, p_max_alarm_pixels, p_filter_box, p_min_filter_pixels, p_max_filter_pixels, p_min_blob_pixels, p_max_blob_pixels, p_min_blobs, p_max_blobs );
|
Setup( p_monitor, p_id, p_label, p_type, p_limits, p_alarm_rgb, p_alarm_threshold, p_min_alarm_pixels, p_max_alarm_pixels, p_filter_box, p_min_filter_pixels, p_max_filter_pixels, p_min_blob_pixels, p_max_blob_pixels, p_min_blobs, p_max_blobs );
|
||||||
}
|
}
|
||||||
Zone( int p_id, const char *p_label, const Box &p_limits, const Rgb p_alarm_rgb, int p_alarm_threshold=15, int p_min_alarm_pixels=50, int p_max_alarm_pixels=75000, const Coord &p_filter_box=Coord( 3, 3 ), int p_min_filter_pixels=50, int p_max_filter_pixels=50000, int p_min_blob_pixels=10, int p_max_blob_pixels=0, int p_min_blobs=0, int p_max_blobs=0 )
|
Zone( Monitor *p_monitor, int p_id, const char *p_label, const Box &p_limits, const Rgb p_alarm_rgb, int p_alarm_threshold=15, int p_min_alarm_pixels=50, int p_max_alarm_pixels=75000, const Coord &p_filter_box=Coord( 3, 3 ), int p_min_filter_pixels=50, int p_max_filter_pixels=50000, int p_min_blob_pixels=10, int p_max_blob_pixels=0, int p_min_blobs=0, int p_max_blobs=0 )
|
||||||
{
|
{
|
||||||
Setup( p_id, p_label, Zone::ACTIVE, p_limits, p_alarm_rgb, p_alarm_threshold, p_min_alarm_pixels, p_max_alarm_pixels, p_filter_box, p_min_filter_pixels, p_max_filter_pixels, p_min_blob_pixels, p_max_blob_pixels, p_min_blobs, p_max_blobs );
|
Setup( p_monitor, p_id, p_label, Zone::ACTIVE, p_limits, p_alarm_rgb, p_alarm_threshold, p_min_alarm_pixels, p_max_alarm_pixels, p_filter_box, p_min_filter_pixels, p_max_filter_pixels, p_min_blob_pixels, p_max_blob_pixels, p_min_blobs, p_max_blobs );
|
||||||
}
|
}
|
||||||
Zone( int p_id, const char *p_label, const Box &p_limits )
|
Zone( Monitor *p_monitor, int p_id, const char *p_label, const Box &p_limits )
|
||||||
{
|
{
|
||||||
Setup( p_id, p_label, Zone::INACTIVE, p_limits, RGB_BLACK, 0, 0, 0, Coord( 0, 0 ), 0, 0, 0, 0, 0, 0 );
|
Setup( p_monitor, p_id, p_label, Zone::INACTIVE, p_limits, RGB_BLACK, 0, 0, 0, Coord( 0, 0 ), 0, 0, 0, 0, 0, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -273,7 +285,19 @@ public:
|
||||||
{
|
{
|
||||||
return( alarmed );
|
return( alarmed );
|
||||||
}
|
}
|
||||||
static int Load( int monitor_id, int width, int height, Zone **&zones );
|
inline void ResetStats()
|
||||||
|
{
|
||||||
|
alarmed = false;
|
||||||
|
alarm_pixels = 0;
|
||||||
|
alarm_filter_pixels = 0;
|
||||||
|
alarm_blob_pixels = 0;
|
||||||
|
alarm_blobs = 0;
|
||||||
|
min_blob_size = 0;
|
||||||
|
max_blob_size = 0;
|
||||||
|
score = 0;
|
||||||
|
}
|
||||||
|
void RecordStats( const Event *event );
|
||||||
|
static int Load( Monitor *monitor, Zone **&zones );
|
||||||
};
|
};
|
||||||
|
|
||||||
class Camera;
|
class Camera;
|
||||||
|
@ -383,7 +407,7 @@ public:
|
||||||
static Image *Merge( int n_images, Image *images[], double weight );
|
static Image *Merge( int n_images, Image *images[], double weight );
|
||||||
static Image *Highlight( int n_images, Image *images[], const Rgb threshold=RGB_BLACK, const Rgb ref_colour=RGB_RED );
|
static Image *Highlight( int n_images, Image *images[], const Rgb threshold=RGB_BLACK, const Rgb ref_colour=RGB_RED );
|
||||||
Image *Delta( const Image &image, bool absolute=true ) const;
|
Image *Delta( const Image &image, bool absolute=true ) const;
|
||||||
unsigned int CheckAlarms( Zone *zone, const Image *delta_image ) const;
|
bool CheckAlarms( Zone *zone, const Image *delta_image ) const;
|
||||||
unsigned int Compare( const Image &image, int n_zones, Zone *zones[] ) const;
|
unsigned int Compare( const Image &image, int n_zones, Zone *zones[] ) const;
|
||||||
void Annotate( const char *text, const Coord &coord, const Rgb colour );
|
void Annotate( const char *text, const Coord &coord, const Rgb colour );
|
||||||
void Annotate( const char *text, const Coord &coord );
|
void Annotate( const char *text, const Coord &coord );
|
||||||
|
@ -402,8 +426,8 @@ protected:
|
||||||
int device;
|
int device;
|
||||||
int channel;
|
int channel;
|
||||||
int format;
|
int format;
|
||||||
int width;
|
unsigned int width;
|
||||||
int height;
|
unsigned int height;
|
||||||
int colours;
|
int colours;
|
||||||
bool capture;
|
bool capture;
|
||||||
|
|
||||||
|
@ -427,6 +451,9 @@ public:
|
||||||
{
|
{
|
||||||
return( name );
|
return( name );
|
||||||
}
|
}
|
||||||
|
unsigned int Width() const { return( width ); }
|
||||||
|
unsigned int Height() const { return( height ); }
|
||||||
|
|
||||||
static void Initialise( int device, int channel, int format, int width, int height, int colours );
|
static void Initialise( int device, int channel, int format, int width, int height, int colours );
|
||||||
void Terminate();
|
void Terminate();
|
||||||
|
|
||||||
|
@ -516,6 +543,11 @@ protected:
|
||||||
public:
|
public:
|
||||||
Event( Monitor *p_monitor, time_t p_start_time );
|
Event( Monitor *p_monitor, time_t p_start_time );
|
||||||
~Event();
|
~Event();
|
||||||
|
|
||||||
|
int Id() const { return( id ); }
|
||||||
|
int Frames() const { return( frames ); }
|
||||||
|
int AlarmFrames() const { return( alarm_frames ); }
|
||||||
|
|
||||||
void AddFrame( time_t timestamp, const Image *image, const Image *alarm_frame=NULL, unsigned int score=0 );
|
void AddFrame( time_t timestamp, const Image *image, const Image *alarm_frame=NULL, unsigned int score=0 );
|
||||||
|
|
||||||
static void StreamEvent( const char *path, int event_id, unsigned long refresh=100, FILE *fd=stdout );
|
static void StreamEvent( const char *path, int event_id, unsigned long refresh=100, FILE *fd=stdout );
|
||||||
|
@ -578,10 +610,14 @@ protected:
|
||||||
|
|
||||||
SharedImages *shared_images;
|
SharedImages *shared_images;
|
||||||
|
|
||||||
|
bool record_zone_stats;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Monitor( int p_id, char *p_name, int p_function, int p_device, int p_channel, int p_format, int p_width, int p_height, int p_colours, bool p_capture, char *p_label_format, const Coord &p_label_coord, int p_warmup_count, int p_pre_event_count, int p_post_event_count, int p_alarm_frame_count, int p_image_buffer_count, int p_fps_report_interval, int p_ref_blend_perc, int p_n_zones=0, Zone *p_zones[]=0 );
|
Monitor( int p_id, char *p_name, int p_function, int p_device, int p_channel, int p_format, int p_width, int p_height, int p_colours, bool p_capture, char *p_label_format, const Coord &p_label_coord, int p_warmup_count, int p_pre_event_count, int p_post_event_count, int p_alarm_frame_count, int p_image_buffer_count, int p_fps_report_interval, int p_ref_blend_perc, int p_n_zones=0, Zone *p_zones[]=0 );
|
||||||
~Monitor();
|
~Monitor();
|
||||||
|
|
||||||
|
void AddZones( int p_n_zones, Zone *p_zones[] );
|
||||||
|
|
||||||
State GetState() const;
|
State GetState() const;
|
||||||
int GetImage( int index=-1 ) const;
|
int GetImage( int index=-1 ) const;
|
||||||
time_t GetTimestamp( int index=-1 ) const;
|
time_t GetTimestamp( int index=-1 ) const;
|
||||||
|
|
18
src/zma.cpp
18
src/zma.cpp
|
@ -21,6 +21,12 @@
|
||||||
|
|
||||||
bool reload = false;
|
bool reload = false;
|
||||||
|
|
||||||
|
void die_handler( int signal )
|
||||||
|
{
|
||||||
|
Info(( "Got signal %d, crashing", signal ));
|
||||||
|
exit( signal );
|
||||||
|
}
|
||||||
|
|
||||||
void hup_handler( int signal )
|
void hup_handler( int signal )
|
||||||
{
|
{
|
||||||
Info(( "Got HUP signal, reloading" ));
|
Info(( "Got HUP signal, reloading" ));
|
||||||
|
@ -63,17 +69,27 @@ int main( int argc, const char *argv[] )
|
||||||
int n_monitors = Monitor::Load( device, monitors, false );
|
int n_monitors = Monitor::Load( device, monitors, false );
|
||||||
|
|
||||||
Info(( "Warming up" ));
|
Info(( "Warming up" ));
|
||||||
|
|
||||||
sigset_t block_set;
|
sigset_t block_set;
|
||||||
sigemptyset( &block_set );
|
sigemptyset( &block_set );
|
||||||
struct sigaction action, old_action;
|
struct sigaction action, old_action;
|
||||||
|
|
||||||
action.sa_handler = hup_handler;
|
action.sa_handler = hup_handler;
|
||||||
action.sa_mask = block_set;
|
action.sa_mask = block_set;
|
||||||
action.sa_flags = 0;
|
action.sa_flags = 0;
|
||||||
sigaction( SIGHUP, &action, &old_action );
|
sigaction( SIGHUP, &action, &old_action );
|
||||||
|
|
||||||
action.sa_handler = term_handler;
|
action.sa_handler = term_handler;
|
||||||
action.sa_mask = block_set;
|
action.sa_mask = block_set;
|
||||||
action.sa_flags = 0;
|
action.sa_flags = 0;
|
||||||
sigaction( SIGTERM, &action, &old_action );
|
sigaction( SIGTERM, &action, &old_action );
|
||||||
|
|
||||||
|
action.sa_handler = die_handler;
|
||||||
|
action.sa_mask = block_set;
|
||||||
|
action.sa_flags = 0;
|
||||||
|
sigaction( SIGBUS, &action, &old_action );
|
||||||
|
sigaction( SIGSEGV, &action, &old_action );
|
||||||
|
|
||||||
sigaddset( &block_set, SIGHUP );
|
sigaddset( &block_set, SIGHUP );
|
||||||
//sigaddset( &block_set, SIGTERM );
|
//sigaddset( &block_set, SIGTERM );
|
||||||
while( 1 )
|
while( 1 )
|
||||||
|
@ -97,7 +113,9 @@ int main( int argc, const char *argv[] )
|
||||||
{
|
{
|
||||||
for ( int i = 0; i < n_monitors; i++ )
|
for ( int i = 0; i < n_monitors; i++ )
|
||||||
{
|
{
|
||||||
|
Mark();
|
||||||
monitors[i]->ReloadZones();
|
monitors[i]->ReloadZones();
|
||||||
|
Mark();
|
||||||
monitors[i]->CheckFunction();
|
monitors[i]->CheckFunction();
|
||||||
}
|
}
|
||||||
reload = false;
|
reload = false;
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
#define Fatal(params) DbgPrintf(DBG_FAT,params)
|
#define Fatal(params) DbgPrintf(DBG_FAT,params)
|
||||||
#define Entrypoint(params) DbgPrintf(9,params);
|
#define Entrypoint(params) DbgPrintf(9,params);
|
||||||
#define Exitpoint(params) DbgPrintf(9,params);
|
#define Exitpoint(params) DbgPrintf(9,params);
|
||||||
#define Mark() Info(("Mark"))
|
#define Mark() Info(("Mark/%s/%d", __FILE__, __LINE__ ))
|
||||||
#define Log() Info(("Log"))
|
#define Log() Info(("Log"))
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#define Enter(level) DbgPrintf(level,("Entering %s",__PRETTY_FUNCTION__))
|
#define Enter(level) DbgPrintf(level,("Entering %s",__PRETTY_FUNCTION__))
|
||||||
|
|
Loading…
Reference in New Issue