summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeokHoon Lee <andy.shlee@samsung.com>2015-12-01 16:40:12 +0900
committerSeokHoon Lee <andy.shlee@samsung.com>2015-12-04 11:44:41 +0900
commit18434240eefdbcf2727d3f07a399a36dbd8caa64 (patch)
tree8420e27d875e844e5091020db1174898644d138b
parentee608e5cbcbae6c8ee6258ca68e7f0b42c1b68a8 (diff)
downloadmediavision-18434240eefdbcf2727d3f07a399a36dbd8caa64.tar.gz
mediavision-18434240eefdbcf2727d3f07a399a36dbd8caa64.tar.bz2
mediavision-18434240eefdbcf2727d3f07a399a36dbd8caa64.zip
Signed-off-by: SeokHoon Lee <andy.shlee@samsung.com> Change-Id: I4f6596a891c7bda729b70bd026026c224974fdc3
-rw-r--r--AUTHORS2
-rw-r--r--CMakeLists.txt18
-rw-r--r--doc/mediavision_doc.h126
-rw-r--r--include/mv_surveillance.h1154
-rw-r--r--include/mv_surveillance_private.h48
-rw-r--r--media-vision-config.json15
-rw-r--r--mv_surveillance/CMakeLists.txt8
-rw-r--r--mv_surveillance/surveillance/CMakeLists.txt26
-rw-r--r--mv_surveillance/surveillance/include/EventDefs.h71
-rw-r--r--mv_surveillance/surveillance/include/EventManager.h190
-rw-r--r--mv_surveillance/surveillance/include/EventResult.h59
-rw-r--r--mv_surveillance/surveillance/include/EventTrigger.h227
-rw-r--r--mv_surveillance/surveillance/include/EventTriggerMovementDetection.h159
-rw-r--r--mv_surveillance/surveillance/include/EventTriggerPersonAppearance.h211
-rw-r--r--mv_surveillance/surveillance/include/EventTriggerPersonRecognition.h192
-rw-r--r--mv_surveillance/surveillance/include/HoGDetector.h194
-rw-r--r--mv_surveillance/surveillance/include/SurveillanceHelper.h70
-rw-r--r--mv_surveillance/surveillance/include/mv_absdiff.h56
-rw-r--r--mv_surveillance/surveillance/include/mv_apply_mask.h56
-rw-r--r--mv_surveillance/surveillance/include/mv_mask_buffer.h55
-rw-r--r--mv_surveillance/surveillance/include/mv_surveillance_open.h194
-rw-r--r--mv_surveillance/surveillance/src/EventManager.cpp410
-rw-r--r--mv_surveillance/surveillance/src/EventTrigger.cpp197
-rw-r--r--mv_surveillance/surveillance/src/EventTriggerMovementDetection.cpp290
-rw-r--r--mv_surveillance/surveillance/src/EventTriggerPersonAppearance.cpp460
-rw-r--r--mv_surveillance/surveillance/src/EventTriggerPersonRecognition.cpp397
-rw-r--r--mv_surveillance/surveillance/src/HoGDetector.cpp1006
-rw-r--r--mv_surveillance/surveillance/src/SurveillanceHelper.cpp200
-rw-r--r--mv_surveillance/surveillance/src/mv_absdiff.c81
-rw-r--r--mv_surveillance/surveillance/src/mv_apply_mask.c77
-rw-r--r--mv_surveillance/surveillance/src/mv_mask_buffer.c89
-rw-r--r--mv_surveillance/surveillance/src/mv_surveillance_open.cpp140
-rw-r--r--mv_surveillance/surveillance_lic/CMakeLists.txt25
-rw-r--r--mv_surveillance/surveillance_lic/include/mv_surveillance_lic.h187
-rw-r--r--mv_surveillance/surveillance_lic/src/mv_surveillance_lic.c63
-rw-r--r--packaging/capi-media-vision.spec13
-rw-r--r--src/mv_surveillance.c363
-rw-r--r--test/testsuites/CMakeLists.txt1
-rw-r--r--test/testsuites/surveillance/CMakeLists.txt31
-rw-r--r--test/testsuites/surveillance/surveillance_test_suite.c1137
40 files changed, 8292 insertions, 6 deletions
diff --git a/AUTHORS b/AUTHORS
index 14ccbdac..c0960577 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,4 +1,3 @@
-ByungWook Jang <bw.jang at samsung dot com>
Tae-Young Chung <ty83.chung at samsung dot com>
Oleg Kopysov <o.kopysov at samsung dot com>
Ievgen Vagin <i.vagin at samsung dot com>
@@ -6,3 +5,4 @@ Anton Artyukh <a.artyukh at samsung dot com>
Yaroslav Zatsikha <y.zatsikha at samsung dot com>
Sergii Rudenko <s.rudenko at samsung dot com>
SeokHoon Lee <andy.shlee at samsung dot com>
+Heechul Jeon <heechul.jeon at samsung dot com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8452d0a4..2ec1ac79 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,6 +19,8 @@ option(MEDIA_VISION_IMAGE_LICENSE_PORT
"Turn on building of licensed port of the image module (if OFF - open port will be built)." OFF)
option(MEDIA_VISION_FACE_LICENSE_PORT
"Turn on building of licensed port of the face module (if OFF - open port will be built)." OFF)
+option(MEDIA_VISION_SURVEILLANCE_LICENSE_PORT
+ "Turn on building of licensed port of the surveillance module (if OFF - open port will be built)." OFF)
set(MV_COMMON_LIB_NAME "mv_common")
set(MV_BARCODE_DETECTOR_LIB_NAME "mv_barcode_detector" CACHE STRING
@@ -29,6 +31,8 @@ set(MV_IMAGE_LIB_NAME "mv_image" CACHE STRING
"Name of the library will be built for image module (without extension).")
set(MV_FACE_LIB_NAME "mv_face" CACHE STRING
"Name of the library will be built for barcode generating module (without extension).")
+set(MV_SURVEILLANCE_LIB_NAME "mv_surveillance" CACHE STRING
+ "Name of the library will be built for surveillance module (without extension).")
SET(INC_DIR "${PROJECT_SOURCE_DIR}/include")
@@ -64,12 +68,20 @@ else()
SET(INC_FACE "${PROJECT_SOURCE_DIR}/mv_face/face/include")
endif()
+if(MEDIA_VISION_SURVEILLANCE_LICENSE_PORT)
+ add_definitions(-DMEDIA_VISION_SURVEILLANCE_LICENSE_PORT)
+ SET(INC_SURVEILLANCE "${PROJECT_SOURCE_DIR}/mv_surveillance/surveillance_lic/include")
+else()
+ SET(INC_SURVEILLANCE "${PROJECT_SOURCE_DIR}/mv_surveillance/surveillance/include")
+endif()
+
INCLUDE_DIRECTORIES(${INC_DIR}
${INC_COMMON}
${INC_BARCODE_DETECTOR}
${INC_BARCODE_GENERATOR}
${INC_FACE}
- ${INC_IMAGE})
+ ${INC_IMAGE}
+ ${INC_SURVEILLANCE})
SET(dependents "dlog capi-media-tool capi-system-info capi-appfw-application")
SET(pc_dependents "dlog")
@@ -100,6 +112,7 @@ ADD_SUBDIRECTORY(mv_common)
ADD_SUBDIRECTORY(mv_barcode)
ADD_SUBDIRECTORY(mv_image)
ADD_SUBDIRECTORY(mv_face)
+ADD_SUBDIRECTORY(mv_surveillance)
aux_source_directory(src SOURCES)
ADD_LIBRARY(${fw_name} SHARED ${SOURCES})
@@ -109,7 +122,8 @@ TARGET_LINK_LIBRARIES(${fw_name} ${MV_COMMON_LIB_NAME}
${MV_BARCODE_GENERATOR_LIB_NAME}
${MV_IMAGE_LIB_NAME}
${MV_FACE_LIB_NAME}
- ${${fw_name}_LDFLAGS})
+ ${${fw_name}_LDFLAGS}
+ ${MV_SURVEILLANCE_LIB_NAME})
SET_TARGET_PROPERTIES(${fw_name}
PROPERTIES
diff --git a/doc/mediavision_doc.h b/doc/mediavision_doc.h
index b7ab18de..8402b851 100644
--- a/doc/mediavision_doc.h
+++ b/doc/mediavision_doc.h
@@ -24,13 +24,16 @@
* * Face detection, recognition, and tracking;\n
* * Barcode detection and generation;\n
* * Flat Image detection, recognition and tracking;\n
- * * Flat Image features extraction.
+ * * Flat Image features extraction;\n
+ * * Surveillance: movement detection, person appearance/disappearance,
+ * person recognition.
*
* @defgroup CAPI_MEDIA_VISION_COMMON_MODULE Media Vision Common
* @ingroup CAPI_MEDIA_VISION_MODULE
* @brief Common functions and enumerations used in
* @ref CAPI_MEDIA_VISION_FACE_MODULE,
- * @ref CAPI_MEDIA_VISION_IMAGE_MODULE and
+ * @ref CAPI_MEDIA_VISION_IMAGE_MODULE,
+ * @ref CAPI_MEDIA_VISION_SURVEILLANCE_MODULE and
* @ref CAPI_MEDIA_VISION_BARCODE_MODULE submodules.
* @section CAPI_MEDIA_VISION_COMMON_MODULE_HEADER Required Header
* \#include <mv_common.h>
@@ -247,6 +250,125 @@
* For QR codes it is possible to specify error correction code and encoding
* mode (see @ref mv_barcode_qr_mode_e). Generation to file supports several
* formats (see @ref mv_barcode_image_format_e).
+ *
+ * @defgroup CAPI_MEDIA_VISION_SURVEILLANCE_MODULE Media Vision Surveillance
+ * @ingroup CAPI_MEDIA_VISION_MODULE
+ * @brief Video surveillance module.
+ * @section CAPI_MEDIA_VISION_SURVEILLANCE_MODULE_HEADER Required Header
+ * \#include <mv_surveillance.h>
+ *
+ * @section CAPI_MEDIA_VISION_SURVEILLANCE_MODULE_FEATURE Related Features
+ * This API is related with the following features:\n
+ * - http://tizen.org/feature/vision.image_recognition\n
+ * - http://tizen.org/feature/vision.face_recognition\n
+ *
+ * It is recommended to design feature related codes in your application for
+ * reliability.\n
+ * You can check if a device supports the related features for this API by using
+ * @ref CAPI_SYSTEM_SYSTEM_INFO_MODULE, thereby controlling the procedure of
+ * your application.\n
+ * To ensure your application is only running on the device with specific
+ * features, please define the features in your manifest file using the manifest
+ * editor in the SDK.\n
+ * More details on featuring your application can be found from
+ * <a href="https://developer.tizen.org/development/tools/native-tools/manifest-text-editor#feature">
+ * <b>Feature Element</b>.
+ * </a>
+ *
+ * @section CAPI_MEDIA_VISION_SURVEILLANCE_MODULE_OVERVIEW Overview
+ * @ref CAPI_MEDIA_VISION_SURVEILLANCE_MODULE provides functionality can be
+ * utilized for creation of video surveillance systems. The main idea underlying
+ * surveillance is event subscription model. By default, supported event types
+ * are described in @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES section.
+ * @ref mv_surveillance_subscribe_event_trigger() function has to be used to
+ * create subscription to the particular event trigger. Triggers are handled by
+ * @ref mv_surveillance_event_trigger_h type. Such type handlers can be created
+ * with @ref mv_surveillance_event_trigger_create() function and destroyed with
+ * @ref mv_surveillance_event_trigger_destroy() function. Once event trigger
+ * subscription is created, corresponding @ref mv_surveillance_event_occurred_cb
+ * callback will be invoked each time when event is detected, i.e. trigger is
+ * activated. @ref mv_surveillance_result_h event detection result handler will
+ * be passed to the callback together with identifier of the video stream where
+ * event was detected and @ref mv_source_h handler containing frame in which
+ * detection was performed. It is possible to retrieve specific to event type
+ * result values using @ref mv_surveillance_result_h handler. In the
+ * @ref mv_surveillance_get_result_value() function documentation can be found
+ * detailed description of result values retrieving. Following table contains
+ * general events and corresponding event detection results can be obtained by
+ * this approach:
+ * <table>
+ * <tr>
+ * <td><b>Event</b></td>
+ * <td><b>Event result values</b></td>
+ * </tr>
+ * <tr>
+ * <td>@ref MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED</td>
+ * <td>
+ * @ref MV_SURVEILLANCE_MOVEMENT_NUMBER_OF_REGIONS;<br>
+ * @ref MV_SURVEILLANCE_MOVEMENT_REGIONS
+ * </td>
+ * </tr>
+ * <tr>
+ * <td>@ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED</td>
+ * <td>
+ * @ref MV_SURVEILLANCE_PERSONS_APPEARED_NUMBER;<br>
+ * @ref MV_SURVEILLANCE_PERSONS_DISAPPEARED_NUMBER;<br>
+ * @ref MV_SURVEILLANCE_PERSONS_TRACKED_NUMBER;<br>
+ * @ref MV_SURVEILLANCE_PERSONS_APPEARED_LOCATIONS;<br>
+ * @ref MV_SURVEILLANCE_PERSONS_DISAPPEARED_LOCATIONS;<br>
+ * @ref MV_SURVEILLANCE_PERSONS_TRACKED_LOCATIONS
+ * </td>
+ * </tr>
+ * <tr>
+ * <td>@ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED</td>
+ * <td>
+ * @ref MV_SURVEILLANCE_PERSONS_RECOGNIZED_NUMBER;<br>
+ * @ref MV_SURVEILLANCE_PERSONS_RECOGNIZED_LOCATIONS;<br>
+ * @ref MV_SURVEILLANCE_PERSONS_RECOGNIZED_LABELS;<br>
+ * @ref MV_SURVEILLANCE_PERSONS_RECOGNIZED_CONFIDENCES
+ * </td>
+ * </tr>
+ * </table>
+ * Before subscription of the event trigger with
+ * @ref mv_surveillance_subscribe_event_trigger() call it is possible to create
+ * @ref mv_engine_config_h handle and configurate following attributes:
+ * - @ref MV_SURVEILLANCE_SKIP_FRAMES_COUNT to setup number of frames will be
+ ignored by event trigger;
+ * - @ref MV_SURVEILLANCE_MOVEMENT_DETECTION_THRESHOLD to specify sensitivity of
+ * the @ref MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED event detection;
+ * - @ref MV_SURVEILLANCE_FACE_RECOGNITION_MODEL_FILE_PATH to specify the file
+ * where face recognition model to be used for recognition is stored.
+ *
+ * Created engine config has to be used as a parameter of
+ * @ref mv_surveillance_subscribe_event_trigger() to apply the configuration. If
+ * NULL will be passed instead of valid @ref mv_engine_config_h handle, then
+ * default attribute values will be used for subsriptions.
+ * To make surveillance system work with video sequences
+ * @ref mv_surveillance_push_source() function has to
+ * be used for each frame in the sequence in the correct order. Multiple video
+ * sources can be supported by the system. To distinguish different video
+ * sources unique stream identifier has to be assigned to each subscription.
+ * Then, particular identifier can be passed as a parameter to the
+ * @ref mv_surveillance_push_source() function. After pushing the source to the
+ * surveillance system, it will notify all triggers which were subscribed to
+ * process frames coming from video stream which source has been pushed.
+ * If trigger(s) is(are) activated on the source, then corresponding callback(s)
+ * of @ref mv_surveillance_event_occurred_cb type will be called.
+ * Additionally, region where event detection will be performed by the triggers
+ * can be set with @ref mv_surveillance_set_event_trigger_roi() function and
+ * gotten with @ref mv_surveillance_get_event_trigger_roi(). ROI is specified
+ * independently for the each event trigger, so it is possible to detect events
+ * of different types in the different parts of the incoming frames.
+ * Event trigger subscription can be stopped any time using
+ * @ref mv_surveillance_unsubscribe_event_trigger() function. Additionally,
+ * @ref mv_surveillance_foreach_supported_event_type() and
+ * @ref mv_surveillance_foreach_event_result_name() functions can be found
+ * useful if it is required to obtain supported event types list or result
+ * value names list dynamically.
+ *
+ * @defgroup CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES Media Vision Surveillance Event Types
+ * @ingroup CAPI_MEDIA_VISION_SURVEILLANCE_MODULE
+ * @brief Event types supported by the Surveillance module.
*/
#endif /* __TIZEN_MEDIAVISION_DOC_H__ */
diff --git a/include/mv_surveillance.h b/include/mv_surveillance.h
new file mode 100644
index 00000000..f17c77b6
--- /dev/null
+++ b/include/mv_surveillance.h
@@ -0,0 +1,1154 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TIZEN_MEDIAVISION_SURVEILLANCE_H__
+#define __TIZEN_MEDIAVISION_SURVEILLANCE_H__
+
+#include <mv_common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @file mv_surveillance.h
+ * @brief This file contains the Media Vision Surveillance API.
+ */
+
+/**
+ * @addtogroup CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES
+ * @{
+ */
+
+/**
+ * @brief Name of the movement detection event type.
+ * @details This is common event for a movement detection. When this event
+ * occurs @ref mv_surveillance_result_h allowed from callback can be
+ * used to get number of regions where movement has been detected and
+ * their positions. Out parameters (can be accessed in the
+ * @ref mv_surveillance_event_occurred_cb callback using
+ * @ref mv_surveillance_get_result_value() function):
+ * * @ref MV_SURVEILLANCE_MOVEMENT_NUMBER_OF_REGIONS - the number
+ * of regions where movement has been detected;\n
+ * * @ref MV_SURVEILLANCE_MOVEMENT_REGIONS - the set
+ * of rectangular regions where movement has been detected.
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED \
+ "MV_SURVEILLANCE_EVENT_MOVEMENT_DETECTED"
+
+/**
+ * @brief Name of the event result value that contains number of regions where
+ * movement was detected.
+ * @details This event result value can be accessed after event triggers of
+ * @ref MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED type activation.
+ * Result value is of @c size_t type, so has to be casted as in the
+ * following example:
+ * @code{.c}
+ * void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ * mv_source_h source,
+ * int video_stream_id,
+ * mv_surveillance_result_h event_result,
+ * void *user_data)
+ * {
+ * const char *event_type = NULL;
+ * int err = mv_surveillance_get_event_trigger_type(trigger,
+ * event_type);
+ * if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ * if (0 == strncmp(event_type,
+ * MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED,
+ * 255))
+ * {
+ * size_t move_regions_num = 0;
+ * err = mv_surveillance_get_result_value(
+ * event_result,
+ * MV_SURVEILLANCE_MOVEMENT_NUMBER_OF_REGIONS,
+ * &move_regions_num);
+ * if (MEDIA_VISION_ERROR_NONE != err)
+ * return;
+ *
+ * // Do something with number of regions where movement
+ * // was detected...
+ * }
+ * }
+ * @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_MOVEMENT_NUMBER_OF_REGIONS \
+ "NUMBER_OF_MOVEMENT_REGIONS"
+
+/**
+ * @brief Name of the event result value that contains rectangular regions where
+ * movement was detected.
+ * @details This event result value can be accessed after event triggers of
+ * @ref MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED type activation.
+ * Result value is of @a mv_rectangle_s array type, so has to be casted
+ * as in the following example:
+ * @code{.c}
+ * void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ * mv_source_h source,
+ * int video_stream_id,
+ * mv_surveillance_result_h event_result,
+ * void *user_data)
+ * {
+ * const char *event_type = NULL;
+ * int err = mv_surveillance_get_event_trigger_type(trigger,
+ * event_type);
+ * if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ * if (0 == strncmp(event_type,
+ * MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED,
+ * 255))
+ * {
+ * size_t move_regions_num = 0;
+ * err = mv_surveillance_get_result_value(
+ * event_result,
+ * MV_SURVEILLANCE_MOVEMENT_NUMBER_OF_REGIONS,
+ * &move_regions_num);
+ *
+ * if (MEDIA_VISION_ERROR_NONE != err || 0 == move_regions_num)
+ * return;
+ *
+ * mv_rectangle_s *regions =
+ * (mv_rectangle_s*)
+ * malloc(sizeof(mv_rectangle_s) * move_regions_num);
+ * err = mv_surveillance_get_result_value(
+ * event_result,
+ * MV_SURVEILLANCE_MOVEMENT_REGIONS,
+ * regions);
+ *
+ * // Do something with movement regions...
+ *
+ * free (regions);
+ * }
+ * }
+ * @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_MOVEMENT_REGIONS "MOVEMENT_REGIONS"
+
+/**
+ * @brief Name of the person appearance/disappearance event type.
+ * @details This is common event for a person appearing (disappearing).
+ * The result will be:
+ * * a number of persons, which were appeared and their positions;\n
+ * * a number of persons, which were tracked and their positions;\n
+ * * a number of persons, which were disappeared and their last
+ * positions.\n
+ * For the first time when a source is loaded, a result should contain
+ * all detected persons (detection will be made using face detection
+ * API). Next time when the source should be loaded, the previously
+ * detected persons will be tracked and new persons will be detected.
+ * For the previously detected persons their locations will be updated.
+ * Out parameters (can be accessed in the
+ * @ref mv_surveillance_event_occurred_cb callback using
+ * @ref mv_surveillance_get_result_value() function):
+ * * @ref MV_SURVEILLANCE_PERSONS_APPEARED_NUMBER - the number
+ * of persons which were appeared;\n
+ * * @ref MV_SURVEILLANCE_PERSONS_APPEARED_LOCATIONS - the locations
+ * of persons which were appeared;\n
+ * * @ref MV_SURVEILLANCE_PERSONS_TRACKED_NUMBER - the number
+ * of persons which were tracked;\n
+ * * @ref MV_SURVEILLANCE_PERSONS_TRACKED_LOCATIONS - the locations
+ * of persons which were tracked;\n
+ * * @ref MV_SURVEILLANCE_PERSONS_DISAPPEARED_NUMBER - the number
+ * of persons which were disappeared;\n
+ * * @ref MV_SURVEILLANCE_PERSONS_DISAPPEARED_LOCATIONS - the locations
+ * of persons which were disappeared.
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED \
+ "MV_SURVEILLANCE_EVENT_PERSON_APPEARED_DISAPEARED"
+
+/**
+ * @brief Name of the event result value that contains number
+ * of persons that have been appeared.
+ * @details This event result value can be accessed after event triggers of
+ * @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED type
+ * activation. Result value is of @c size_t type, so has to be casted
+ * as in the following example:
+ * @code{.c}
+ * void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ * mv_source_h source,
+ * int video_stream_id,
+ * mv_surveillance_result_h event_result,
+ * void *user_data)
+ * {
+ * const char *event_type = NULL;
+ * int err = mv_surveillance_get_event_trigger_type(trigger,
+ * event_type);
+ * if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ * if (0 == strncmp(event_type,
+ * MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED,
+ * 255))
+ * {
+ * size_t appear_person_num = 0;
+ * err = mv_surveillance_get_result_value(
+ * event_result,
+ * MV_SURVEILLANCE_PERSONS_APPEARED_NUMBER,
+ * &appear_person_num);
+ * if (MEDIA_VISION_ERROR_NONE != err)
+ * return;
+ *
+ * // Do something with number of appeared persons...
+ * }
+ * }
+ * @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_PERSONS_APPEARED_NUMBER \
+ "NUMBER_OF_APPEARED_PERSONS"
+
+/**
+ * @brief Name of the event result value that contains number
+ * of persons that have been disappeared.
+ * @details This event result value can be accessed after event triggers of
+ * @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED type
+ * activation. Result value is of @c size_t type, so has to be casted
+ * as in the following example:
+ * @code{.c}
+ * void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ * mv_source_h source,
+ * int video_stream_id,
+ * mv_surveillance_result_h event_result,
+ * void *user_data)
+ * {
+ * const char *event_type = NULL;
+ * int err = mv_surveillance_get_event_trigger_type(trigger,
+ * event_type);
+ * if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ * if (0 == strncmp(event_type,
+ * MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED,
+ * 255))
+ * {
+ * size_t disappear_person_num = 0;
+ * err = mv_surveillance_get_result_value(
+ * event_result,
+ * MV_SURVEILLANCE_PERSONS_DISAPPEARED_NUMBER,
+ * &disappear_person_num);
+ * if (MEDIA_VISION_ERROR_NONE != err)
+ * return;
+ *
+ * // Do something with number of disappeared persons...
+ * }
+ * }
+ * @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_PERSONS_DISAPPEARED_NUMBER \
+ "NUMBER_OF_DISAPPEARED_PERSONS"
+
+/**
+ * @brief Name of the event result value that contains number
+ * of persons that have been tracked.
+ * @details This event result value can be accessed after event triggers of
+ * @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED type
+ * activation. Result value is of @c size_t type, so has to be casted
+ * as in the following example:
+ * @code{.c}
+ * void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ * mv_source_h source,
+ * int video_stream_id,
+ * mv_surveillance_result_h event_result,
+ * void *user_data)
+ * {
+ * const char *event_type = NULL;
+ * int err = mv_surveillance_get_event_trigger_type(trigger,
+ * event_type);
+ * if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ * if (0 == strncmp(event_type,
+ * MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED,
+ * 255))
+ * {
+ * size_t tracked_person_num = 0;
+ * err = mv_surveillance_get_result_value(
+ * event_result,
+ * MV_SURVEILLANCE_PERSONS_TRACKED_NUMBER,
+ * &tracked_person_num);
+ * if (MEDIA_VISION_ERROR_NONE != err)
+ * return;
+ *
+ * // Do something with number of tracked persons...
+ * }
+ * }
+ * @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_PERSONS_TRACKED_NUMBER \
+ "NUMBER_OF_TRACKED_PERSONS"
+
+/**
+ * @brief Name of the event result value that contains a set of rectangular
+ * locations where appearances of the persons were detected.
+ * @details This event result value can be accessed after event triggers of
+ * @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED type
+ * activation. Result value is of @a mv_rectangle_s array type, so has
+ * to be casted as in the following example:
+ * @code{.c}
+ * void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ * mv_source_h source,
+ * int video_stream_id,
+ * mv_surveillance_result_h event_result,
+ * void *user_data)
+ * {
+ * const char *event_type = NULL;
+ * int err = mv_surveillance_get_event_trigger_type(trigger,
+ * event_type);
+ * if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ * if (0 == strncmp(event_type,
+ * MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED,
+ * 255))
+ * {
+ * size_t appear_person_num = 0;
+ * err = mv_surveillance_get_result_value(
+ * event_result,
+ * MV_SURVEILLANCE_PERSONS_APPEARED_NUMBER,
+ * &appear_person_num);
+ *
+ * if (MEDIA_VISION_ERROR_NONE != err ||
+ * 0 == appear_person_num) return;
+ *
+ * mv_rectangle_s *appear_locations =
+ * (mv_rectangle_s*)
+ * malloc(sizeof(mv_rectangle_s) * appear_person_num);
+ * err = mv_surveillance_get_result_value(
+ * event_result,
+ * MV_SURVEILLANCE_PERSONS_APPEARED_LOCATIONS,
+ * appear_locations);
+ *
+ * // Do something with locations where persons were
+ * // appeared...
+ *
+ * free (appear_locations);
+ * }
+ * }
+ * @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_PERSONS_APPEARED_LOCATIONS \
+ "APPEARED_PERSONS_LOCATIONS"
+
+/**
+ * @brief Name of the event result value that contains a set of rectangular
+ * locations where disappearances of the persons were detected.
+ * @details This event result value can be accessed after event triggers of
+ * @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED type
+ * activation. Result value is of @a mv_rectangle_s array type, so has
+ * to be casted as in the following example:
+ * @code{.c}
+ * void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ * mv_source_h source,
+ * int video_stream_id,
+ * mv_surveillance_result_h event_result,
+ * void *user_data)
+ * {
+ * const char *event_type = NULL;
+ * int err = mv_surveillance_get_event_trigger_type(trigger,
+ * event_type);
+ * if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ * if (0 == strncmp(event_type,
+ * MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED,
+ * 255))
+ * {
+ * size_t disappear_person_num = 0;
+ * err = mv_surveillance_get_result_value(
+ * event_result,
+ * MV_SURVEILLANCE_PERSONS_DISAPPEARED_NUMBER,
+ * &disappear_person_num);
+ *
+ * if (MEDIA_VISION_ERROR_NONE != err ||
+ * 0 == disappear_person_num) return;
+ *
+ * mv_rectangle_s *disappear_locations =
+ * (mv_rectangle_s*)
+ * malloc(sizeof(mv_rectangle_s) * disappear_person_num);
+ * err = mv_surveillance_get_result_value(
+ * event_result,
+ * MV_SURVEILLANCE_PERSONS_DISAPPEARED_LOCATIONS,
+ * disappear_locations);
+ *
+ * // Do something with locations where persons were
+ * // disappeared...
+ *
+ * free (disappear_locations);
+ * }
+ * }
+ * @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_PERSONS_DISAPPEARED_LOCATIONS \
+ "DISAPPEARED_PERSONS_LOCATIONS"
+
+/**
+ * @brief Name of the event result value that contains a set of rectangular
+ * locations where persons were tracked.
+ * @details This event result value can be accessed after event triggers of
+ * @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED type
+ * activation. Result value is of @a mv_rectangle_s array type, so has
+ * to be casted as in the following example:
+ * @code{.c}
+ * void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ * mv_source_h source,
+ * int video_stream_id,
+ * mv_surveillance_result_h event_result,
+ * void *user_data)
+ * {
+ * const char *event_type = NULL;
+ * int err = mv_surveillance_get_event_trigger_type(trigger,
+ * event_type);
+ * if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ * if (0 == strncmp(event_type,
+ * MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED,
+ * 255))
+ * {
+ * size_t tracked_person_num = 0;
+ * err = mv_surveillance_get_result_value(
+ * event_result,
+ * MV_SURVEILLANCE_PERSONS_TRACKED_NUMBER,
+ * &tracked_person_num);
+ *
+ * if (MEDIA_VISION_ERROR_NONE != err || 0 == tracked_person_num)
+ * return;
+ *
+ * mv_rectangle_s *track_locations =
+ * (mv_rectangle_s*)
+ * malloc(sizeof(mv_rectangle_s) * tracked_person_num);
+ * err = mv_surveillance_get_result_value(
+ * event_result,
+ * MV_SURVEILLANCE_PERSONS_TRACKED_LOCATIONS,
+ * track_locations);
+ *
+ * // Do something with locations where persons were tracked...
+ *
+ * free (track_locations);
+ * }
+ * }
+ * @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_PERSONS_TRACKED_LOCATIONS \
+ "TRACKED_PERSONS_LOCATIONS"
+
+/**
+ * @brief Name of the person recognition event type.
+ *
+ * @details This is common event for a person recognizing. The result will be
+ * a number of persons, which were recognized, their positions (face
+ * locations), labels and confidences of the recognition models (see
+ * documentation for @ref mv_face_recognize() in
+ * @ref CAPI_MEDIA_VISION_FACE_MODULE). When one subscribes to this
+ * event, the engine configuration must be filled by path to the saved
+ * face recognition model. These path should be set using
+ * @ref mv_engine_config_set_string_attribute() as attribute named
+ * @ref MV_SURVEILLANCE_FACE_RECOGNITION_MODEL_FILE_PATH.
+ * See documentation for face recognition in
+ * @ref CAPI_MEDIA_VISION_FACE_MODULE and for engine configuration in
+ * @ref CAPI_MEDIA_VISION_COMMON_MODULE for details. Out parameters
+ * (can be accessed in the @ref mv_surveillance_event_occurred_cb
+ * callback using @ref mv_surveillance_get_result_value() function):
+ * * @ref MV_SURVEILLANCE_PERSONS_RECOGNIZED_NUMBER - the number
+ * of persons which were recognized;\n
+ * * @ref MV_SURVEILLANCE_PERSONS_RECOGNIZED_LOCATIONS - the locations
+ * of persons which were recognized;\n
+ * * @ref MV_SURVEILLANCE_PERSONS_RECOGNIZED_LABELS - the labels of
+ * persons which were recognized;\n
+ * * @ref MV_SURVEILLANCE_PERSONS_RECOGNIZED_CONFIDENCES -
+ * the confidences values that persons were recognized correctly.
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED \
+ "MV_SURVEILLANCE_EVENT_PERSON_RECOGNIZED"
+
+/**
+ * @brief Name of the event result value that contains number of locations where
+ * faces were recognized.
+ * @details This event result value can be accessed after event triggers of
+ * @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED type activation.
+ * Result value is of @c size_t type, so has to be casted as in
+ * the following example:
+ * @code{.c}
+ * void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ * mv_source_h source,
+ * int video_stream_id,
+ * mv_surveillance_result_h event_result,
+ * void *user_data)
+ * {
+ * const char *event_type = NULL;
+ * int err = mv_surveillance_get_event_trigger_type(trigger,
+ * event_type);
+ * if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ * if (0 == strncmp(event_type,
+ * MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED,
+ * 255))
+ * {
+ * size_t rec_person_num = 0;
+ * err = mv_surveillance_get_result_value(
+ * event_result,
+ * MV_SURVEILLANCE_PERSONS_RECOGNIZED_NUMBER,
+ * &rec_person_num);
+ * if (MEDIA_VISION_ERROR_NONE != err)
+ * return;
+ *
+ * // Do something with number of recognized persons...
+ * }
+ * }
+ * @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_PERSONS_RECOGNIZED_NUMBER \
+ "NUMBER_OF_PERSONS"
+
+/**
+ * @brief Name of the event result value that contains a set of rectangular
+ * locations where person faces were recognized.
+ * @details This event result value can be accessed after event triggers of
+ * @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED type activation.
+ * Result value is of @a mv_rectangle_s array type, so has to be casted
+ * as in the following example:
+ * @code{.c}
+ * void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ * mv_source_h source,
+ * int video_stream_id,
+ * mv_surveillance_result_h event_result,
+ * void *user_data)
+ * {
+ * const char *event_type = NULL;
+ * int err = mv_surveillance_get_event_trigger_type(trigger,
+ * event_type);
+ * if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ * if (0 == strncmp(event_type,
+ * MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED,
+ * 255))
+ * {
+ * size_t rec_person_num = 0;
+ * err = mv_surveillance_get_result_value(
+ * event_result,
+ * MV_SURVEILLANCE_PERSONS_RECOGNIZED_NUMBER,
+ * &rec_person_num);
+ * if (MEDIA_VISION_ERROR_NONE != err || 0 == rec_person_num)
+ * return;
+ *
+ * mv_rectangle_s *locations =
+ * (mv_rectangle_s*)
+ * malloc(sizeof(mv_rectangle_s) * rec_person_num);
+ * err = mv_surveillance_get_result_value(
+ * event_result,
+ * MV_SURVEILLANCE_PERSONS_RECOGNIZED_LOCATIONS,
+ * locations);
+ *
+ * // Do something with locations...
+ *
+ * free (locations);
+ * }
+ * }
+ * @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_PERSONS_RECOGNIZED_LOCATIONS \
+ "PERSONS_LOCATIONS"
+
+/**
+ * @brief Name of the event result value that contains a set of labels that
+ * correspond to the recognized persons.
+ * @details This event result value can be accessed after event triggers of
+ * @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED type activation.
+ * Result value is of integers array type, so has to be casted
+ * as in the following example:
+ * @code{.c}
+ * void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ * mv_source_h source,
+ * int video_stream_id,
+ * mv_surveillance_result_h event_result,
+ * void *user_data)
+ * {
+ * const char *event_type = NULL;
+ * int err = mv_surveillance_get_event_trigger_type(trigger,
+ * event_type);
+ * if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ * if (0 == strncmp(event_type,
+ * MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED,
+ * 255))
+ * {
+ * size_t rec_person_num = 0;
+ * err = mv_surveillance_get_result_value(
+ * event_result,
+ * MV_SURVEILLANCE_PERSONS_RECOGNIZED_NUMBER,
+ * &rec_person_num);
+ * if (MEDIA_VISION_ERROR_NONE != err || 0 == rec_person_num)
+ * return;
+ *
+ * int *labels =
+ * (int*)malloc(sizeof(int) * rec_person_num);
+ * err = mv_surveillance_get_result_value(
+ * event_result,
+ * MV_SURVEILLANCE_PERSONS_RECOGNIZED_LABELS,
+ * labels);
+ *
+ * // Do something with labels...
+ *
+ * free (labels);
+ * }
+ * }
+ * @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_PERSONS_RECOGNIZED_LABELS \
+ "PERSONS_LABELS"
+
+/**
+ * @brief Name of the event result value that contains a set of confidence
+ * values that correspond to the recognized persons.
+ * @details This event result value can be accessed after event triggers of
+ * @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED type activation.
+ * Result value is of doubles array type, so has to be casted
+ * as in the following example:
+ * @code{.c}
+ * void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ * mv_source_h source,
+ * int video_stream_id,
+ * mv_surveillance_result_h event_result,
+ * void *user_data)
+ * {
+ * const char *event_type = NULL;
+ * int err = mv_surveillance_get_event_trigger_type(trigger,
+ * event_type);
+ * if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ * if (0 == strncmp(event_type,
+ * MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED,
+ * 255))
+ * {
+ * size_t rec_person_num = 0;
+ * err = mv_surveillance_get_result_value(
+ * event_result,
+ * MV_SURVEILLANCE_PERSONS_RECOGNIZED_NUMBER,
+ * &rec_person_num);
+ * if (MEDIA_VISION_ERROR_NONE != err || 0 == rec_person_num)
+ * return;
+ *
+ * double *confidences =
+ * (double*)malloc(sizeof(double) * rec_person_num);
+ * err = mv_surveillance_get_result_value(
+ * event_result,
+ * MV_SURVEILLANCE_PERSONS_RECOGNIZED_CONFIDENCES,
+ * confidences);
+ *
+ * // Do something with confidences...
+ *
+ * free (confidences);
+ * }
+ * }
+ * @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_PERSONS_RECOGNIZED_CONFIDENCES \
+ "PERSONS_CONFIDENCES"
+
+/**
+ * @}
+ */
+
+/**
+ * @addtogroup CAPI_MEDIA_VISION_SURVEILLANCE_MODULE
+ * @{
+ */
+
+/**
+ * @brief Defines MV_SURVEILLANCE_FACE_RECOGNITION_MODEL_FILE_PATH to set face
+ * recognition model file path. It is an attribute of the engine
+ * configuration.
+ * @details This value HAS TO BE set in engine configuration before subscription
+ * on @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED event trigger
+ *
+ * @since_tizen 3.0
+ * @see mv_engine_config_set_string_attribute()
+ * @see mv_engine_config_get_string_attribute()
+ */
+#define MV_SURVEILLANCE_FACE_RECOGNITION_MODEL_FILE_PATH \
+ "MV_SURVEILLANCE_FACE_RECOGNITION_MODEL_FILE_PATH"
+
+/**
+ * @brief Defines MV_SURVEILLANCE_MOVEMENT_DETECTION_THRESOLD to set movement
+ * detection threshold. It is an attribute of the engine configuration.
+ * @details This value might be set in engine configuration before subscription
+ * on @ref MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED event trigger
+ * to specify sensitivity of the movement detector. This value has to
+ * be integer in 0..255 range where 255 means that no movements will
+ * be detected, and 0 means that all frame changes will be interpreted
+ * as movements. Default value is 10.
+ *
+ * @since_tizen 3.0
+ * @see mv_engine_config_set_int_attribute()
+ * @see mv_engine_config_get_int_attribute()
+ */
+#define MV_SURVEILLANCE_MOVEMENT_DETECTION_THRESHOLD \
+ "MV_SURVEILLANCE_MOVEMENT_DETECTION_THRESHOLD"
+
+/**
+ * @brief Defines MV_SURVEILLANCE_SKIP_FRAMES_COUNT to set how many frames
+ * will be skipped during push source. It is an attribute of the engine
+ * configuration.
+ * @details This integer value might be set in engine configuration to specify
+ * number of @ref mv_surveillance_push_source() function calls will be
+ * ignored by subscription of the event trigger. Default value is 0.
+ * It means that no frames will be skipped and all
+ * @ref mv_surveillance_push_source() function calls will be processed.
+ *
+ * @since_tizen 3.0
+ * @see mv_engine_config_set_int_attribute()
+ * @see mv_engine_config_get_int_attribute()
+ */
+#define MV_SURVEILLANCE_SKIP_FRAMES_COUNT "MV_SURVEILLANCE_SKIP_FRAMES_COUNT"
+
+/**
+ * @brief The handle to event trigger.
+ *
+ * @since_tizen 3.0
+ * @remarks See supported event types and their descriptions in
+ * @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES documentation
+ * section.
+ * Also the list of supported events can be obtained using
+ * @ref mv_surveillance_foreach_supported_event_type() function
+ */
+typedef void *mv_surveillance_event_trigger_h;
+
+/**
+ * @brief The handle to event trigger activation result.
+ * @details Result is a handle to the output values which are specific for each event.
+ * See the output values names in the event types descriptions located
+ * in @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES documentation
+ * section.
+ * Result values can be gotten by @ref mv_surveillance_get_result_value()
+ * function one by one in order specified in the event description (
+ * the same order of event value names is supported by
+ * @ref mv_surveillance_foreach_event_result_name() function).
+ * This pointer will be destroyed when
+ * @ref mv_surveillance_event_occurred_cb passed.
+ *
+ * @since_tizen 3.0
+ */
+typedef void *mv_surveillance_result_h;
+
+/**
+ * @brief Called when event trigger activation has been detected.
+ *
+ * @since_tizen 3.0
+ * @remarks Handle @a event_result is valid only inside callback
+ * @param [in] trigger The event trigger handle
+ * @param [in] source The handle to the media source
+ * @param [in] video_stream_id The identifier of the video source where event
+ * has been detected
+ * @param [in] event_result The event result passed from the
+ * @ref mv_surveillance_subscribe_event_trigger()
+ * @param [in] user_data The user data passed from the
+ * @ref mv_surveillance_subscribe_event_trigger()
+ * function
+ *
+ * @pre Callback can be invoked only after
+ * @ref mv_surveillance_subscribe_event_trigger()
+ * was called for particular event trigger.
+ *
+ * @see mv_surveillance_subscribe_event_trigger()
+ * @see mv_surveillance_unsubscribe_event_trigger()
+ */
+typedef void (*mv_surveillance_event_occurred_cb)(
+ mv_surveillance_event_trigger_h trigger,
+ mv_source_h source,
+ int video_stream_id,
+ mv_surveillance_result_h event_result,
+ void *user_data);
+
+/**
+ * @brief Called to get the information once for each supported event type.
+ *
+ * @since_tizen 3.0
+ * @remarks Don't release memory of @a event_type
+ * @param [in] event_type Character string containing name of the event type
+ * @param [in] user_data The user data passed from the
+ * @ref mv_surveillance_foreach_supported_event_type()
+ * function
+ * @return @c true to continue with the next iteration of the loop, \n
+ * otherwise @c false to break out of the loop
+ *
+ * @pre mv_surveillance_foreach_supported_event_type() will invoke this callback
+ * @see mv_surveillance_foreach_supported_event_type()
+ */
+typedef bool (*mv_surveillance_event_type_cb)(
+ const char *event_type,
+ void *user_data);
+
+/**
+ * @brief Called to get the result name from the triggered event.
+ *
+ * @since_tizen 3.0
+ * @remarks Don't release memory of @a value_name
+ * @param [in] name Character string containing the name of value that
+ * can be obtained from @ref mv_surveillance_result_h
+ * handle by @ref mv_surveillance_get_result_value()
+ * function
+ * @param [in] user_data The user data passed from the
+ * @ref mv_surveillance_foreach_event_result_name()
+ * function
+ * @return @c true to continue with the next iteration of the loop, \n
+ * otherwise @c false to break out of the loop
+ *
+ * @pre mv_surveillance_foreach_event_result_name() will invoke this
+ * callback
+ * @see mv_surveillance_foreach_event_result_name()
+ */
+typedef bool (*mv_surveillance_event_result_name_cb)(
+ const char *name,
+ void *user_data);
+
+/**
+ * @brief Creates surveillance event trigger handle.
+ *
+ * @since_tizen 3.0
+ * @remarks List of supported event types can be obtained by
+ * @ref mv_surveillance_foreach_supported_event_type function
+ * @remarks You must release @a trigger by using
+ * @ref mv_surveillance_event_trigger_destroy()
+ * @param [in] event_type Name of the event type to be supported by the
+ * @a trigger
+ * @param [out] trigger A new handle to the event trigger
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @see mv_surveillance_event_trigger_destroy()
+ * @see mv_surveillance_foreach_supported_event_type()
+ */
+int mv_surveillance_event_trigger_create(
+ const char *event_type,
+ mv_surveillance_event_trigger_h *trigger);
+
+/**
+ * @brief Destroys the surveillance event trigger handle and releases all its
+ * resources.
+ *
+ * @since_tizen 3.0
+ * @param [in] trigger The handle to the event trigger to be destroyed
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @see mv_surveillance_event_trigger_create
+ */
+int mv_surveillance_event_trigger_destroy(
+ mv_surveillance_event_trigger_h trigger);
+
+/**
+ * @brief Gets the surveillance event trigger type as character string.
+ *
+ * @since_tizen 3.0
+ * @remarks The @a event_type should be freed using free()
+ * @param [in] trigger The handle to the event trigger
+ * @param [out] event_type The pointer to the character string which will be
+ * filled by textual name of the event type
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @pre Event trigger has to be created by
+ * @ref mv_surveillance_event_trigger_create() function
+ */
+int mv_surveillance_get_event_trigger_type(
+ mv_surveillance_event_trigger_h trigger,
+ char **event_type);
+
+/**
+ * @brief Sets ROI (Region Of Interest) to the event trigger.
+ * @details When ROI is set for the event trigger, then event check for this
+ * @a triger will be performed only inside the polygonal region
+ * determined by @a roi parameter.
+ * If this method has been never called for the @a trigger, then event
+ * will be checked for the whole input frame (event check is performed
+ * for each @ref mv_surveillance_push_source() function call).
+ * It is possible to change the ROI between
+ * @ref mv_surveillance_push_source() calls.
+ *
+ * @since_tizen 3.0
+ * @param [in] trigger The handle to the event trigger
+ * @param [in] number_of_points The number of ROI points
+ * @param [in] roi The input array with ROI points
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @pre Event trigger has to be created by
+ * @ref mv_surveillance_event_trigger_create() function
+ *
+ * @see mv_surveillance_event_trigger_h
+ * @see mv_surveillance_get_event_trigger_roi()
+ */
+int mv_surveillance_set_event_trigger_roi(
+ mv_surveillance_event_trigger_h trigger,
+ int number_of_points,
+ mv_point_s *roi);
+
+/**
+ * @brief Gets ROI (Region Of Interest) from the event trigger.
+ *
+ * @since_tizen 3.0
+ * @remark If @ref mv_surveillance_set_event_trigger_roi() has been never
+ * called for @a trigger, then @a number_of_points output value will be
+ * zero and @a roi pointer will be not changed.
+ * @param [in] trigger The handle to the event trigger
+ * @param [out] number_of_points The number of ROI points
+ * @param [out] roi The output array with ROI points
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @pre Event trigger has to be created by
+ * @ref mv_surveillance_event_trigger_create() function
+ *
+ * @post Memory for @a roi array must be released
+ *
+ * @see mv_surveillance_event_trigger_h
+ * @see mv_surveillance_set_event_trigger_roi()
+ */
+int mv_surveillance_get_event_trigger_roi(
+ mv_surveillance_event_trigger_h trigger,
+ int *number_of_points,
+ mv_point_s **roi);
+
+/**
+ * @brief Subscribes @a trigger to process sources pushed from video identified
+ * by @a video_stream_id.
+ * @details When @a trigger is subscribed, then each time when function
+ * @ref mv_surveillance_push_source() is called for @a video_stream_id,
+ * event occurrence is checked. If this check is successful,
+ * @a callback is invoked. Details on occurred event can be obtained
+ * using @ref mv_surveillance_result_h handle from @a callback.
+ *
+ * @since_tizen 3.0
+ * @remarks Use @ref mv_surveillance_unsubscribe_event_trigger() function for
+ * the same @a trigger and @a video_stream_id parameters to stop
+ * subscription.
+ * @param [in] trigger The handle to the event trigger activating
+ * calls of the @a callback function
+ * @param [in] video_stream_id The identifier of the video stream for which
+ * event trigger activation will be checked
+ * @param [in] engine_cfg The engine configuration of the event
+ * @param [in] callback Callback to be called each time when event
+ * occurrence is detected
+ * @param [in] user_data The user data to be passed to the @a callback
+ * function
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @post @ref mv_surveillance_event_occurred_cb will be called each time
+ * @a trigger is activated after @ref mv_surveillance_push_source() call
+ *
+ * @see mv_surveillance_event_trigger_h
+ * @see mv_surveillance_unsubscribe_event_trigger()
+ * @see mv_surveillance_push_source()
+ */
+int mv_surveillance_subscribe_event_trigger(
+ mv_surveillance_event_trigger_h trigger,
+ int video_stream_id,
+ mv_engine_config_h engine_cfg,
+ mv_surveillance_event_occurred_cb callback,
+ void *user_data);
+
+/**
+ * @brief Unsubscribes @a trigger from the event and stop calling @a callback.
+ *
+ * @since_tizen 3.0
+ * @remarks To start handling trigger activation use
+ @ref mv_surveillance_subscribe_event_trigger().
+ * @param [in] trigger The handle to the event trigger for which
+ * subscription will be stopped
+ * @param [in] video_stream_id The identifier of the video source for which
+ * subscription will be stopped
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @pre To stop subscription it has to be created earlier with
+ * @ref mv_surveillance_subscribe_event_trigger() function
+ *
+ * @see mv_surveillance_event_trigger_h
+ * @see mv_surveillance_subscribe_event_trigger()
+ */
+int mv_surveillance_unsubscribe_event_trigger(
+ mv_surveillance_event_trigger_h trigger,
+ int video_stream_id);
+
+/**
+ * @brief Pushes source to the surveillance system to detect events.
+ * @details mv_surveillance_event_occurred_cb() will be called when any
+ * subscribing event detected.
+ *
+ * @since_tizen 3.0
+ * @remarks @ref mv_surveillance_set_event_trigger_roi() function can be used
+ * to specify the polygon region where event can be detected only
+ * @param [in] source The handle to the media source
+ * @param [in] video_stream_id The identifier of video stream from which
+ * @a source is coming
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @pre To receive surveillance results, some event triggers has to be
+ * subscribed by @ref mv_surveillance_subscribe_event_trigger() function
+ * before @ref mv_surveillance_push_source() calls
+ * @pre Before calling of this method @a source has to be correctly filled.
+ * @ref mv_source_fill_by_media_packet(), @ref mv_source_fill_by_buffer()
+ * functions can be used to fill @a source
+ *
+ * @see mv_surveillance_event_trigger_h
+ * @see mv_surveillance_event_occurred_cb
+ * @see mv_surveillance_subscribe_event_trigger()
+ * @see mv_surveillance_unsubscribe_event_trigger()
+ */
+int mv_surveillance_push_source(
+ mv_source_h source,
+ int video_stream_id);
+
+/**
+ * @brief Starts traversing through list of supported event types.
+ *
+ * @since_tizen 3.0
+ * @remarks Supported event types and their descriptions can be found in
+ * @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES documentation
+ * section
+ * @param [in] callback The callback function to be called for each
+ * supported event type
+ * @param [in] user_data The user data to be passed to the @a callback
+ * function
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @see mv_surveillance_event_type_cb
+ * @see mv_surveillance_foreach_event_result_name()
+ */
+int mv_surveillance_foreach_supported_event_type(
+ mv_surveillance_event_type_cb callback,
+ void *user_data);
+
+/**
+ * @brief Starts traversing through list of supported event result value names.
+ *
+ * @since_tizen 3.0
+ * @remarks Supported event types, event result value names and their
+ * descriptions can be found in
+ * @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES documentation
+ * section
+ * @param [in] event_type The name of the event type for which result value
+ * names will be passed to the @a callback. Can be
+ * set @c NULL. If set @c NULL then all supported
+ * event result value names will be traversed
+ * @param [in] callback The callback function to be called for each
+ * supported event result value name
+ * @param [in] user_data The user data to be passed to the @a callback
+ * function
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @see mv_surveillance_event_result_name_cb
+ * @see mv_surveillance_foreach_supported_event_type()
+ * @see mv_surveillance_get_result_value()
+ */
+int mv_surveillance_foreach_event_result_name(
+ const char *event_type,
+ mv_surveillance_event_result_name_cb callback,
+ void *user_data);
+
+/**
+ * @brief Gets result value.
+ * @details See the output values names in the event types descriptions located
+ * in @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES documentation
+ * section.
+ *
+ * @since_tizen 3.0
+ * @remarks The name can be obtained by
+ * @ref mv_surveillance_foreach_event_result_name function
+ * @param [in] result The handle to the event result
+ * @param [in] name The name of the value to be gotten
+ * @param [in, out] value The pointer to variable which will be filled
+ * by result value. To find the type of @a value
+ * please refer to the
+ * @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES
+ * documentation section
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @pre Memory for value has to be allocated
+ *
+ * @see mv_surveillance_event_trigger_h
+ * @see mv_surveillance_event_occurred_cb
+ * @see mv_surveillance_subscribe_event_trigger()
+ * @see mv_surveillance_unsubscribe_event_trigger()
+ * @see mv_surveillance_foreach_supported_event_type()
+ * @see mv_surveillance_foreach_event_result_name()
+ */
+int mv_surveillance_get_result_value(
+ mv_surveillance_result_h result,
+ const char *name,
+ void *value);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TIZEN_MEDIAVISION_SURVEILLANCE_H__ */
diff --git a/include/mv_surveillance_private.h b/include/mv_surveillance_private.h
new file mode 100644
index 00000000..4dc4bad0
--- /dev/null
+++ b/include/mv_surveillance_private.h
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TIZEN_MEDIAVISION_SURVEILLANCE_PRIVATE_H__
+#define __TIZEN_MEDIAVISION_SURVEILLANCE_PRIVATE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "mv_common.h"
+
+/**
+ * @brief Event trigger structure.
+ * @details See supported event types and their descriptions in
+ * @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES documentation
+ * section.
+ * Also the list of supported events can be obtained using
+ * @ref mv_surveillance_foreach_supported_event_type() function
+ *
+ * @since_tizen 3.0
+ */
+typedef struct
+{
+ unsigned int trigger_id; /**< Unique event trigger identifier */
+ const char *event_type; /**< Type of the event */
+ int number_of_roi_points; /**< Number of ROI (Region of interest) points */
+ mv_point_s *roi; /**< ROI points array */
+} mv_surveillance_event_trigger_s;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TIZEN_MEDIAVISION_SURVEILLANCE_PRIVATE_H__ */
diff --git a/media-vision-config.json b/media-vision-config.json
index 2f0b46ce..207e575c 100644
--- a/media-vision-config.json
+++ b/media-vision-config.json
@@ -114,6 +114,21 @@
"name" : "MV_FACE_RECOGNITION_MODEL_TYPE",
"type" : "integer",
"value" : 3
+ },
+ {
+ "name" : "MV_SURVEILLANCE_FACE_RECOGNITION_MODEL_FILE_PATH",
+ "type" : "string",
+ "value" : ""
+ },
+ {
+ "name" : "MV_SURVEILLANCE_MOVEMENT_DETECTION_THRESHOLD",
+ "type" : "integer",
+ "value" : 10
+ },
+ {
+ "name" : "MV_SURVEILLANCE_SKIP_FRAMES_COUNT",
+ "type" : "integer",
+ "value" : 0
}
]
}
diff --git a/mv_surveillance/CMakeLists.txt b/mv_surveillance/CMakeLists.txt
new file mode 100644
index 00000000..e6a0a448
--- /dev/null
+++ b/mv_surveillance/CMakeLists.txt
@@ -0,0 +1,8 @@
+project(mv_surveillance_port)
+cmake_minimum_required(VERSION 2.6)
+
+if(MEDIA_VISION_SURVEILLANCE_LICENSE_PORT)
+ add_subdirectory(${PROJECT_SOURCE_DIR}/surveillance_lic) # Licensed port
+else()
+ add_subdirectory(${PROJECT_SOURCE_DIR}/surveillance) # Open port
+endif()
diff --git a/mv_surveillance/surveillance/CMakeLists.txt b/mv_surveillance/surveillance/CMakeLists.txt
new file mode 100644
index 00000000..b7b5f03a
--- /dev/null
+++ b/mv_surveillance/surveillance/CMakeLists.txt
@@ -0,0 +1,26 @@
+project(${MV_SURVEILLANCE_LIB_NAME})
+cmake_minimum_required(VERSION 2.6)
+
+set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG _DEBUG)
+
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${LIB_INSTALL_DIR})
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${LIB_INSTALL_DIR})
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+
+include_directories("${INC_DIR}")
+include_directories("${PROJECT_SOURCE_DIR}/include")
+include_directories("${PROJECT_SOURCE_DIR}/src")
+
+file(GLOB MV_SURVEILLANCE_INC_LIST "${PROJECT_SOURCE_DIR}/include/*.h")
+file(GLOB MV_SURVEILLANCE_SRC_LIST "${PROJECT_SOURCE_DIR}/src/*.cpp"
+ "${PROJECT_SOURCE_DIR}/src/*.c")
+
+if(FORCED_STATIC_BUILD)
+ add_library(${PROJECT_NAME} STATIC ${MV_SURVEILLANCE_INC_LIST} ${MV_SURVEILLANCE_SRC_LIST})
+else()
+ add_library(${PROJECT_NAME} SHARED ${MV_SURVEILLANCE_INC_LIST} ${MV_SURVEILLANCE_SRC_LIST})
+endif()
+
+target_link_libraries(${PROJECT_NAME} ${MV_COMMON_LIB_NAME} ${MV_FACE_LIB_NAME})
+
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR})
diff --git a/mv_surveillance/surveillance/include/EventDefs.h b/mv_surveillance/surveillance/include/EventDefs.h
new file mode 100644
index 00000000..9d92ade0
--- /dev/null
+++ b/mv_surveillance/surveillance/include/EventDefs.h
@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_EVENT_DEFS_H__
+#define __MEDIA_VISION_EVENT_DEFS_H__
+
+/**
+ * @file EventDefs.h
+ * @brief This file contains definitions for event triggers.
+ */
+
+#include <mv_common.h>
+
+#include <string>
+#include <vector>
+#include <list>
+#include <map>
+
+#include <opencv2/opencv.hpp>
+
+namespace mediavision {
+namespace surveillance {
+
+typedef std::map<std::string, std::vector<std::string> > EventTypesMap;
+typedef EventTypesMap::iterator EventTypesMapIter;
+typedef EventTypesMap::const_iterator EventTypesMapConstIter;
+
+typedef std::vector<std::string> StringVector;
+typedef StringVector::iterator StringIter;
+typedef StringVector::const_iterator StringConstIter;
+
+typedef std::vector<int> IntVector;
+typedef IntVector::iterator IntIter;
+typedef IntVector::const_iterator IntConstIter;
+
+typedef std::vector<double> DoubleVector;
+typedef DoubleVector::iterator DoubleIter;
+typedef DoubleVector::const_iterator DoubleConstIter;
+
+typedef std::vector<mv_rectangle_s> MVRectangles;
+typedef MVRectangles::iterator MVRectanglesIter;
+typedef MVRectangles::const_iterator MVRectanglesConstIter;
+
+typedef std::vector<cv::Rect> CVRectangles;
+typedef CVRectangles::iterator CVRectanglesIter;
+typedef CVRectangles::const_iterator CVRectanglesConstIter;
+
+typedef std::vector<mv_point_s> MVPoints;
+typedef MVPoints::iterator MVPointsIter;
+typedef MVPoints::const_iterator MVPointsConstIter;
+
+typedef std::vector<cv::Point> CVPoints;
+typedef std::vector<CVPoints> Contours;
+
+} /* surveillance */
+} /* mediavision */
+
+#endif /* __MEDIA_VISION_EVENT_DEFS_H__ */
diff --git a/mv_surveillance/surveillance/include/EventManager.h b/mv_surveillance/surveillance/include/EventManager.h
new file mode 100644
index 00000000..fd13f52f
--- /dev/null
+++ b/mv_surveillance/surveillance/include/EventManager.h
@@ -0,0 +1,190 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_EVENT_MANAGER_H__
+#define __MEDIA_VISION_EVENT_MANAGER_H__
+
+/**
+ * @file EventManager.h
+ * @brief This file contains functionality for event manager.
+ */
+
+#include "EventTrigger.h"
+#include "EventDefs.h"
+
+namespace mediavision {
+namespace surveillance {
+
+class EventManager;
+
+/**
+ * @class EventManagerDestroyer
+ * @brief This class contains event manager destroyer functionality.
+ *
+ * @since_tizen 3.0
+ */
+class EventManagerDestroyer {
+public:
+
+ /**
+ * @brief Default destructor.
+ *
+ * @since_tizen 3.0
+ */
+ ~EventManagerDestroyer();
+
+ /**
+ * @brief Initializes pointer to EventManager which will be destroyed.
+ *
+ * @since_tizen 3.0
+ * @param [in] pointer The pointer to EventManager which will be destroyed
+ */
+ void initialize(EventManager *pointer);
+
+private:
+
+ EventManager *__pInstance;
+};
+
+/**
+ * @class EventManager
+ * @brief This class contains event manager functionality.
+ *
+ * @since_tizen 3.0
+ */
+
+class EventManager {
+public:
+
+ /**
+ * @brief Gets EventManager instance.
+ *
+ * @since_tizen 3.0
+ */
+ static EventManager& getInstance();
+
+ /**
+ * @brief Registers event.
+ *
+ * @since_tizen 3.0
+ * @param [in] eventTrigger The event trigger to be register (NULL if internal)
+ * @param [in] triggerId Unique event trigger identifier to be register
+ * @param [in] eventType Type of the event
+ * @param [in] videoStreamId Video stream identificator
+ * @param [in] engineCfg The engine configuration for event trigger
+ * @param [in] callback The callback to be called if event will be occured
+ * @param [in] user_data The user data to be passed to the callback function
+ * @param [in] numberOfPoints The number of ROI points
+ * @param [in] roi The intput array with ROI points
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ int registerEvent(
+ mv_surveillance_event_trigger_h eventTrigger,
+ long int triggerId,
+ const char *eventType,
+ int videoStreamId,
+ mv_engine_config_h engineCfg,
+ mv_surveillance_event_occurred_cb callback,
+ void *user_data,
+ int numberOfPoints,
+ mv_point_s *roi);
+
+ /**
+ * @brief Unregisters event.
+ *
+ * @since_tizen 3.0
+ * @param [in] triggerId Unique event trigger identifier to be
+ * unregister
+ * @param [in] videoStreamId Video stream identifier for which event
+ * will be unregistered
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ int unregisterEvent(long int triggerId, int videoStreamId);
+
+ /**
+ * @brief Pushes media source to run event triggers.
+ *
+ * @since_tizen 3.0
+ * @param [in] source The media source to be pushed
+ * @param [in] videoStreamId The video stream identificator for media source
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ int pushSource(mv_source_h source, int videoStreamId);
+
+ /**
+ * @brief Gets supported event types.
+ *
+ * @since_tizen 3.0
+ * @param [out] eventTypes The supported event types
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ static int getSupportedEventTypes(StringVector& eventTypes);
+
+ /**
+ * @brief Gets all supported event result value names.
+ *
+ * @since_tizen 3.0
+ * @param [out] eventResValNames The supported event result value names
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ static int getSupportedEventResultValueNames(StringVector& eventResValNames);
+
+ /**
+ * @brief Gets supported event result value names for an event type.
+ *
+ * @since_tizen 3.0
+ * @param [in] eventTypeName The name of the event type to return
+ * result value names for
+ * @param [out] eventResValNames The supported event result value names
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ static int getSupportedEventResultValueNames(
+ const std::string& eventTypeName,
+ StringVector& eventResValNames);
+
+private:
+
+ EventManager();
+
+ EventManager(const EventManager&);
+
+ EventManager& operator=(EventManager&);
+
+ ~EventManager();
+
+ static void setSupportedEventTypes();
+
+ EventTriggersIter isTriggerExists(EventTrigger *trigger, int videoStreamId);
+
+ friend class EventManagerDestroyer;
+
+private:
+
+ static EventManager *__pInstance;
+
+ static EventManagerDestroyer Destroyer;
+
+ static EventTypesMap SupportedEventTypes;
+
+private:
+
+ EventTriggersMap __eventTriggers;
+};
+
+} /* surveillance */
+} /* mediavision */
+
+#endif /* __MEDIA_VISION_EVENT_MANAGER_H__ */
diff --git a/mv_surveillance/surveillance/include/EventResult.h b/mv_surveillance/surveillance/include/EventResult.h
new file mode 100644
index 00000000..7ce8f454
--- /dev/null
+++ b/mv_surveillance/surveillance/include/EventResult.h
@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_EVENT_RESULT_H__
+#define __MEDIA_VISION_EVENT_RESULT_H__
+
+/**
+ * @file EventTrigger.h
+ * @brief This file contains interface for event trigger.
+ */
+
+namespace mediavision {
+namespace surveillance {
+
+/**
+ * @class EventResult
+ * @brief This class contains event result interface.
+ *
+ * @since_tizen 3.0
+ */
+class EventResult {
+public:
+ /**
+ * @brief Default destructor.
+ *
+ * @since_tizen 3.0
+ */
+ virtual ~EventResult() {}
+
+ /**
+ * @brief Gets result value.
+ *
+ * @since_tizen 3.0
+ * @param [in] valueName The name of the value to be gotten
+ * @param [in, out] value The pointer to variable which will be filled
+ * by result value
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ virtual int getResultValue(const char *valueName, void *value) const = 0;
+};
+
+
+} /* surveillance */
+} /* mediavision */
+
+#endif /* _MEDIA_VISION__EVENT_RESULT_H__ */
diff --git a/mv_surveillance/surveillance/include/EventTrigger.h b/mv_surveillance/surveillance/include/EventTrigger.h
new file mode 100644
index 00000000..d5851957
--- /dev/null
+++ b/mv_surveillance/surveillance/include/EventTrigger.h
@@ -0,0 +1,227 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_EVENT_TRIGGER_H__
+#define __MEDIA_VISION_EVENT_TRIGGER_H__
+
+/**
+ * @file EventTrigger.h
+ * @brief This file contains interface for event trigger.
+ */
+
+#include "EventDefs.h"
+
+#include <mv_surveillance.h>
+#include <mv_surveillance_private.h>
+
+#include <string>
+#include <map>
+#include <list>
+
+namespace mediavision {
+namespace surveillance {
+
+/**
+ * @class EventTrigger
+ * @brief This class contains event trigger interface.
+ *
+ * @since_tizen 3.0
+ */
+class EventTrigger {
+public:
+ /**
+ * @brief Default constructor.
+ *
+ * @since_tizen 3.0
+ * @param [in] eventTrigger The event trigger to be register (NULL if internal)
+ * @param [in] triggerId Unique event trigger identifier to be register
+ * @param [in] videoStreamId Video stream identifier
+ * @param [in] callback The callback to be called if event will be occured
+ * @param [in] user_data The user data to be passed to the callback function
+ * @param [in] numberOfPoints The number of ROI points
+ * @param [in] roi The intput array with ROI points
+ */
+ EventTrigger(
+ mv_surveillance_event_trigger_h eventTrigger,
+ long int triggerId,
+ int videoStreamId,
+ mv_surveillance_event_occurred_cb callback,
+ void *userData,
+ int numberOfPoints,
+ mv_point_s *roi);
+
+ /**
+ * @brief Default destructor.
+ *
+ * @since_tizen 3.0
+ */
+ virtual ~EventTrigger();
+
+ /**
+ * @brief Parses engine configuration.
+ *
+ * @since_tizen 3.0
+ * @param [in] engineConfig The engine configuration to be parsed
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ virtual int parseEngineConfig(mv_engine_config_h engineConfig) = 0;
+
+ /**
+ * @brief Pushes media source.
+ *
+ * @since_tizen 3.0
+ * @param [in] source The media source to be parsed
+ * @param [in] graySource The media source converted to gray scale
+ * @param [in] grayImage The converted to gray scale source
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ virtual int pushSource(
+ mv_source_h source,
+ mv_source_h graySource,
+ const cv::Mat& grayImage) = 0;
+
+ /**
+ * @brief Gets event type.
+ *
+ * @since_tizen 3.0
+ * @return string with event type
+ */
+ virtual std::string getEventType() const = 0;
+
+ /**
+ * @brief Gets video stream identifier of event trigger.
+ *
+ * @since_tizen 3.0
+ * @return video stream identifier
+ */
+ int getVideoStreamId() const;
+
+ /**
+ * @brief Checks if callback with the identifier is subscribed.
+ *
+ * @since_tizen 3.0
+ * @return true if suscribed, false otherwise
+ */
+ bool isCallbackSubscribed(long int triggerId) const;
+
+ /**
+ * @brief Subscibes callback with unique identifier.
+ *
+ * @since_tizen 3.0
+ * @param [in] eventTrigger The event trigger to be register (NULL if internal)
+ * @param [in] triggerId Unique event trigger identifier to be subscribed
+ * @param [in] callback The callback to be called if event will be occured
+ * @param [in] user_data The user data to be passed to the callback function
+ * @param [in] numberOfPoints The number of ROI points
+ * @param [in] roi The intput array with ROI points
+ * @return @c true on success, false otherwise
+ */
+ bool subscribeCallback(
+ mv_surveillance_event_trigger_h eventTrigger,
+ long int triggerId,
+ mv_surveillance_event_occurred_cb callback,
+ void *userData,
+ int numberOfPoints,
+ mv_point_s *roi);
+
+ /**
+ * @brief Unsubscibes callback with unique identifier.
+ *
+ * @since_tizen 3.0
+ * @param [in] triggerId Unique event trigger identifier to be unsubscribed
+ * @return @c true on success, false otherwise
+ */
+ bool unsubscribeCallback(long int triggerId);
+
+ /**
+ * @brief Checks if there are no subscribed callbacks.
+ *
+ * @since_tizen 3.0
+ * @return @c true at least one callback is subscribed, false otherwise
+ */
+ bool isCallbacksEmpty() const;
+
+ /**
+ * @brief Applies ROI (Region Of Interest) to input image.
+ *
+ * @since_tizen 3.0
+ * @param [in, out] image The input image where ROI will be applied
+ * @param [in] imageWidth The input image width
+ * @param [in] imageHeight The input image height
+ * @param [in] scalePoints True if ROI points must be scaled, false oterwise
+ * @param [in] scaleX The scale for X ROI point coordinate
+ * @param [in] scaleY The scale for Y ROI point coordinate
+ * @return @c true on success, false otherwise
+ */
+ int applyROIToImage(
+ unsigned char *image,
+ int imageWidth,
+ int imageHeight,
+ bool scalePoints = false,
+ int scaleX = 1,
+ int scaleY = 1);
+
+ /**
+ * @brief Comparison operator for equal case.
+ *
+ * @since_tizen 3.0
+ * @return true if event trigger is equal to other, false otherwise
+ */
+ virtual bool operator==(const EventTrigger& other) const;
+
+ /**
+ * @brief Comparison operator for not equal case.
+ *
+ * @since_tizen 3.0
+ * @return true if event trigger is not equal to other, false otherwise
+ */
+ virtual bool operator!=(const EventTrigger& other) const;
+
+protected:
+ struct CallbackData {
+ mv_surveillance_event_trigger_h eventTrigger;
+
+ mv_surveillance_event_occurred_cb callback;
+
+ void *userData;
+ };
+
+ typedef std::map<long int, CallbackData> CallbackDataMap;
+ typedef CallbackDataMap::const_iterator CallbackDataMapConstIter;
+ typedef CallbackDataMap::iterator CallbackDataMapIter;
+
+ typedef std::pair<long int, CallbackData> CallbackDataPair;
+
+protected:
+ static long int InternalTriggersCounter;
+
+protected:
+ int __videoStreamId;
+
+ MVPoints __roi;
+
+ CallbackDataMap __callbackDataMap;
+};
+
+typedef std::list<EventTrigger*> EventTriggers;
+typedef std::map<int, EventTriggers> EventTriggersMap;
+typedef EventTriggers::const_iterator EventTriggersConstIter;
+typedef EventTriggers::iterator EventTriggersIter;
+
+} /* surveillance */
+} /* mediavision */
+
+#endif /* __MEDIA_VISION_EVENT_TRIGGER_H__ */
diff --git a/mv_surveillance/surveillance/include/EventTriggerMovementDetection.h b/mv_surveillance/surveillance/include/EventTriggerMovementDetection.h
new file mode 100644
index 00000000..e3b57a9c
--- /dev/null
+++ b/mv_surveillance/surveillance/include/EventTriggerMovementDetection.h
@@ -0,0 +1,159 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_EVENT_TRIGGER_MOVEMENT_DETECTION_H__
+#define __MEDIA_VISION_EVENT_TRIGGER_MOVEMENT_DETECTION_H__
+
+/**
+ * @file EventTriggerMovementDetection.h
+ * @brief This file contains interface for movement detection events.
+ */
+
+#include "EventTrigger.h"
+
+#include "EventResult.h"
+#include "EventDefs.h"
+
+#include <opencv/cv.h>
+
+namespace mediavision {
+namespace surveillance {
+
+/**
+ * @class EventResultMovementDetection
+ * @brief This class contains movement detection event results.
+ *
+ * @since_tizen 3.0
+ */
+class EventResultMovementDetection : public EventResult {
+public:
+ /**
+ * @brief Gets result value.
+ *
+ * @since_tizen 3.0
+ * @param [in] valueName The name of the value to be gotten
+ * @param [in, out] value The pointer to variable which will be filled
+ * by result value
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ virtual int getResultValue(const char *valueName, void *value) const;
+
+public:
+ MVRectangles __movementRegions; /**< Regions where movements were detected */
+
+ cv::Mat __grayImage; /** Current gray image (only for internal usage) */
+};
+
+/**
+ * @class EventTriggerMovementDetection
+ * @brief This class contains movement detection events.
+ *
+ * @since_tizen 3.0
+ */
+class EventTriggerMovementDetection : public EventTrigger {
+public:
+ /**
+ * @brief Default constructor.
+ *
+ * @since_tizen 3.0
+ * @param [in] eventTrigger The event trigger to be register (NULL if internal)
+ * @param [in] triggerId Unique event trigger identifier to be register
+ * @param [in] videoStreamId Video stream identifier
+ * @param [in] callback The callback to be called if event will be occured
+ * @param [in] user_data The user data to be passed to the callback function
+ * @param [in] numberOfPoints The number of ROI points
+ * @param [in] roi The intput array with ROI points
+ */
+ EventTriggerMovementDetection(
+ mv_surveillance_event_trigger_h eventTrigger,
+ long int triggerId,
+ int videoStreamId,
+ mv_surveillance_event_occurred_cb callback,
+ void *userData,
+ int numberOfPoints,
+ mv_point_s *roi);
+
+ /**
+ * @brief Default destructor.
+ *
+ * @since_tizen 3.0
+ */
+ virtual ~EventTriggerMovementDetection();
+
+ /**
+ * @brief Parses engine configuration.
+ *
+ * @since_tizen 3.0
+ * @param [in] engineConfig The engine configuration to be parsed
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ virtual int parseEngineConfig(mv_engine_config_h engineConfig);
+
+ /**
+ * @brief Pushes media source.
+ *
+ * @since_tizen 3.0
+ * @param [in] source The media source to be parsed
+ * @param [in] graySource The media source converted to gray scale
+ * @param [in] grayImage The converted to gray scale source
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ virtual int pushSource(
+ mv_source_h source,
+ mv_source_h graySource,
+ const cv::Mat& grayImage);
+
+ /**
+ * @brief Gets event type.
+ *
+ * @since_tizen 3.0
+ * @return string with event type
+ */
+ virtual std::string getEventType() const;
+
+ /**
+ * @brief Comparison operator for equal case.
+ *
+ * @since_tizen 3.0
+ * @return true if event trigger is equal to other, false otherwise
+ */
+ virtual bool operator==(const EventTriggerMovementDetection& other) const;
+
+ /**
+ * @brief Comparison operator for not equal case.
+ *
+ * @since_tizen 3.0
+ * @return true if event trigger is not equal to other, false otherwise
+ */
+ virtual bool operator!=(const EventTriggerMovementDetection& other) const;
+
+private:
+ static const cv::Mat __ERODE_KERNEL;
+
+ static const cv::Mat __DILATE_KERNEL;
+
+private:
+ cv::Mat __previousImage;
+
+ EventResultMovementDetection *__eventResult;
+
+ int __diffThreshold;
+};
+
+} /* surveillance */
+} /* mediavision */
+
+#endif /* __MEDIA_VISION_EVENT_TRIGGER_MOVEMENT_DETECTION_H__ */
diff --git a/mv_surveillance/surveillance/include/EventTriggerPersonAppearance.h b/mv_surveillance/surveillance/include/EventTriggerPersonAppearance.h
new file mode 100644
index 00000000..7aeecffb
--- /dev/null
+++ b/mv_surveillance/surveillance/include/EventTriggerPersonAppearance.h
@@ -0,0 +1,211 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_EVENT_TRIGGER_PERSON_APPEARANCE_H__
+#define __MEDIA_VISION_EVENT_TRIGGER_PERSON_APPEARANCE_H__
+
+/**
+ * @file EventTriggerPersonAppearance.h
+ * @brief This file contains interface for person appeared / disapeared events.
+ */
+
+#include "EventTrigger.h"
+
+#include "EventResult.h"
+#include "EventDefs.h"
+#include "HoGDetector.h"
+
+#include <opencv/cv.h>
+
+namespace mediavision {
+namespace surveillance {
+
+/**
+ * @class EventResultPersonAppearance
+ * @brief This class contains person appeared / disapeared event results.
+ *
+ * @since_tizen 3.0
+ */
+class EventResultPersonAppearance : public EventResult {
+public:
+ /**
+ * @brief Gets result value.
+ *
+ * @since_tizen 3.0
+ * @param [in] valueName The name of the value to be gotten
+ * @param [in, out] value The pointer to variable which will be filled
+ * by result value
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ virtual int getResultValue(const char *valueName, void *value) const;
+
+public:
+ MVRectangles __appearedLocations; /**< Locations of persons which were appeared
+ first time*/
+
+ MVRectangles __trackedLocations; /**< Locations of persons which were tracked
+ from previous frame*/
+
+ MVRectangles __disappearedLocations; /**< Locations of persons which were
+ disappeared */
+};
+
+/**
+ * @class EventTriggerPersonAppearance
+ * @brief This class contains person appeared / disapeared events.
+ *
+ * @since_tizen 3.0
+ */
+class EventTriggerPersonAppearance : public EventTrigger {
+public:
+ /**
+ * @brief Default constructor.
+ *
+ * @since_tizen 3.0
+ * @param [in] eventTrigger The event trigger to be register (NULL if internal)
+ * @param [in] triggerId Unique event trigger identifier to be register
+ * @param [in] videoStreamId Video stream identifier
+ * @param [in] callback The callback to be called if event will be occured
+ * @param [in] user_data The user data to be passed to the callback function
+ * @param [in] numberOfPoints The number of ROI points
+ * @param [in] roi The intput array with ROI points
+ */
+ EventTriggerPersonAppearance(
+ mv_surveillance_event_trigger_h eventTrigger,
+ long int triggerId,
+ int videoStreamId,
+ mv_surveillance_event_occurred_cb callback,
+ void *userData,
+ int numberOfPoints,
+ mv_point_s *roi);
+
+ /**
+ * @brief Default destructor.
+ *
+ * @since_tizen 3.0
+ */
+ virtual ~EventTriggerPersonAppearance();
+
+ /**
+ * @brief Parses engine configuration.
+ *
+ * @since_tizen 3.0
+ * @param [in] engineConfig The engine configuration to be parsed
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ virtual int parseEngineConfig(mv_engine_config_h engineConfig);
+
+ /**
+ * @brief Pushes media source.
+ *
+ * @since_tizen 3.0
+ * @param [in] source The media source to be parsed
+ * @param [in] graySource The media source converted to gray scale
+ * @param [in] grayImage The converted to gray scale source
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ virtual int pushSource(
+ mv_source_h source,
+ mv_source_h graySource,
+ const cv::Mat& grayImage);
+
+ /**
+ * @brief Gets event type.
+ *
+ * @since_tizen 3.0
+ * @return string with event type
+ */
+ virtual std::string getEventType() const;
+
+ /**
+ * @brief Comparison operator for equal case.
+ *
+ * @since_tizen 3.0
+ * @return true if event trigger is equal to other, false otherwise
+ */
+ virtual bool operator==(const EventTriggerPersonAppearance& other) const;
+
+ /**
+ * @brief Comparison operator for not equal case.
+ *
+ * @since_tizen 3.0
+ * @return true if event trigger is not equal to other, false otherwise
+ */
+ virtual bool operator!=(const EventTriggerPersonAppearance& other) const;
+
+private:
+ static void movementDetectedCB(
+ mv_surveillance_event_trigger_h event_trigger,
+ mv_source_h source,
+ int video_stream_id,
+ mv_surveillance_result_h event_result,
+ void *user_data);
+
+private:
+
+ void runCallbacks(mv_source_h source);
+
+private:
+
+ struct TrackedRectangle {
+ cv::Rect rect;
+
+ int framesCount;
+
+ TrackedRectangle(cv::Rect _rect, int _framesCount)
+ {
+ rect = _rect;
+ framesCount = _framesCount;
+ }
+ };
+
+ typedef std::list<TrackedRectangle> TrackedRectangles;
+ typedef TrackedRectangles::const_iterator TrackedRectanglesConstIter;
+ typedef TrackedRectangles::iterator TrackedRectanglesIter;
+
+private:
+ int __skipFramesCount;
+
+ int __frameCounter; /**< Counts frames on which detection has not be launched */
+
+ long int __movementDetectedEventId;
+
+ float __factorX;
+
+ float __factorY;
+
+ cv::Rect __rectToDetect;
+
+ cv::Rect __rectToDetectPrevious;
+
+ TrackedRectangles __trackedRects;
+
+ CVRectangles __appearedRects;
+
+ CVRectangles __disappearedRects;
+
+ modifiedcv::HOGDescriptor __hogClassifier; /**< Classifier to be used for full body
+ person detection */
+
+ MVRectangles __detectedLocations;
+
+ EventResultPersonAppearance *__eventResult;
+};
+
+} /* surveillance */
+} /* mediavision */
+
+#endif /* __MEDIA_VISION_EVENT_TRIGGER_PERSON_APPEARANCE_H__ */
diff --git a/mv_surveillance/surveillance/include/EventTriggerPersonRecognition.h b/mv_surveillance/surveillance/include/EventTriggerPersonRecognition.h
new file mode 100644
index 00000000..cd3448ea
--- /dev/null
+++ b/mv_surveillance/surveillance/include/EventTriggerPersonRecognition.h
@@ -0,0 +1,192 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_EVENT_TRIGGER_PERSON_RECOGNITION_H__
+#define __MEDIA_VISION_EVENT_TRIGGER_PERSON_RECOGNITION_H__
+
+/**
+ * @file EventTriggerPersonRecognition.h
+ * @brief This file contains interface for person recognized events.
+ */
+
+#include <mv_face.h>
+
+#include "EventTrigger.h"
+
+#include "EventResult.h"
+#include "EventDefs.h"
+
+#include "EventTriggerPersonAppearance.h"
+
+namespace mediavision {
+namespace surveillance {
+
+/**
+ * @class EventResultPersonRecogniton
+ * @brief This class contains person recognized event results.
+ *
+ * @since_tizen 3.0
+ */
+class EventResultPersonRecognition : public EventResult {
+public:
+ /**
+ * @brief Gets result value.
+ *
+ * @since_tizen 3.0
+ * @param [in] valueName The name of the value to be gotten
+ * @param [in, out] value The pointer to variable which will be filled
+ * by result value
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ virtual int getResultValue(const char *valueName, void *value) const;
+
+public:
+ MVRectangles __locations; /**< Persons locations */
+
+ IntVector __faceLabels; /**< Persons face lables */
+
+ DoubleVector __confidences; /**< Persons face recognition confidences */
+};
+
+/**
+ * @class EventTriggerPersonRecognition
+ * @brief This class contains person recognized events.
+ *
+ * @since_tizen 3.0
+ */
+class EventTriggerPersonRecognition : public EventTrigger {
+public:
+ /**
+ * @brief Default constructor.
+ *
+ * @since_tizen 3.0
+ * @param [in] eventTrigger The event trigger to be register (NULL if internal)
+ * @param [in] triggerId Unique event trigger identifier to be register
+ * @param [in] videoStreamId Video stream identifier
+ * @param [in] callback The callback to be called if event will be occured
+ * @param [in] user_data The user data to be passed to the callback function
+ * @param [in] numberOfPoints The number of ROI points
+ * @param [in] roi The intput array with ROI points
+ */
+ EventTriggerPersonRecognition(
+ mv_surveillance_event_trigger_h eventTrigger,
+ long int triggerId,
+ int videoStreamId,
+ mv_surveillance_event_occurred_cb callback,
+ void *userData,
+ int numberOfPoints,
+ mv_point_s *roi);
+
+ /**
+ * @brief Default destructor.
+ *
+ * @since_tizen 3.0
+ */
+ virtual ~EventTriggerPersonRecognition();
+
+ /**
+ * @brief Parses engine configuration.
+ *
+ * @since_tizen 3.0
+ * @param [in] engineConfig The engine configuration to be parsed
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ virtual int parseEngineConfig(mv_engine_config_h engineConfig);
+
+ /**
+ * @brief Pushes media source.
+ *
+ * @since_tizen 3.0
+ * @param [in] source The media source to be parsed
+ * @param [in] graySource The media source converted to gray scale
+ * @param [in] grayImage The converted to gray scale source
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ virtual int pushSource(
+ mv_source_h source,
+ mv_source_h graySource,
+ const cv::Mat& grayImage);
+
+ /**
+ * @brief Gets event type.
+ *
+ * @since_tizen 3.0
+ * @return string with event type
+ */
+ virtual std::string getEventType() const;
+
+ /**
+ * @brief Comparison operator for equal case.
+ *
+ * @since_tizen 3.0
+ * @return true if event trigger is equal to other, false otherwise
+ */
+ virtual bool operator==(const EventTriggerPersonRecognition& other) const;
+
+ /**
+ * @brief Comparison operator for not equal case.
+ *
+ * @since_tizen 3.0
+ * @return true if event trigger is not equal to other, false otherwise
+ */
+ virtual bool operator!=(const EventTriggerPersonRecognition& other) const;
+
+ /**
+ * @brief Sets event results.
+ *
+ * @since_tizen 3.0
+ * @param [in] faceLocation The location of the face recognized on @a source.
+ * @param [in] faceLabel The label that identifies face which was
+ * recognized in the @a source.
+ * @param [in] confidence The confidence of the @a recognition_model
+ * that face has been recognized correctly
+ * (value from 0.0 to 1.0).
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ void setEventResults(
+ mv_rectangle_s faceLocation,
+ int faceLabel,
+ double confidence);
+
+private:
+ mv_face_recognition_model_h __faceRecognitionModel;
+
+ mv_source_h __lastFrame;
+
+ EventResultPersonRecognition *__eventResult;
+
+private:
+ static void faceDetectedCB(
+ mv_source_h source,
+ mv_engine_config_h engine_cfg,
+ mv_rectangle_s *faces_locations,
+ int number_of_faces,
+ void *user_data);
+
+ static void faceRecognizedCB(
+ mv_source_h source,
+ mv_face_recognition_model_h recognition_model,
+ mv_engine_config_h engine_cfg,
+ mv_rectangle_s *face_location,
+ const int *face_label,
+ double confidence,
+ void *user_data);
+};
+
+} /* surveillance */
+} /* mediaVision */
+
+#endif /* __MEDIA_VISION_EVENT_TRIGGER_PERSON_RECOGNITION_H__ */
diff --git a/mv_surveillance/surveillance/include/HoGDetector.h b/mv_surveillance/surveillance/include/HoGDetector.h
new file mode 100644
index 00000000..d4bb4008
--- /dev/null
+++ b/mv_surveillance/surveillance/include/HoGDetector.h
@@ -0,0 +1,194 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __MEDIA_VISION_HOGDETECTOR_H__
+#define __MEDIA_VISION_HOGDETECTOR_H__
+
+/**
+ * @file HOGDetector.h
+ * @brief This file contains structure of HOG detector.
+ */
+
+#include "opencv2/core/core.hpp"
+#include "opencv2/objdetect/objdetect.hpp"
+
+#include <vector>
+
+namespace modifiedcv {
+
+using namespace cv;
+
+struct HOGDescriptor {
+ enum { L2Hys = 0 };
+ enum { DEFAULT_NLEVELS = 64 };
+
+ // default constructor
+ HOGDescriptor() :
+ winSize(64, 128),
+ blockSize(16, 16),
+ blockStride(8, 8),
+ cellSize(8, 8),
+ nbins(9),
+ derivAperture(1),
+ winSigma(-1),
+ histogramNormType(HOGDescriptor::L2Hys),
+ L2HysThreshold(0.2),
+ gammaCorrection(true),
+ nlevels(HOGDescriptor::DEFAULT_NLEVELS)
+ {}
+
+ // constructor
+ HOGDescriptor(
+ Size _winSize,
+ Size _blockSize,
+ Size _blockStride,
+ Size _cellSize,
+ int _nbins,
+ int _derivAperture = 1,
+ double _winSigma = -1.,
+ int _histogramNormType = L2Hys,
+ double _L2HysThreshold = 0.2,
+ bool _gammaCorrection = false,
+ int _nlevels = DEFAULT_NLEVELS) :
+ winSize(_winSize),
+ blockSize(_blockSize),
+ blockStride(_blockStride),
+ cellSize(_cellSize),
+ nbins(_nbins),
+ derivAperture(_derivAperture),
+ winSigma(_winSigma),
+ histogramNormType(_histogramNormType),
+ L2HysThreshold(_L2HysThreshold),
+ gammaCorrection(_gammaCorrection),
+ nlevels(_nlevels)
+ {}
+
+ // default destructor
+ virtual ~HOGDescriptor() {}
+
+ size_t getDescriptorSize() const;
+
+ bool checkDetectorSize() const;
+
+ double getWinSigma() const;
+
+ virtual void setSVMDetector(InputArray _svmdetector);
+
+ virtual void compute(
+ const Mat& img,
+ CV_OUT vector<float>& descriptors,
+ Size winStride = Size(),
+ Size padding = Size(),
+ const vector<Point>& locations = vector<Point>()) const;
+
+ //with found weights output
+ virtual void detect(
+ const Mat& img,
+ CV_OUT vector<Point>& foundLocations,
+ CV_OUT vector<double>& weights,
+ double hitThreshold = 0.,
+ Size winStride = Size(),
+ Size padding = Size(),
+ const vector<Point>& searchLocations = vector<Point>()) const;
+
+ //without found weights output
+ virtual void detect(
+ const Mat& img,
+ CV_OUT vector<Point>& foundLocations,
+ double hitThreshold = 0.,
+ Size winStride = Size(),
+ Size padding = Size(),
+ const vector<Point>& searchLocations = vector<Point>()) const;
+
+ //with result weights output
+ virtual void detectMultiScale(
+ const Mat& img,
+ CV_OUT vector<Rect>& foundLocations,
+ CV_OUT vector<double>& foundWeights,
+ double hitThreshold = 0,
+ Size winStride = Size(),
+ Size padding = Size(),
+ double scale = 1.05,
+ double finalThreshold = 2.0,
+ bool useMeanshiftGrouping = false) const;
+
+ //without found weights output
+ virtual void detectMultiScale(
+ const Mat& img,
+ CV_OUT vector<Rect>& foundLocations,
+ double hitThreshold = 0.,
+ Size winStride = Size(),
+ Size padding = Size(),
+ double scale = 1.05,
+ double finalThreshold = 2.0,
+ bool useMeanshiftGrouping = false) const;
+
+ virtual void computeGradient(
+ const Mat& img,
+ CV_OUT Mat& grad,
+ CV_OUT Mat& angleOfs,
+ Size paddingTL = Size(),
+ Size paddingBR = Size()) const;
+
+ void groupRectangles(
+ vector<cv::Rect>& rectList,
+ vector<double>& weights,
+ int groupThreshold,
+ double eps) const;
+
+ Size winSize;
+ Size blockSize;
+ Size blockStride;
+ Size cellSize;
+ int nbins;
+ int derivAperture;
+ double winSigma;
+ int histogramNormType;
+ double L2HysThreshold;
+ bool gammaCorrection;
+ vector<float> svmDetector;
+ int nlevels;
+};
+
+} /* modifiedcv */
+
+#endif /* __MEDIA_VISION_HOGDETECTOR_H__ */
diff --git a/mv_surveillance/surveillance/include/SurveillanceHelper.h b/mv_surveillance/surveillance/include/SurveillanceHelper.h
new file mode 100644
index 00000000..ffb6302e
--- /dev/null
+++ b/mv_surveillance/surveillance/include/SurveillanceHelper.h
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_SURVEILLANCE_HELPER_H__
+#define __MEDIA_VISION_SURVEILLANCE_HELPER_H__
+
+/**
+ * @file SurveillanceHelper.h
+ * @brief This file contains interface for surveillance helper.
+ */
+
+#include <mv_common.h>
+
+#include <opencv/cv.h>
+
+namespace mediavision {
+namespace surveillance {
+
+/**
+ * @class SurveillanceHelper
+ * @brief This class contains surveillance helper interface (common class for
+ * surveillance module).
+ *
+ * @since_tizen 3.0
+ */
+class SurveillanceHelper {
+public:
+ /**
+ * @brief Converts mediavision source to cv::Mat in gray scale.
+ *
+ * @since_tizen 3.0
+ * @param [in] mvSource The input media source handle
+ * @param [out] cvSource The outut matrix with gray scaled image
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ static int convertSourceMV2GrayCV(mv_source_h mvSource, cv::Mat& cvSource);
+
+#ifdef ENABLE_NEON
+ /**
+ * @brief Converts mediavision source to cv::Mat in gray scale with NEON.
+ * @details Works only with RGB color space
+ *
+ * @since_tizen 3.0
+ * @param [in] mvSource The input media source handle
+ * @param [out] cvSource The outut matrix with gray scaled image
+ * @return @c 0 on success, otherwise a negative error value
+ */
+ static int convertSourceMVRGB2GrayCVNeon(mv_source_h mvSource, cv::Mat& cvSource);
+#endif
+
+};
+
+
+} /* surveillance */
+} /* mediavision */
+
+#endif /* __MEDIA_VISION_SURVEILLANCE_HELPER_H__ */
diff --git a/mv_surveillance/surveillance/include/mv_absdiff.h b/mv_surveillance/surveillance/include/mv_absdiff.h
new file mode 100644
index 00000000..1ad0a8ab
--- /dev/null
+++ b/mv_surveillance/surveillance/include/mv_absdiff.h
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_MV_ABSDIFF_H__
+#define __MEDIA_VISION_MV_ABSDIFF_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @brief Absolute difference between two buffers.
+ * @details Works only with grayscale buffers.
+ *
+ * @since_tizen 3.0
+ * @remarks If NEON is enabled (ENABLE_NEON flag), then @a width has to be
+ * multiple of 16
+ * @param [in] src1 The first input buffer.
+ * @param [in] src2 The second input buffer.
+ * @param [in] width The ROI width. Must be the multiple of 16.
+ * @param [in] height The ROI height.
+ * @param [in] stride The stride.
+ * @param [out] dst The output buffer.
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int mv_absdiff(
+ uint8_t *__restrict__ src1,
+ uint8_t *__restrict__ src2,
+ int width,
+ int height,
+ int stride,
+ uint8_t *__restrict__ dst);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __MEDIA_VISION_MV_ABSDIFF_H__ */
+
diff --git a/mv_surveillance/surveillance/include/mv_apply_mask.h b/mv_surveillance/surveillance/include/mv_apply_mask.h
new file mode 100644
index 00000000..a639c03e
--- /dev/null
+++ b/mv_surveillance/surveillance/include/mv_apply_mask.h
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_MV_APPLY_MASK_H__
+#define __MEDIA_VISION_MV_APPLY_MASK_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @brief Applies a binary mask to the input buffer.
+ * @details Works only with grayscale buffers.
+ *
+ * @since_tizen 3.0
+ * @remarks If NEON is enabled (ENABLE_NEON flag), then @a width has to be
+ * multiple of 16
+ * @param [in] src_buffer The source buffer.
+ * @param [in] mask The mask, which should contain only values of 0 or 255.
+ * @param [in] width The image width.
+ * @param [in] height The image height.
+ * @param [in] stride The stride.
+ * @param [out] dst_buffer The destination buffer.
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int mv_apply_mask(
+ uint8_t *src_buffer,
+ uint8_t *__restrict mask,
+ int width,
+ int height,
+ int stride,
+ uint8_t *dst_buffer);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __MEDIA_VISION_MV_APPLY_MASK_H__ */
+
diff --git a/mv_surveillance/surveillance/include/mv_mask_buffer.h b/mv_surveillance/surveillance/include/mv_mask_buffer.h
new file mode 100644
index 00000000..abc690f5
--- /dev/null
+++ b/mv_surveillance/surveillance/include/mv_mask_buffer.h
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_MV_MASK_BUFFER_H__
+#define __MEDIA_VISION_MV_MASK_BUFFER_H__
+
+#include "mv_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @brief Gets mask buffer from buffer with known size.
+ * @details Mask buffer values: 0 ouside polygon and 255 inside polygon.
+ *
+ * @since_tizen 3.0
+ * @param [in] buffer_width The buffer width
+ * @param [in] buffer_height The buffer height
+ * @param [in] polygon The array with polygon
+ * @param [in] points_number The size of array with polygon
+ * @param [out] mask_buffer The output mask buffer. mask_buffer size is
+ * the same as the buffer size in media source
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ *
+ * @post Free memory for mask_buffer.
+ */
+int mv_get_mask_buffer(
+ unsigned int buffer_width,
+ unsigned int buffer_height,
+ mv_point_s *polygon,
+ unsigned int points_number,
+ unsigned char **mask_buffer);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __MEDIA_VISION_MV_MASK_BUFFER_H__ */
+
diff --git a/mv_surveillance/surveillance/include/mv_surveillance_open.h b/mv_surveillance/surveillance/include/mv_surveillance_open.h
new file mode 100644
index 00000000..e70c90b4
--- /dev/null
+++ b/mv_surveillance/surveillance/include/mv_surveillance_open.h
@@ -0,0 +1,194 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_SURVEILLANCE_OPEN_H__
+#define __MEDIA_VISION_SURVEILLANCE_OPEN_H__
+
+#include "mv_surveillance.h"
+#include "mv_surveillance_private.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @file mv_surveillance_open.h
+ * @brief This file contains the Media Vision surveillance API
+ */
+
+/**
+ * @brief Allows to subscribe to the event and start calling @a callback
+ * each time when the @a source is pushed using
+ * @ref mv_surveillance_push_source_open() and event is detected.
+ *
+ * @since_tizen 3.0
+ * @remarks To stop handling triggering use
+ * @ref mv_surveillance_unsubscribe_event_trigger_open().
+ * @param [in] event_trigger The event trigger activating calls of the
+ * @a callback function
+ * @param [in] video_stream_id The identifier of the video stream for which
+ * event trigger activation will be checked
+ * @param [in] engine_cfg The engine configuration of the event
+ * @param [in] callback Callback to be called each time when event
+ * occurrence is detected
+ * @param [in] user_data The user data to be passed to the callback function
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @post @ref mv_surveillance_event_occurred_cb
+ *
+ * @see mv_surveillance_event_trigger_s
+ * @see mv_surveillance_unsubscribe_event_trigger_open()
+ */
+int mv_surveillance_subscribe_event_trigger_open(
+ mv_surveillance_event_trigger_h event_trigger,
+ int video_stream_id,
+ mv_engine_config_h engine_cfg,
+ mv_surveillance_event_occurred_cb callback,
+ void *user_data);
+
+/**
+ * @brief Allows to unsubscribe from the event and stop calling @a callback.
+ *
+ * @since_tizen 3.0
+ * @remarks To start handling trigger activation use
+ @ref mv_surveillance_subscribe_event_trigger_open().
+ * @param [in] event_trigger The event trigger for which subscription will
+ * be stopped
+ * @param [in] video_stream_id The identifier of the video source for which
+ * subscription will be stopped
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @post @ref mv_surveillance_event_occurred_cb
+ *
+ * @see mv_surveillance_event_trigger_s
+ * @see mv_surveillance_subscribe_event_trigger_open()
+ */
+int mv_surveillance_unsubscribe_event_trigger_open(
+ mv_surveillance_event_trigger_h event_trigger,
+ int video_stream_id);
+
+/**
+ * @brief Allows to push source to the event trigger and start calling @a callback.
+ *
+ * @since_tizen 3.0
+ * @param [in] source The handle to the media source
+ * @param [in] video_stream_id The video stream, wthich will be updated
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @see mv_surveillance_event_trigger_s
+ * @see mv_surveillance_event_occurred_cb
+ * @see mv_surveillance_subscribe_event_trigger_open()
+ * @see mv_surveillance_unsubscribe_event_trigger_open()
+ */
+int mv_surveillance_push_source_open(
+ mv_source_h source,
+ int video_stream_id);
+
+/**
+ * @brief Starts traversing through list of supported event types.
+ *
+ * @since_tizen 3.0
+ * @remarks Supported event types and their descriptions can be found in
+ * @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES documentation
+ * section
+ * @param [in] callback The callback function to be called for each
+ * supported event type
+ * @param [in] user_data The user data to be passed to the @a callback
+ * function
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @see mv_surveillance_event_type_cb
+ * @see mv_surveillance_foreach_event_result_value_name_open()
+ */
+int mv_surveillance_foreach_event_type_open(
+ mv_surveillance_event_type_cb callback,
+ void *user_data);
+
+/**
+ * @brief Starts traversing through list of supported event result value names.
+ *
+ * @since_tizen 3.0
+ * @remarks Supported event types, event result value names and their
+ * descriptions can be found in
+ * @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES documentation
+ * section
+ * @param [in] event_type The name of the event type for which result value
+ * names will be passed to the @a callback. Can be
+ * set @c NULL. If set @c NULL then all supported
+ * event result value names will be traversed
+ * @param [in] callback The callback function to be called for each
+ * supported event result value name
+ * @param [in] user_data The user data to be passed to the @a callback
+ * function
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @see mv_surveillance_event_result_value_name_cb
+ * @see mv_surveillance_foreach_event_type_open()
+ * @see mv_surveillance_get_result_value_open()
+ */
+int mv_surveillance_foreach_event_result_value_name_open(
+ const char *event_type,
+ mv_surveillance_event_result_name_cb callback,
+ void *user_data);
+
+/**
+ * @brief Gets result value.
+ * @details See the output values names in the event types descriptions located
+ * in /usr/share/config/capi-media-vision/surveillance-event-types.txt.
+ *
+ * @since_tizen 3.0
+ * @param [in] result The event result
+ * @param [in] value_name The name of the value to be gotten
+ * @param [in, out] value The pointer to variable which will be filled
+ * by result value
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @pre Memory for value has to be allocated
+ *
+ * @see mv_surveillance_event_trigger_s
+ * @see mv_surveillance_event_occurred_cb
+ * @see mv_surveillance_subscribe_event_trigger_open()
+ * @see mv_surveillance_unsubscribe_event_trigger_open()
+ * @see mv_surveillance_query_events_open()
+ */
+int mv_surveillance_get_result_value_open(
+ mv_surveillance_result_h result,
+ const char *value_name,
+ void *value);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __MEDIA_VISION_SURVEILLANCE_OPEN_H__ */
diff --git a/mv_surveillance/surveillance/src/EventManager.cpp b/mv_surveillance/surveillance/src/EventManager.cpp
new file mode 100644
index 00000000..0a3a05b2
--- /dev/null
+++ b/mv_surveillance/surveillance/src/EventManager.cpp
@@ -0,0 +1,410 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EventManager.h"
+
+#include "SurveillanceHelper.h"
+
+#include "EventTriggerPersonAppearance.h"
+#include "EventTriggerPersonRecognition.h"
+#include "EventTriggerMovementDetection.h"
+
+#include <mv_private.h>
+
+namespace mediavision {
+namespace surveillance {
+
+static const int MAX_VALUE_NAME_LENGTH = 255;
+
+EventManager *EventManager::__pInstance = 0;
+EventManagerDestroyer EventManager::Destroyer;
+EventTypesMap EventManager::SupportedEventTypes;
+
+EventManagerDestroyer::~EventManagerDestroyer()
+{
+ delete __pInstance;
+}
+
+void EventManagerDestroyer::initialize(EventManager* pointer)
+{
+ __pInstance = pointer;
+}
+
+EventManager& EventManager::getInstance()
+{
+ if(!__pInstance) {
+ __pInstance = new EventManager();
+ Destroyer.initialize(__pInstance);
+ setSupportedEventTypes();
+ }
+
+ return *__pInstance;
+}
+
+void EventManager::setSupportedEventTypes()
+{
+ /* Add supported event types here */
+ SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED]
+ .push_back(MV_SURVEILLANCE_MOVEMENT_NUMBER_OF_REGIONS);
+ SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED]
+ .push_back(MV_SURVEILLANCE_MOVEMENT_REGIONS);
+
+ SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED]
+ .push_back(MV_SURVEILLANCE_PERSONS_APPEARED_NUMBER);
+ SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED]
+ .push_back(MV_SURVEILLANCE_PERSONS_DISAPPEARED_NUMBER);
+ SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED]
+ .push_back(MV_SURVEILLANCE_PERSONS_TRACKED_NUMBER);
+ SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED]
+ .push_back(MV_SURVEILLANCE_PERSONS_APPEARED_LOCATIONS);
+ SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED]
+ .push_back(MV_SURVEILLANCE_PERSONS_DISAPPEARED_LOCATIONS);
+ SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED]
+ .push_back(MV_SURVEILLANCE_PERSONS_TRACKED_LOCATIONS);
+
+ SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED]
+ .push_back(MV_SURVEILLANCE_PERSONS_RECOGNIZED_NUMBER);
+ SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED]
+ .push_back(MV_SURVEILLANCE_PERSONS_RECOGNIZED_LOCATIONS);
+ SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED]
+ .push_back(MV_SURVEILLANCE_PERSONS_RECOGNIZED_LABELS);
+ SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED]
+ .push_back(MV_SURVEILLANCE_PERSONS_RECOGNIZED_CONFIDENCES);
+}
+
+EventManager::EventManager()
+{
+ ; /* NULL */
+}
+
+EventManager::~EventManager()
+{
+ ; /* NULL */
+}
+
+int EventManager::registerEvent(
+ mv_surveillance_event_trigger_h eventTrigger,
+ long int triggerId,
+ const char *eventType,
+ int videoStreamId,
+ mv_engine_config_h engineCfg,
+ mv_surveillance_event_occurred_cb callback,
+ void *user_data,
+ int numberOfPoints,
+ mv_point_s *roi)
+{
+ if (NULL == callback || NULL == eventType) {
+ LOGE("Input event trigger or callback is NULL. Event registering failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ EventTriggersConstIter iter = __eventTriggers[videoStreamId].begin();
+
+ for (; iter != __eventTriggers[videoStreamId].end(); ++iter) {
+ if ((*iter)->isCallbackSubscribed(triggerId)) {
+ LOGE("Callback with id %d is already subscribed. "
+ "Event registering failed.", triggerId);
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+ }
+
+ /* Add appropriate event trigger here */
+ if (strncmp(eventType, MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED,
+ MAX_VALUE_NAME_LENGTH) == 0) {
+ EventTriggerPersonAppearance* trigger =
+ new EventTriggerPersonAppearance(
+ eventTrigger,
+ triggerId,
+ videoStreamId,
+ callback,
+ user_data,
+ numberOfPoints,
+ roi);
+ const int error = trigger->parseEngineConfig(engineCfg);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ delete trigger;
+
+ LOGE("Input engine configuration is wrong. Event registering failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ EventTriggersIter iter2 = isTriggerExists(trigger, videoStreamId);
+
+ if (iter2 != __eventTriggers[videoStreamId].end()) {
+ (*iter2)->subscribeCallback(
+ eventTrigger,
+ triggerId,
+ callback,
+ user_data,
+ numberOfPoints,
+ roi);
+
+ delete trigger;
+ } else {
+ __eventTriggers[videoStreamId].push_back(trigger);
+ }
+ } else if (strncmp(eventType, MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED,
+ MAX_VALUE_NAME_LENGTH) == 0) {
+ EventTriggerPersonRecognition* trigger =
+ new EventTriggerPersonRecognition(
+ eventTrigger,
+ triggerId,
+ videoStreamId,
+ callback,
+ user_data,
+ numberOfPoints,
+ roi);
+
+ const int error = trigger->parseEngineConfig(engineCfg);
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ delete trigger;
+
+ LOGE("Input engine configuration is wrong. Event registering failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ EventTriggersIter iter2 = isTriggerExists(trigger, videoStreamId);
+
+ if (iter2 != __eventTriggers[videoStreamId].end()) {
+ (*iter2)->subscribeCallback(
+ eventTrigger,
+ triggerId,
+ callback,
+ user_data,
+ numberOfPoints,
+ roi);
+
+ delete trigger;
+ } else {
+ __eventTriggers[videoStreamId].push_back(trigger);
+ }
+ } else if (strncmp(eventType, MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED,
+ MAX_VALUE_NAME_LENGTH) == 0) {
+ EventTriggerMovementDetection* trigger =
+ new EventTriggerMovementDetection(
+ eventTrigger,
+ triggerId,
+ videoStreamId,
+ callback,
+ user_data,
+ numberOfPoints,
+ roi);
+
+ const int error = trigger->parseEngineConfig(engineCfg);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ delete trigger;
+
+ LOGE("Input engine configuration is wrong. Event registering failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ EventTriggersIter iter2 = isTriggerExists(trigger, videoStreamId);
+
+ if (iter2 != __eventTriggers[videoStreamId].end()) {
+ (*iter2)->subscribeCallback(
+ eventTrigger,
+ triggerId,
+ callback,
+ user_data,
+ numberOfPoints,
+ roi);
+
+ delete trigger;
+ } else {
+ __eventTriggers[videoStreamId].push_back(trigger);
+ }
+ } else {
+ LOGE("Input event trigger has wrong type. Event registering failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int EventManager::unregisterEvent(long int triggerId, int videoStreamId)
+{
+ EventTriggersIter iter = __eventTriggers[videoStreamId].begin();
+
+ while (iter != __eventTriggers[videoStreamId].end()) {
+ if ((*iter)->unsubscribeCallback(triggerId)) {
+ if ((*iter)->isCallbacksEmpty()) {
+ delete *iter;
+ __eventTriggers[videoStreamId].erase(iter);
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+ }
+
+ ++iter;
+ }
+
+ if (iter == __eventTriggers[videoStreamId].end()) {
+ LOGE("Event trigger doesn't exist. Event unregistering failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int EventManager::pushSource(mv_source_h source, int videoStreamId)
+{
+ if (NULL == source) {
+ LOGE("Input source is NULL. Push source failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ if (__eventTriggers[videoStreamId].empty()) {
+ LOGE("There are no events yet. Push source failed.");
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ }
+
+ unsigned int width = 0;
+ unsigned int height = 0;
+ mv_colorspace_e colorspace = MEDIA_VISION_COLORSPACE_INVALID;
+
+ MEDIA_VISION_ASSERT(mv_source_get_width(source, &width),
+ "Failed to get the width.");
+ MEDIA_VISION_ASSERT(mv_source_get_height(source, &height),
+ "Failed to get the height.");
+ MEDIA_VISION_ASSERT(mv_source_get_colorspace(source, &colorspace),
+ "Failed to get the colorspace.");
+
+ cv::Mat grayImage;
+
+ int error = MEDIA_VISION_ERROR_NONE;
+
+#ifdef ENABLE_NEON
+ if (colorspace == MEDIA_VISION_COLORSPACE_RGB888 && (width * height % 8) == 0)
+ error = SurveillanceHelper::convertSourceMVRGB2GrayCVNeon(source, grayImage);
+ else
+#endif /* ENABLE_NEON */
+ error = SurveillanceHelper::convertSourceMV2GrayCV(source, grayImage);
+
+ if (error != MEDIA_VISION_ERROR_NONE || grayImage.empty()) {
+ LOGE("Media source conversion failed.");
+ return error;
+ }
+
+ mv_source_h graySource;
+ error = mv_create_source(&graySource);
+ if (MEDIA_VISION_ERROR_NONE != error) {
+ LOGE("Errors were occurred during source creating %i", error);
+ return error;
+ }
+
+ error = mv_source_fill_by_buffer(
+ graySource,
+ grayImage.data,
+ grayImage.cols * grayImage.rows,
+ grayImage.cols,
+ grayImage.rows,
+ MEDIA_VISION_COLORSPACE_Y800);
+
+ if (MEDIA_VISION_ERROR_NONE != error) {
+ mv_destroy_source(graySource);
+ LOGE("Errors were occurred during source filling %i", error);
+ return error;
+ }
+
+ EventTriggersConstIter iter = __eventTriggers[videoStreamId].begin();
+
+ for (; iter != __eventTriggers[videoStreamId].end(); ++iter) {
+ error = (*iter)->pushSource(source, graySource, grayImage);
+
+ if (error != MEDIA_VISION_ERROR_NONE)
+ LOGE("Push source failed for event ", (*iter)->getEventType().c_str());
+ }
+
+ error = mv_destroy_source(graySource);
+
+ if (MEDIA_VISION_ERROR_NONE != error)
+ LOGE("Errors were occurred during gray source destroying %i", error);
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int EventManager::getSupportedEventTypes(StringVector& eventTypes)
+{
+ eventTypes.clear();
+
+ if (!__pInstance)
+ setSupportedEventTypes();
+
+ EventTypesMapConstIter etIter = SupportedEventTypes.begin();
+ while (etIter != SupportedEventTypes.end()) {
+ eventTypes.push_back(etIter->first);
+ ++etIter;
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int EventManager::getSupportedEventResultValueNames(
+ StringVector& eventResValNames)
+{
+ eventResValNames.clear();
+
+ if (!__pInstance)
+ setSupportedEventTypes();
+
+ EventTypesMapConstIter etIter = SupportedEventTypes.begin();
+ while (etIter != SupportedEventTypes.end()) {
+ eventResValNames.insert(
+ eventResValNames.end(),
+ etIter->second.begin(),
+ etIter->second.end());
+ ++etIter;
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int EventManager::getSupportedEventResultValueNames(
+ const std::string& eventTypeName,
+ StringVector& eventResValNames)
+{
+ eventResValNames.clear();
+
+ if (!__pInstance)
+ setSupportedEventTypes();
+
+ EventTypesMapConstIter etIter = SupportedEventTypes.find(eventTypeName);
+ if (etIter == SupportedEventTypes.end())
+ return MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE;
+
+ eventResValNames = etIter->second;
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+EventTriggersIter EventManager::isTriggerExists(
+ EventTrigger* trigger,
+ int videoStreamId)
+{
+ EventTriggersIter iter = __eventTriggers[videoStreamId].begin();
+
+ for (; iter != __eventTriggers[videoStreamId].end(); ++iter)
+ if (*(*iter) == *trigger)
+ return iter;
+
+ return iter;
+}
+
+} /* surveillance */
+} /* mediavision */
+
diff --git a/mv_surveillance/surveillance/src/EventTrigger.cpp b/mv_surveillance/surveillance/src/EventTrigger.cpp
new file mode 100644
index 00000000..d6b4cecb
--- /dev/null
+++ b/mv_surveillance/surveillance/src/EventTrigger.cpp
@@ -0,0 +1,197 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EventTrigger.h"
+
+#include <mv_private.h>
+#include <mv_mask_buffer.h>
+#include <mv_apply_mask.h>
+
+namespace mediavision {
+namespace surveillance {
+
+long int EventTrigger::InternalTriggersCounter = -1l;
+
+EventTrigger::EventTrigger(
+ mv_surveillance_event_trigger_h eventTrigger,
+ long int triggerId,
+ int videoStreamId,
+ mv_surveillance_event_occurred_cb callback,
+ void *userData,
+ int numberOfPoints,
+ mv_point_s *roi):
+ __videoStreamId(videoStreamId),
+ __roi(numberOfPoints)
+{
+ CallbackData callbackData;
+ callbackData.eventTrigger = eventTrigger;
+ callbackData.callback = callback;
+ callbackData.userData = userData;
+
+ __callbackDataMap.insert(CallbackDataPair(triggerId, callbackData));
+
+ for (int i = 0; i < numberOfPoints; ++i)
+ __roi[i] = roi[i];
+}
+
+EventTrigger::~EventTrigger()
+{
+ ; /* NULL */
+}
+
+int EventTrigger::getVideoStreamId() const
+{
+ return __videoStreamId;
+}
+
+bool EventTrigger::isCallbackSubscribed(long int triggerId) const
+{
+ return __callbackDataMap.find(triggerId) != __callbackDataMap.end();
+}
+
+bool EventTrigger::subscribeCallback(
+ mv_surveillance_event_trigger_h eventTrigger,
+ long int triggerId,
+ mv_surveillance_event_occurred_cb callback,
+ void *userData,
+ int numberOfPoints,
+ mv_point_s *roi)
+{
+ if (isCallbackSubscribed(triggerId)) {
+ LOGE("Callback with id %d is already subscribed. "
+ "Callback subscribing failed.", triggerId);
+ return false;
+ }
+
+ CallbackData callbackData;
+ callbackData.eventTrigger = eventTrigger;
+ callbackData.callback = callback;
+ callbackData.userData = userData;
+
+ __callbackDataMap.insert(CallbackDataPair(triggerId, callbackData));
+
+ /* TODO: implement support of multiple ROI */
+ __roi.clear();
+ __roi.resize(numberOfPoints);
+
+ for (int i = 0; i < numberOfPoints; ++i)
+ __roi[i] = roi[i];
+
+ return true;
+}
+
+bool EventTrigger::unsubscribeCallback(long int triggerId)
+{
+ CallbackDataMapIter iter = __callbackDataMap.find(triggerId);
+
+ if (iter == __callbackDataMap.end()) {
+ LOGE("Callback with id %d was not subscribed. "
+ "Callback unsubscribing failed.", triggerId);
+ return false;
+ }
+
+ iter->second.callback = NULL;
+ iter->second.userData = NULL;
+ __callbackDataMap.erase(iter);
+
+ return true;
+}
+
+bool EventTrigger::isCallbacksEmpty() const
+{
+ return __callbackDataMap.empty();
+}
+
+int EventTrigger::applyROIToImage(
+ unsigned char *image,
+ int imageWidth,
+ int imageHeight,
+ bool scalePoints,
+ int scaleX,
+ int scaleY)
+{
+ const size_t roiSize = __roi.size();
+
+ if (roiSize >= 3) {
+ MVPoints scaledPoints = __roi;
+
+ if (scalePoints)
+ for (size_t i = 0u; i < roiSize; ++i) {
+ scaledPoints[i].x /= scaleX;
+ scaledPoints[i].y /= scaleY;
+ }
+
+ unsigned char *maskBuffer = NULL;
+
+ int error = mv_get_mask_buffer(
+ imageWidth,
+ imageHeight,
+ scaledPoints.data(),
+ (int) roiSize,
+ &maskBuffer);
+
+ if (error != MEDIA_VISION_ERROR_NONE || maskBuffer == NULL) {
+ if (maskBuffer != NULL)
+ delete maskBuffer;
+
+ LOGE("Getting mask buffer failed.");
+ return error;
+ }
+
+ error = mv_apply_mask(
+ image,
+ maskBuffer,
+ imageWidth / 16 * 16,
+ imageHeight,
+ imageWidth,
+ image);
+
+ delete maskBuffer;
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ LOGE("Applying mask buffer failed.");
+ return error;
+ }
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+bool EventTrigger::operator==(const EventTrigger& other) const
+{
+ const std::string currentEventType = this->getEventType();
+ const std::string otherEventType = other.getEventType();
+
+ if (__videoStreamId != other.__videoStreamId ||
+ currentEventType.compare(otherEventType) != 0 ||
+ __roi.size() != other.__roi.size())
+ return false;
+
+ size_t size = __roi.size();
+ for (size_t i = 0; i < size; ++i)
+ if (__roi[i].x != other.__roi[i].x || __roi[i].y != other.__roi[i].y)
+ return false;
+
+ return true;
+}
+
+bool EventTrigger::operator!=(const EventTrigger& other) const
+{
+ return !(*this == other);
+}
+
+} /* surveillance */
+} /* mediavision */
diff --git a/mv_surveillance/surveillance/src/EventTriggerMovementDetection.cpp b/mv_surveillance/surveillance/src/EventTriggerMovementDetection.cpp
new file mode 100644
index 00000000..cc6ee91d
--- /dev/null
+++ b/mv_surveillance/surveillance/src/EventTriggerMovementDetection.cpp
@@ -0,0 +1,290 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EventTriggerMovementDetection.h"
+
+#include "EventDefs.h"
+#include "mv_absdiff.h"
+#include "SurveillanceHelper.h"
+
+#include <mv_private.h>
+
+#include "opencv2/highgui/highgui.hpp"
+
+namespace mediavision {
+namespace surveillance {
+
+static const int DEFAULT_DIFF_THRESHOLD = 10;
+
+static const int MAX_VALUE_NAME_LENGTH = 255;
+
+const cv::Mat EventTriggerMovementDetection::__ERODE_KERNEL =
+ cv::getStructuringElement(cv::MORPH_RECT, cv::Size(4, 4));
+
+const cv::Mat EventTriggerMovementDetection::__DILATE_KERNEL =
+ cv::getStructuringElement(cv::MORPH_RECT, cv::Size(24, 24));
+
+static const cv::Rect DEFAULT_RECT = cv::Rect(0, 0, 0, 0);
+
+namespace {
+
+inline void convertRectCV2MV(const cv::Rect& src, mv_rectangle_s& dst)
+{
+ dst.point.x = src.x;
+ dst.point.y = src.y;
+ dst.width = src.width;
+ dst.height = src.height;
+}
+
+void mergeOverlappedRects(CVRectangles& rects)
+{
+ const size_t rectsSize = rects.size();
+
+ for (size_t i = 0; i < rectsSize; ++i) {
+ const int area1 = rects[i].area();
+
+ for (size_t j = i + 1; j < rectsSize; ++j) {
+ const int area2 = rects[j].area();
+ const int intersectionArea = (rects[i] & rects[j]).area();
+
+ if (intersectionArea != 0 &&
+ intersectionArea > std::min(area1, area2) / 2) {
+ rects[i] |= rects[j];
+ rects[j] = DEFAULT_RECT;
+ }
+ }
+ }
+}
+
+} /* anonymous namespace */
+
+int EventResultMovementDetection::getResultValue(
+ const char *valueName,
+ void *value) const
+{
+ if (valueName == NULL) {
+ LOGE("Invalid pointer for value name. Getting result value failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ if (value == NULL) {
+ LOGE("Invalid pointer for value. Getting result value failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ if (strncmp(valueName, MV_SURVEILLANCE_MOVEMENT_NUMBER_OF_REGIONS,
+ MAX_VALUE_NAME_LENGTH) == 0) {
+ size_t *const numberOfDetectedMovements = (size_t*) value;
+ *numberOfDetectedMovements = __movementRegions.size();
+ } else if (strncmp(valueName, MV_SURVEILLANCE_MOVEMENT_REGIONS,
+ MAX_VALUE_NAME_LENGTH) == 0) {
+ mv_rectangle_s *const movementsRegions = (mv_rectangle_s*) value;
+
+ const size_t numberOfDetectedMovements = __movementRegions.size();
+
+ for (size_t i = 0u; i < numberOfDetectedMovements; ++i) {
+ movementsRegions[i] = __movementRegions[i];
+ }
+ } else {
+ LOGE("This value name doesn't exist. Getting result value failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+EventTriggerMovementDetection::EventTriggerMovementDetection(
+ mv_surveillance_event_trigger_h eventTrigger,
+ long int triggerId,
+ int videoStreamId,
+ mv_surveillance_event_occurred_cb callback,
+ void *userData,
+ int numberOfPoints,
+ mv_point_s *roi) : EventTrigger(
+ eventTrigger,
+ triggerId,
+ videoStreamId,
+ callback,
+ userData,
+ numberOfPoints,
+ roi),
+ __previousImage(),
+ __eventResult(new EventResultMovementDetection()),
+ __diffThreshold(DEFAULT_DIFF_THRESHOLD)
+{
+ ; /* NULL */
+}
+
+EventTriggerMovementDetection::~EventTriggerMovementDetection()
+{
+ delete __eventResult;
+}
+
+int EventTriggerMovementDetection::parseEngineConfig(mv_engine_config_h engineConfig)
+{
+ if (NULL == engineConfig) {
+ LOGI("Default value for movement detection threshold was set.");
+ return MEDIA_VISION_ERROR_NONE;
+ }
+
+ const int error = mv_engine_config_get_int_attribute(
+ engineConfig,
+ MV_SURVEILLANCE_MOVEMENT_DETECTION_THRESHOLD,
+ &__diffThreshold);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ LOGE("Getting movement detection threshold from engine configuration failed.");
+ return error;
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int EventTriggerMovementDetection::pushSource(
+ mv_source_h source,
+ mv_source_h graySource,
+ const cv::Mat& grayImage)
+{
+ if (source == NULL || graySource == NULL || grayImage.empty()) {
+ LOGE("Media source is NULL. Pushing source failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ __eventResult->__movementRegions.clear();
+
+ int error = MEDIA_VISION_ERROR_NONE;
+
+ if (__previousImage.empty()) {
+ __previousImage = grayImage.clone();
+
+ LOGI("Previous media source is empty. Push next source.");
+ return error;
+ }
+
+ cv::Mat image = grayImage.clone();
+
+ const int bufSize = image.cols * image.rows * sizeof(uint8_t);
+ uint8_t *diffBuffer = (uint8_t*) malloc(bufSize * sizeof(uint8_t));
+ memset(diffBuffer, 0, bufSize);
+
+ error = mv_absdiff(
+ image.data,
+ __previousImage.data,
+ image.cols,
+ image.rows,
+ image.cols,
+ diffBuffer);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ LOGE("Absolute difference calculation failed. Pushing source failed.");
+ return error;
+ }
+
+ error = applyROIToImage(diffBuffer, image.cols, image.rows);
+
+ if (error != MEDIA_VISION_ERROR_NONE || image.empty()) {
+ LOGE("Applying ROI failed with error %d.", error);
+ return error;
+ }
+
+ cv::Mat imgDiff = cv::Mat(cv::Size(image.cols, image.rows),
+ CV_8UC1, diffBuffer);
+
+ cv::erode(imgDiff, imgDiff, __ERODE_KERNEL);
+ cv::dilate(imgDiff, imgDiff, __DILATE_KERNEL);
+
+ cv::threshold(imgDiff, imgDiff, __diffThreshold, 255, CV_THRESH_BINARY);
+
+ Contours contours;
+
+ cv::findContours(imgDiff, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
+
+ free(diffBuffer);
+
+ const size_t contoursSize = contours.size();
+ CVRectangles rects(contoursSize);
+
+ for (size_t i = 0u; i < contoursSize; ++i)
+ rects[i] = cv::boundingRect(cv::Mat(contours[i]));
+
+ mergeOverlappedRects(rects);
+
+ const size_t roiSize = __roi.size();
+ CVPoints roi(roiSize);
+
+ cv::Rect roiRect(0, 0, imgDiff.cols, imgDiff.rows);
+
+ if (roiSize >= 3u) {
+ for (size_t i = 0u; i < roiSize; ++i)
+ roi[i] = cv::Point(__roi[i].x, __roi[i].y);
+
+ roiRect = cv::boundingRect(roi);
+ }
+
+ const size_t rectsSize = rects.size();
+ for (size_t i = 0u; i < rectsSize; ++i)
+ if (rects[i] != DEFAULT_RECT &&
+ roiRect.contains(rects[i].tl()) &&
+ roiRect.contains(rects[i].br())) {
+ mv_rectangle_s rectMV;
+ convertRectCV2MV(rects[i], rectMV);
+
+ __eventResult->__movementRegions.push_back(rectMV);
+ }
+
+ __previousImage = image;
+ __eventResult->__grayImage = __previousImage;
+
+ // Don't invoke the callback if movement wasn't detected at the frame
+ if (__eventResult->__movementRegions.size() > 0) {
+ CallbackDataMapConstIter iter = __callbackDataMap.begin();
+
+ for (; iter != __callbackDataMap.end(); ++iter) {
+ mv_surveillance_event_occurred_cb callback = iter->second.callback;
+ callback(
+ iter->second.eventTrigger,
+ source,
+ __videoStreamId,
+ __eventResult,
+ iter->second.userData);
+ }
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+std::string EventTriggerMovementDetection::getEventType() const
+{
+ return MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED;
+}
+
+bool EventTriggerMovementDetection::operator==(const EventTriggerMovementDetection& other) const
+{
+ if (EventTrigger::operator !=(other))
+ return false;
+
+ /* TODO: compare private values if necessary */
+
+ return true;
+}
+
+bool EventTriggerMovementDetection::operator!=(const EventTriggerMovementDetection& other) const
+{
+ return !(*this == other);
+}
+
+} /* surveillance */
+} /* mediavision */
diff --git a/mv_surveillance/surveillance/src/EventTriggerPersonAppearance.cpp b/mv_surveillance/surveillance/src/EventTriggerPersonAppearance.cpp
new file mode 100644
index 00000000..ca14d450
--- /dev/null
+++ b/mv_surveillance/surveillance/src/EventTriggerPersonAppearance.cpp
@@ -0,0 +1,460 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EventTriggerPersonAppearance.h"
+
+#include "EventManager.h"
+#include "FaceDetector.h"
+#include "SurveillanceHelper.h"
+#include "EventTriggerMovementDetection.h"
+
+#include "opencv2/opencv.hpp"
+#include "opencv2/highgui/highgui.hpp"
+
+#include <mv_private.h>
+
+#include <sys/time.h>
+#include <unistd.h>
+
+namespace mediavision {
+namespace surveillance {
+
+using namespace cv;
+
+static const int MAX_VALUE_NAME_LENGHT = 255;
+
+static const int DEFAULT_SKIP_FRAMES_COUNT = 6;
+
+static const int DEFAULT_FRAME_WIDTH = 640;
+
+static const int DEFAULT_FRAME_HEIGHT = 480;
+
+static const cv::Size DEFAULT_FRAME_SIZE(DEFAULT_FRAME_WIDTH, DEFAULT_FRAME_HEIGHT);
+
+static const cv::Rect ALL_IMAGE_RECT(0, 0, DEFAULT_FRAME_WIDTH, DEFAULT_FRAME_HEIGHT);
+
+static const cv::Size DEFAULT_DETECTION_STEPS = cv::Size(8, 8);
+
+static const std::vector<float> DEFAULT_SVM_PEOPLE_DETECTOR =
+ cv::HOGDescriptor::getDefaultPeopleDetector();
+
+namespace {
+
+inline void convertRectMV2CV(const mv_rectangle_s& src, cv::Rect& dst)
+{
+ dst.x = src.point.x;
+ dst.y = src.point.y;
+ dst.width = src.width;
+ dst.height = src.height;
+}
+
+inline void convertRectCV2MV(const cv::Rect& src, mv_rectangle_s& dst)
+{
+ dst.point.x = src.x;
+ dst.point.y = src.y;
+ dst.width = src.width;
+ dst.height = src.height;
+}
+
+} /* Anonymous namespace*/
+
+int EventResultPersonAppearance::getResultValue(const char *valueName,
+ void *value) const
+{
+ if (valueName == NULL) {
+ LOGE("Invalid pointer for value name. Getting result value failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ if (value == NULL) {
+ LOGE("Invalid pointer for value. Getting result value failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ if (strncmp(valueName, MV_SURVEILLANCE_PERSONS_APPEARED_NUMBER,
+ MAX_VALUE_NAME_LENGHT) == 0) {
+ size_t * const numberOfAppearedPersons = (size_t*) value;
+ *numberOfAppearedPersons = __appearedLocations.size();
+ }
+ else if (strncmp(valueName, MV_SURVEILLANCE_PERSONS_APPEARED_LOCATIONS,
+ MAX_VALUE_NAME_LENGHT) == 0) {
+ mv_rectangle_s * const appearedLocations = (mv_rectangle_s*) value;
+
+ const size_t numberOfAppearedPersons = __appearedLocations.size();
+
+ for (size_t i = 0u; i < numberOfAppearedPersons; ++i)
+ appearedLocations[i] = __appearedLocations[i];
+ }
+ else if (strncmp(valueName, MV_SURVEILLANCE_PERSONS_TRACKED_NUMBER,
+ MAX_VALUE_NAME_LENGHT) == 0) {
+ size_t * const numberOfTrackedPersons = (size_t*) value;
+ *numberOfTrackedPersons = __trackedLocations.size();
+ }
+ else if (strncmp(valueName, MV_SURVEILLANCE_PERSONS_TRACKED_LOCATIONS,
+ MAX_VALUE_NAME_LENGHT) == 0) {
+ mv_rectangle_s * const trackedLocations = (mv_rectangle_s*) value;
+
+ const size_t numberOfTrackedPersons = __trackedLocations.size();
+
+ for (size_t i = 0u; i < numberOfTrackedPersons; ++i)
+ trackedLocations[i] = __trackedLocations[i];
+ }
+ else if (strncmp(valueName, MV_SURVEILLANCE_PERSONS_DISAPPEARED_NUMBER,
+ MAX_VALUE_NAME_LENGHT) == 0) {
+ size_t * const numberOfDisappearedPersons = (size_t*) value;
+ *numberOfDisappearedPersons = __disappearedLocations.size();
+ }
+ else if (strncmp(valueName, MV_SURVEILLANCE_PERSONS_DISAPPEARED_LOCATIONS,
+ MAX_VALUE_NAME_LENGHT) == 0) {
+ mv_rectangle_s * const disappearedLocations = (mv_rectangle_s*) value;
+
+ const size_t numberOfDisappearedPersons = __disappearedLocations.size();
+
+ for (size_t i = 0u; i < numberOfDisappearedPersons; ++i)
+ disappearedLocations[i] = __disappearedLocations[i];
+ }
+ else {
+ LOGE("This value name doesn't exist. Getting result value failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+EventTriggerPersonAppearance::EventTriggerPersonAppearance(
+ mv_surveillance_event_trigger_h eventTrigger, long int triggerId,
+ int videoStreamId, mv_surveillance_event_occurred_cb callback,
+ void *userData, int numberOfPoints, mv_point_s *roi) :
+ EventTrigger(eventTrigger, triggerId, videoStreamId, callback, userData,
+ numberOfPoints, roi), __skipFramesCount(DEFAULT_SKIP_FRAMES_COUNT),
+ __frameCounter(0), __movementDetectedEventId(InternalTriggersCounter--),
+ __factorX(1.f), __factorY(1.f), __rectToDetect(ALL_IMAGE_RECT),
+ __rectToDetectPrevious(ALL_IMAGE_RECT), __trackedRects(),
+ __appearedRects(), __disappearedRects(), __hogClassifier(),
+ __eventResult(new EventResultPersonAppearance())
+{
+ __hogClassifier.setSVMDetector(DEFAULT_SVM_PEOPLE_DETECTOR);
+
+ EventManager::getInstance().registerEvent(
+ NULL, __movementDetectedEventId,
+ MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED, videoStreamId,
+ NULL, movementDetectedCB, this, numberOfPoints, roi);
+}
+
+EventTriggerPersonAppearance::~EventTriggerPersonAppearance()
+{
+ EventManager::getInstance().unregisterEvent(__movementDetectedEventId,
+ __videoStreamId);
+
+ delete __eventResult;
+}
+
+int EventTriggerPersonAppearance::parseEngineConfig(
+ mv_engine_config_h engineConfig)
+{
+ if (NULL == engineConfig) {
+ LOGI("Default value for frame skip count was set.");
+ return MEDIA_VISION_ERROR_NONE;
+ }
+
+ const int error = mv_engine_config_get_int_attribute(engineConfig,
+ MV_SURVEILLANCE_SKIP_FRAMES_COUNT, &__skipFramesCount);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ LOGE("Getting frame skip count from engine configuration failed.");
+ return error;
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int EventTriggerPersonAppearance::pushSource(mv_source_h source,
+ mv_source_h graySource, const cv::Mat& grayImage)
+{
+ if (source == NULL || graySource == NULL || grayImage.empty()) {
+ LOGE("Media source is NULL. Pushing source failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+std::string EventTriggerPersonAppearance::getEventType() const
+{
+ return MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED;
+}
+
+bool EventTriggerPersonAppearance::operator==(
+ const EventTriggerPersonAppearance& other) const
+{
+ if (EventTrigger::operator !=(other))
+ return false;
+
+ /* TODO: compare private values if necessary */
+
+ return true;
+}
+
+bool EventTriggerPersonAppearance::operator!=(
+ const EventTriggerPersonAppearance& other) const
+{
+ return !(*this == other);
+}
+
+void EventTriggerPersonAppearance::movementDetectedCB(
+ mv_surveillance_event_trigger_h /*event_trigger*/, mv_source_h source,
+ int /*video_stream_id*/, mv_surveillance_result_h event_result,
+ void *user_data)
+{
+ EventTriggerPersonAppearance *trigger =
+ (EventTriggerPersonAppearance*) user_data;
+
+ /* 1. Get input image in grayscale and resize it */
+ EventResultMovementDetection *result =
+ static_cast<EventResultMovementDetection*>(event_result);
+
+ cv::Mat resizedImage;
+ cv::resize(result->__grayImage, resizedImage, DEFAULT_FRAME_SIZE);
+
+ int error = trigger->applyROIToImage(resizedImage.data, resizedImage.cols,
+ resizedImage.rows, true, DEFAULT_FRAME_WIDTH, DEFAULT_FRAME_HEIGHT);
+
+ if (error != MEDIA_VISION_ERROR_NONE || resizedImage.empty()) {
+ trigger->runCallbacks(source);
+ LOGE("Applying ROI failed with error %d.", error);
+ return;
+ }
+
+ trigger->__factorX = (float) DEFAULT_FRAME_WIDTH / result->__grayImage.cols;
+ trigger->__factorY = (float) DEFAULT_FRAME_HEIGHT / result->__grayImage.rows;
+
+ /* 2. Get detected movement regions */
+ const size_t numberOfMovementRegions = result->__movementRegions.size();
+ CVRectangles movementRegions(numberOfMovementRegions);
+
+ for (size_t i = 0u; i < numberOfMovementRegions; ++i) {
+ convertRectMV2CV(result->__movementRegions[i], movementRegions[i]);
+ movementRegions[i].x *= trigger->__factorX;
+ movementRegions[i].y *= trigger->__factorY;
+ movementRegions[i].width *= trigger->__factorX;
+ movementRegions[i].height *= trigger->__factorY;
+ }
+
+ /* 3. Calculate rectangle where person will be detect */
+ if (movementRegions.empty()) {
+ trigger->__rectToDetect = ALL_IMAGE_RECT;
+ } else {
+ trigger->__rectToDetect = movementRegions[0];
+
+ for (size_t j = 1u; j < numberOfMovementRegions; ++j)
+ trigger->__rectToDetect |= movementRegions[j];
+
+ if (trigger->__rectToDetect.width
+ < trigger->__hogClassifier.winSize.width
+ || trigger->__rectToDetect.height
+ < trigger->__hogClassifier.winSize.height)
+ trigger->__rectToDetect |= trigger->__rectToDetectPrevious;
+ }
+
+ trigger->__rectToDetect &= ALL_IMAGE_RECT;
+
+ /* 4. Perform Hog detector or try to track using movement regions */
+ if ((trigger->__skipFramesCount == 0 ||
+ trigger->__frameCounter % trigger->__skipFramesCount == 0) &&
+ (trigger->__rectToDetect != ALL_IMAGE_RECT)) {
+ /* 4.1 Perform Hog detector */
+ TrackedRectanglesConstIter iter = trigger->__trackedRects.begin();
+ for (; iter != trigger->__trackedRects.end(); ++iter)
+ trigger->__rectToDetect |= iter->rect;
+
+ // Slightly extend detection area...
+ const int xShift = .25f * trigger->__rectToDetect.width;
+ const int yShift = .25f * trigger->__rectToDetect.height;
+ trigger->__rectToDetect.x -= xShift / 2;
+ trigger->__rectToDetect.y -= yShift / 2;
+ trigger->__rectToDetect.width += xShift;
+ trigger->__rectToDetect.height += yShift;
+ trigger->__rectToDetect &= ALL_IMAGE_RECT;
+ // and fit it to the HOG cell size
+ const int xRest = trigger->__rectToDetect.width % 8;
+ const int yRest = trigger->__rectToDetect.height % 8;
+ trigger->__rectToDetect.x += xRest / 2;
+ trigger->__rectToDetect.y += yRest / 2;
+ trigger->__rectToDetect.width -= xRest;
+ trigger->__rectToDetect.height -= yRest;
+
+ CVRectangles hogRects;
+
+ trigger->__hogClassifier.detectMultiScale(
+ resizedImage(trigger->__rectToDetect), hogRects, 0,
+ DEFAULT_DETECTION_STEPS, cv::Size(32, 32), 1.059, 2);
+
+ const size_t hogRectsSize = hogRects.size();
+
+ for (size_t i = 0u; i < hogRectsSize; ++i) {
+ hogRects[i].x += trigger->__rectToDetect.x;
+ hogRects[i].y += trigger->__rectToDetect.y;
+ }
+
+ std::vector<bool> trackChecks(hogRectsSize, false);
+ TrackedRectanglesIter trackRectIter = trigger->__trackedRects.begin();
+ for (; trackRectIter != trigger->__trackedRects.end();
+ ++trackRectIter) {
+ size_t bestArea = 0;
+ size_t bestIdx = 0;
+ for (size_t idx = 0u; idx < hogRectsSize; ++idx) {
+ if (trackChecks[idx])
+ continue;
+ const size_t curArea =
+ (hogRects[idx] & trackRectIter->rect).area();
+ if (bestArea < curArea) {
+ bestArea = curArea;
+ bestIdx = idx;
+ }
+ }
+ if (bestArea > 10) {
+ trackChecks[bestIdx] = true;
+ trackRectIter->rect = hogRects[bestIdx];
+ }
+ }
+
+ trigger->__appearedRects.clear();
+ for (size_t idx = 0u; idx < hogRectsSize; ++idx)
+ if (!trackChecks[idx])
+ trigger->__appearedRects.push_back(hogRects[idx]);
+ }
+ else {
+ /* 4.2 Try to track */
+ CVRectanglesConstIter appearedIter = trigger->__appearedRects.begin();
+ for (; appearedIter != trigger->__appearedRects.end(); ++appearedIter)
+ trigger->__trackedRects.push_back(
+ TrackedRectangle(*appearedIter, 7));
+
+ trigger->__appearedRects.clear();
+
+ TrackedRectanglesIter iter = trigger->__trackedRects.begin();
+ while (iter != trigger->__trackedRects.end()) {
+ bool tracked = false;
+
+ for (size_t j = 0u; j < numberOfMovementRegions; ++j) {
+ cv::Rect rect = iter->rect;
+ if ((rect & movementRegions[j]).area() != 0 &&
+ movementRegions[j].area() <= 3 * rect.area() / 2) {
+ cv::Rect r1 = rect | movementRegions[j];
+ const int dx = r1.width - rect.width;
+ const int dy = r1.height - rect.height;
+
+ if (r1.x < movementRegions[j].x)
+ r1.x += dx;
+ else if (r1.x > movementRegions[j].x)
+ r1.x -= dx;
+
+ if (r1.y < movementRegions[j].y)
+ r1.y += dy;
+ else if (r1.y > movementRegions[j].y)
+ r1.y -= dy;
+
+ r1.height = rect.height;
+ r1.width = rect.width;
+
+ iter->rect = r1;
+
+ tracked = true;
+ }
+ }
+
+ if (tracked)
+ ++iter;
+ else {
+ if (iter->framesCount == 0) {
+ trigger->__disappearedRects.push_back(iter->rect);
+ iter = trigger->__trackedRects.erase(iter);
+ }
+ else {
+ --(iter->framesCount);
+ ++iter;
+ }
+ }
+ }
+ }
+
+ trigger->__rectToDetectPrevious = trigger->__rectToDetect;
+ ++trigger->__frameCounter;
+
+ /* 5. Update event result and run callbacks */
+ trigger->runCallbacks(source);
+
+ trigger->__disappearedRects.clear();
+}
+
+void EventTriggerPersonAppearance::runCallbacks(mv_source_h source)
+{
+ __eventResult->__appearedLocations.clear();
+ __eventResult->__disappearedLocations.clear();
+ __eventResult->__trackedLocations.clear();
+
+ const size_t appearedLocationsSize = __appearedRects.size();
+ __eventResult->__appearedLocations.resize(appearedLocationsSize);
+
+ for (size_t i = 0u; i < appearedLocationsSize; ++i) {
+ convertRectCV2MV(__appearedRects[i],
+ __eventResult->__appearedLocations[i]);
+ __eventResult->__appearedLocations[i].point.x /= __factorX;
+ __eventResult->__appearedLocations[i].point.y /= __factorY;
+ __eventResult->__appearedLocations[i].width /= __factorX;
+ __eventResult->__appearedLocations[i].height /= __factorY;
+ }
+
+ const size_t disappearedLocationsSize = __disappearedRects.size();
+ __eventResult->__disappearedLocations.resize(disappearedLocationsSize);
+
+ for (size_t i = 0u; i < disappearedLocationsSize; ++i) {
+ convertRectCV2MV(__disappearedRects[i],
+ __eventResult->__disappearedLocations[i]);
+ __eventResult->__disappearedLocations[i].point.x /= __factorX;
+ __eventResult->__disappearedLocations[i].point.y /= __factorY;
+ __eventResult->__disappearedLocations[i].width /= __factorX;
+ __eventResult->__disappearedLocations[i].height /= __factorY;
+ }
+
+ const size_t trackedLocationsSize = __trackedRects.size();
+ __eventResult->__trackedLocations.resize(trackedLocationsSize);
+
+ TrackedRectanglesConstIter trackedIter = __trackedRects.begin();
+ for (size_t i = 0u; i < trackedLocationsSize; ++i, ++trackedIter) {
+ convertRectCV2MV(trackedIter->rect,
+ __eventResult->__trackedLocations[i]);
+ __eventResult->__trackedLocations[i].point.x /= __factorX;
+ __eventResult->__trackedLocations[i].point.y /= __factorY;
+ __eventResult->__trackedLocations[i].width /= __factorX;
+ __eventResult->__trackedLocations[i].height /= __factorY;
+ }
+
+ // Don't invoke the callback if no appearance, disappearance or tracking
+ if (appearedLocationsSize > 0 || disappearedLocationsSize > 0
+ || trackedLocationsSize > 0) {
+ CallbackDataMapConstIter iter = __callbackDataMap.begin();
+
+ for (; iter != __callbackDataMap.end(); ++iter) {
+ mv_surveillance_event_occurred_cb callback = iter->second.callback;
+ callback(iter->second.eventTrigger, source, __videoStreamId,
+ __eventResult, iter->second.userData);
+ }
+ }
+}
+
+} /* surveillance */
+} /* mediavision */
diff --git a/mv_surveillance/surveillance/src/EventTriggerPersonRecognition.cpp b/mv_surveillance/surveillance/src/EventTriggerPersonRecognition.cpp
new file mode 100644
index 00000000..7b28709a
--- /dev/null
+++ b/mv_surveillance/surveillance/src/EventTriggerPersonRecognition.cpp
@@ -0,0 +1,397 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EventTriggerPersonRecognition.h"
+#include "EventManager.h"
+
+#include <mv_private.h>
+#include <mv_face.h>
+#include <mv_surveillance.h>
+
+#include <sstream>
+
+namespace mediavision {
+namespace surveillance {
+
+static const int MAX_VALUE_NAME_LENGHT = 255;
+
+namespace {
+
+template <typename T>
+std::string numberToString(T Number)
+{
+ std::ostringstream ss;
+ ss << Number;
+ return ss.str();
+}
+
+} /* Anonymous namespace*/
+
+int EventResultPersonRecognition::getResultValue(
+ const char *valueName,
+ void *value) const
+{
+ if (valueName == NULL) {
+ LOGE("Invalid pointer for value name. Getting result value failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ if (value == NULL) {
+ LOGE("Invalid pointer for value. Getting result value failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ const size_t numberOfPersons = __locations.size();
+
+ if (strncmp(valueName,
+ MV_SURVEILLANCE_PERSONS_RECOGNIZED_NUMBER,
+ MAX_VALUE_NAME_LENGHT) == 0) {
+ size_t *outNumberOfPersons = (size_t*) value;
+ *outNumberOfPersons = numberOfPersons;
+ } else if (strncmp(valueName,
+ MV_SURVEILLANCE_PERSONS_RECOGNIZED_LOCATIONS,
+ MAX_VALUE_NAME_LENGHT) == 0) {
+ mv_rectangle_s *locations = (mv_rectangle_s*) value;
+
+ for (size_t i = 0; i < numberOfPersons; ++i)
+ locations[i] = __locations[i];
+ } else if (strncmp(valueName,
+ MV_SURVEILLANCE_PERSONS_RECOGNIZED_LABELS,
+ MAX_VALUE_NAME_LENGHT) == 0) {
+ int *labels = (int*) value;
+
+ for (size_t i = 0; i < numberOfPersons; ++i)
+ labels[i] = __faceLabels[i];
+ } else if (strncmp(valueName,
+ MV_SURVEILLANCE_PERSONS_RECOGNIZED_CONFIDENCES,
+ MAX_VALUE_NAME_LENGHT) == 0) {
+ double *confidences = (double*) value;
+
+ for (size_t i = 0; i < numberOfPersons; ++i)
+ confidences[i] = __confidences[i];
+ } else {
+ LOGE("This value name doesn't exist. Getting result value failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+EventTriggerPersonRecognition::EventTriggerPersonRecognition(
+ mv_surveillance_event_trigger_h eventTrigger,
+ long int triggerId,
+ int videoStreamId,
+ mv_surveillance_event_occurred_cb callback,
+ void *userData,
+ int numberOfPoints,
+ mv_point_s *roi) : EventTrigger(eventTrigger,
+ triggerId,
+ videoStreamId,
+ callback,
+ userData,
+ numberOfPoints,
+ roi),
+ __faceRecognitionModel(NULL),
+ __lastFrame(NULL),
+ __eventResult(new EventResultPersonRecognition())
+{
+ ; /* NULL */
+}
+
+EventTriggerPersonRecognition::~EventTriggerPersonRecognition()
+{
+ if (NULL != __faceRecognitionModel) {
+ const int err = mv_face_recognition_model_destroy(__faceRecognitionModel);
+ if (MEDIA_VISION_ERROR_NONE != err)
+ LOGE("Error while trying to delete face recognition model when "
+ "event trigger had been destroyed. Error code: %i.", err);
+ }
+
+ delete __eventResult;
+}
+
+int EventTriggerPersonRecognition::parseEngineConfig(mv_engine_config_h engineConfig)
+{
+ if (engineConfig == NULL) {
+ LOGE("Engine configuration is NULL. Parsing failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ char *modelPath = NULL;
+
+ int error = mv_engine_config_get_string_attribute(
+ engineConfig,
+ MV_SURVEILLANCE_FACE_RECOGNITION_MODEL_FILE_PATH,
+ &modelPath);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ if (modelPath != NULL)
+ delete[] modelPath;
+
+ LOGE("Getting recognition model from engine configuration failed.");
+
+ return error;
+ }
+
+ mv_face_recognition_model_h recognitionModel = NULL;
+
+ error = mv_face_recognition_model_load(modelPath, &recognitionModel);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ LOGE("Loading recognition model from file %s failed.",
+ modelPath);
+
+ if (modelPath != NULL)
+ delete[] modelPath;
+
+ return error;
+ }
+
+ if (NULL != __faceRecognitionModel) {
+ error = mv_face_recognition_model_destroy(__faceRecognitionModel);
+ if (MEDIA_VISION_ERROR_NONE != error) {
+ LOGE("Error while trying to delete old face recognition model when "
+ "new model is trying to be loaded. Error code: %i.", error);
+ }
+ }
+
+ __faceRecognitionModel = recognitionModel;
+
+ if (NULL == __faceRecognitionModel) {
+ LOGE("Failed to load face recognition model. Check %s attribute of the "
+ "engine config.", MV_SURVEILLANCE_FACE_RECOGNITION_MODEL_FILE_PATH);
+
+ if (modelPath != NULL)
+ delete[] modelPath;
+
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ if (modelPath != NULL)
+ delete[] modelPath;
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int EventTriggerPersonRecognition::pushSource(
+ mv_source_h source,
+ mv_source_h graySource,
+ const cv::Mat& grayImage)
+{
+ if (source == NULL || graySource == NULL || grayImage.empty()) {
+ LOGE("Media source is NULL. Pushing source failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ __lastFrame = source;
+
+ __eventResult->__locations.clear();
+ __eventResult->__faceLabels.clear();
+ __eventResult->__confidences.clear();
+
+ unsigned char *data_buffer = NULL;
+ unsigned int buffer_size = 0;
+ mv_colorspace_e colorspace = MEDIA_VISION_COLORSPACE_INVALID;
+ unsigned int width = 0;
+ unsigned int height = 0;
+
+ int error = mv_source_get_buffer(graySource, &data_buffer, &buffer_size);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ LOGE("Operation with media source failed with error %d.", error);
+ return error;
+ }
+
+ error = mv_source_get_colorspace(graySource, &colorspace);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ LOGE("Operation with media source failed with error %d.", error);
+ return error;
+ }
+
+ error = mv_source_get_width(graySource, &width);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ LOGE("Operation with media source failed with error %d.", error);
+ return error;
+ }
+
+ error = mv_source_get_height(graySource, &height);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ LOGE("Operation with media source failed with error %d.", error);
+ return error;
+ }
+
+ if (buffer_size != width * height)
+ {
+ // Unexcepted behaviour
+ LOGE("Grayscale source interpretation failed.");
+ return MEDIA_VISION_ERROR_INTERNAL;
+ }
+
+ mv_source_h sourceCopy = NULL;
+
+ error = mv_create_source(&sourceCopy);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ LOGE("Operation with media source failed with error %d.", error);
+ return error;
+ }
+
+ error = mv_source_fill_by_buffer(sourceCopy, data_buffer, buffer_size,
+ width, height, colorspace);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ mv_destroy_source(sourceCopy);
+ LOGE("Operation with media source failed with error %d.", error);
+ return error;
+ }
+
+ error = mv_source_get_buffer(sourceCopy, &data_buffer, &buffer_size);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ mv_destroy_source(sourceCopy);
+ LOGE("Operation with media source failed with error %d.", error);
+ return error;
+ }
+
+ error = applyROIToImage(data_buffer, width, height);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ mv_destroy_source(sourceCopy);
+ LOGE("Applying ROI failed with error %d.", error);
+ return error;
+ }
+
+ error = mv_face_detect(sourceCopy, NULL, faceDetectedCB, this);
+
+ if (MEDIA_VISION_ERROR_NONE != error) {
+ mv_destroy_source(sourceCopy);
+ LOGE("Errors were occurred during face detecting %i", error);
+ return error;
+ }
+
+ error = mv_destroy_source(sourceCopy);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ LOGE("Operation with media source failed with error %d.", error);
+ return error;
+ }
+
+ return error;
+}
+
+std::string EventTriggerPersonRecognition::getEventType() const
+{
+ return MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED;
+}
+
+bool EventTriggerPersonRecognition::operator==(const EventTriggerPersonRecognition& other) const
+{
+ if (EventTrigger::operator !=(other))
+ return false;
+
+ /* TODO: compare private values if necessary */
+
+ return true;
+}
+
+bool EventTriggerPersonRecognition::operator!=(const EventTriggerPersonRecognition& other) const
+{
+ return !(*this == other);
+}
+
+void EventTriggerPersonRecognition::setEventResults(
+ mv_rectangle_s faceLocation,
+ int faceLabel,
+ double confidence)
+{
+ __eventResult->__locations.push_back(faceLocation);
+ __eventResult->__faceLabels.push_back(faceLabel);
+ __eventResult->__confidences.push_back(confidence);
+}
+
+void EventTriggerPersonRecognition::faceDetectedCB(
+ mv_source_h source,
+ mv_engine_config_h /*engine_cfg*/,
+ mv_rectangle_s *faces_locations,
+ int number_of_faces,
+ void *user_data)
+{
+ if (NULL == user_data) {
+ LOGE("Invalid user data passed");
+ return;
+ }
+
+ EventTriggerPersonRecognition *recognitionTrigger =
+ (EventTriggerPersonRecognition*)user_data;
+
+ int location_idx = 0;
+ for (; location_idx < number_of_faces; ++location_idx) {
+ LOGI("Start surveillance face recognition");
+
+ const int error = mv_face_recognize(
+ source,
+ recognitionTrigger->__faceRecognitionModel,
+ NULL,
+ &faces_locations[location_idx],
+ faceRecognizedCB,
+ recognitionTrigger);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ LOGW("Face recognition for one model failed. Continue");
+ continue;
+ }
+
+ LOGI("Face has been successfully recognized");
+ }
+}
+
+void EventTriggerPersonRecognition::faceRecognizedCB(
+ mv_source_h source,
+ mv_face_recognition_model_h /*recognition_model*/,
+ mv_engine_config_h /*engine_cfg*/,
+ mv_rectangle_s *face_location,
+ const int *face_label,
+ double confidence,
+ void *user_data)
+{
+ if (face_location == NULL || face_label == NULL) {
+ LOGI("Face wasn't recognized");
+ return;
+ }
+
+ EventTriggerPersonRecognition *trigger =
+ (EventTriggerPersonRecognition*) user_data;
+
+ trigger->setEventResults(*face_location, *face_label, confidence);
+
+ CallbackDataMapConstIter iter = trigger->__callbackDataMap.begin();
+
+ for (; iter != trigger->__callbackDataMap.end(); ++iter) {
+ mv_surveillance_event_occurred_cb callback = iter->second.callback;
+ callback(
+ iter->second.eventTrigger,
+ trigger->__lastFrame,
+ trigger->__videoStreamId,
+ trigger->__eventResult,
+ iter->second.userData);
+ }
+}
+
+} /* surveillance */
+} /* mediavision */
diff --git a/mv_surveillance/surveillance/src/HoGDetector.cpp b/mv_surveillance/surveillance/src/HoGDetector.cpp
new file mode 100644
index 00000000..4d1ea0c7
--- /dev/null
+++ b/mv_surveillance/surveillance/src/HoGDetector.cpp
@@ -0,0 +1,1006 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include <stdio.h>
+#include "HoGDetector.h"
+#include "opencv2/imgproc/imgproc.hpp"
+#include <iterator>
+
+#ifdef ENABLE_NEON
+#include <arm_neon.h>
+#endif
+
+#ifdef ENABLE_OMP
+#include <sched.h>
+#define NCORES 4
+static int coreids[NCORES] = {1, 2, 3, 4};
+#endif
+
+/****************************************************************************************\
+ The code below is implementation of HOG (Histogram-of-Oriented Gradients)
+ descriptor and object detection, introduced by Navneet Dalal and Bill Triggs.
+
+ The computed feature vectors are compatible with the
+ INRIA Object Detection and Localization Toolkit
+ (http://pascal.inrialpes.fr/soft/olt/)
+\****************************************************************************************/
+
+namespace modifiedcv {
+
+class ParallelLoopBodyWrapper {
+public:
+ ParallelLoopBodyWrapper(const cv::ParallelLoopBody& _body, const cv::Range& _r) {
+ body = &_body;
+ wholeRange = _r;
+ nstripes = cvRound(wholeRange.end - wholeRange.start);
+ }
+ void operator()(const cv::Range& sr) const {
+ cv::Range r;
+ r.start = (int)(wholeRange.start +
+ ((uint64)sr.start*(wholeRange.end - wholeRange.start) + nstripes/2)/nstripes);
+ r.end = sr.end >= nstripes ? wholeRange.end : (int)(wholeRange.start +
+ ((uint64)sr.end*(wholeRange.end - wholeRange.start) + nstripes/2)/nstripes);
+ (*body)(r);
+ }
+ cv::Range stripeRange() const {
+ return cv::Range(0, nstripes);
+ }
+
+protected:
+ const cv::ParallelLoopBody* body;
+ cv::Range wholeRange;
+ int nstripes;
+};
+
+void parallel_for_(const cv::Range& range, const cv::ParallelLoopBody& body)
+{
+#if defined ENABLE_OMP
+ ParallelLoopBodyWrapper pbody(body, range);
+ cv::Range stripeRange = pbody.stripeRange();
+ int i = 0;
+ #pragma omp parallel for private(i) num_threads(NCORES)
+ for (i = stripeRange.start; i < stripeRange.end; ++i) {
+ cpu_set_t mask;
+ CPU_ZERO(&mask);
+ CPU_SET(coreids[i % 4], &mask);
+
+ if (sched_setaffinity (0, sizeof(mask), &mask) == -1) {
+ printf("Could not set CPU Affinity, continuing...");
+ }
+
+ pbody(Range(i, i + 1));
+ }
+#else
+ cv::parallel_for_(range, body);
+#endif
+}
+
+size_t HOGDescriptor::getDescriptorSize() const
+{
+ return (size_t)nbins*
+ (blockSize.width/cellSize.width)*
+ (blockSize.height/cellSize.height)*
+ ((winSize.width - blockSize.width)/blockStride.width + 1)*
+ ((winSize.height - blockSize.height)/blockStride.height + 1);
+}
+
+double HOGDescriptor::getWinSigma() const
+{
+ return winSigma >= 0 ? winSigma : (blockSize.width + blockSize.height)/8.;
+}
+
+bool HOGDescriptor::checkDetectorSize() const
+{
+ size_t detectorSize = svmDetector.size(), descriptorSize = getDescriptorSize();
+ return detectorSize == 0 ||
+ detectorSize == descriptorSize ||
+ detectorSize == descriptorSize + 1;
+}
+
+void HOGDescriptor::setSVMDetector(InputArray _svmDetector)
+{
+ _svmDetector.getMat().convertTo(svmDetector, CV_32F);
+ CV_Assert(checkDetectorSize());
+}
+
+void HOGDescriptor::computeGradient(const Mat& img, Mat& grad, Mat& qangle,
+ Size paddingTL, Size paddingBR) const
+{
+ CV_Assert(img.type() == CV_8U);
+
+ Size gradsize(img.cols + paddingTL.width + paddingBR.width,
+ img.rows + paddingTL.height + paddingBR.height);
+ grad.create(gradsize, CV_32FC2); /* <magnitude*(1-alpha), magnitude*alpha> */
+ qangle.create(gradsize, CV_8UC2); /* [0..nbins-1] - quantized gradient orientation */
+ Size wholeSize;
+ Point roiofs;
+ img.locateROI(wholeSize, roiofs);
+
+ int i, x, y;
+ /* int cn = img.channels(); */
+
+ Mat_<float> _lut(1, 256);
+ const float* lut = &_lut(0, 0);
+
+ if ( gammaCorrection )
+ for ( i = 0; i < 256; i++ )
+ _lut(0, i) = std::sqrt((float)i);
+ else
+ for ( i = 0; i < 256; i++ )
+ _lut(0, i) = (float)i;
+
+ AutoBuffer<int> mapbuf(gradsize.width + gradsize.height + 4);
+ int* xmap = (int*)mapbuf + 1;
+ int* ymap = xmap + gradsize.width + 2;
+
+ const int borderType = (int)cv::BORDER_REFLECT_101;
+
+ for ( x = -1; x < gradsize.width + 1; x++ )
+ xmap[x] = cv::borderInterpolate(x - paddingTL.width + roiofs.x,
+ wholeSize.width, borderType) - roiofs.x;
+ for ( y = -1; y < gradsize.height + 1; y++ )
+ ymap[y] = cv::borderInterpolate(y - paddingTL.height + roiofs.y,
+ wholeSize.height, borderType) - roiofs.y;
+
+ /* x- & y- derivatives for the whole row */
+ int width = gradsize.width;
+ AutoBuffer<float> _dbuf(width*4);
+ float* dbuf = _dbuf;
+ Mat Dx(1, width, CV_32F, dbuf);
+ Mat Dy(1, width, CV_32F, dbuf + width);
+ Mat Mag(1, width, CV_32F, dbuf + width*2);
+ Mat Angle(1, width, CV_32F, dbuf + width*3);
+
+ int _nbins = nbins;
+ float angleScale = (float)(_nbins/CV_PI);
+
+ for ( y = 0; y < gradsize.height; y++ ) {
+ const uchar* imgPtr = img.data + img.step*ymap[y];
+ const uchar* prevPtr = img.data + img.step*ymap[y-1];
+ const uchar* nextPtr = img.data + img.step*ymap[y+1];
+ float* gradPtr = (float*)grad.ptr(y);
+ uchar* qanglePtr = (uchar*)qangle.ptr(y);
+
+ for (x = 0; x < width; x++) {
+ int x1 = xmap[x];
+ dbuf[x] = (float)(lut[imgPtr[xmap[x+1]]] - lut[imgPtr[xmap[x-1]]]);
+ dbuf[width + x] = (float)(lut[nextPtr[x1]] - lut[prevPtr[x1]]);
+ }
+
+ cartToPolar(Dx, Dy, Mag, Angle, false);
+
+ for (x = 0; x < width; x++) {
+ float mag = dbuf[x+width*2], angle = dbuf[x+width*3]*angleScale - 0.5f;
+ int hidx = cvFloor(angle);
+ angle -= hidx;
+ gradPtr[x*2] = mag*(1.f - angle);
+ gradPtr[x*2+1] = mag*angle;
+
+ if ( hidx < 0 )
+ hidx += _nbins;
+ else if ( hidx >= _nbins )
+ hidx -= _nbins;
+ assert((unsigned)hidx < (unsigned)_nbins);
+
+ qanglePtr[x*2] = (uchar)hidx;
+ hidx++;
+ hidx &= hidx < _nbins ? -1 : 0;
+ qanglePtr[x*2+1] = (uchar)hidx;
+ }
+ }
+}
+
+
+struct HOGCache {
+ struct BlockData {
+ BlockData() : histOfs(0), imgOffset() {}
+ int histOfs;
+ Point imgOffset;
+ };
+
+ struct PixData {
+ size_t gradOfs, qangleOfs;
+ int histOfs[4];
+ float histWeights[4];
+ float gradWeight;
+ };
+
+ HOGCache();
+ HOGCache(const HOGDescriptor* descriptor,
+ const Mat& img, Size paddingTL, Size paddingBR,
+ bool useCache, Size cacheStride);
+ virtual ~HOGCache() {};
+ virtual void init(const HOGDescriptor* descriptor,
+ const Mat& img, Size paddingTL, Size paddingBR,
+ bool useCache, Size cacheStride);
+
+ Size windowsInImage(Size imageSize, Size winStride) const;
+ Rect getWindow(Size imageSize, Size winStride, int idx) const;
+
+ const float* getBlock(Point pt, float* buf);
+ virtual void normalizeBlockHistogram(float* histogram) const;
+
+ vector<PixData> pixData;
+ vector<BlockData> blockData;
+
+ bool useCache;
+ vector<int> ymaxCached;
+ Size winSize, cacheStride;
+ Size nblocks, ncells;
+ int blockHistogramSize;
+ int count1, count2, count4;
+ Point imgoffset;
+ Mat_<float> blockCache;
+ Mat_<uchar> blockCacheFlags;
+
+ Mat grad, qangle;
+ const HOGDescriptor* descriptor;
+};
+
+
+HOGCache::HOGCache()
+{
+ useCache = false;
+ blockHistogramSize = count1 = count2 = count4 = 0;
+ descriptor = 0;
+}
+
+HOGCache::HOGCache(const HOGDescriptor* _descriptor,
+ const Mat& _img, Size _paddingTL, Size _paddingBR,
+ bool _useCache, Size _cacheStride)
+{
+ init(_descriptor, _img, _paddingTL, _paddingBR, _useCache, _cacheStride);
+}
+
+void HOGCache::init(const HOGDescriptor* _descriptor,
+ const Mat& _img, Size _paddingTL, Size _paddingBR,
+ bool _useCache, Size _cacheStride)
+{
+ descriptor = _descriptor;
+ cacheStride = _cacheStride;
+ useCache = _useCache;
+
+ descriptor->computeGradient(_img, grad, qangle, _paddingTL, _paddingBR);
+ imgoffset = _paddingTL;
+
+ winSize = descriptor->winSize;
+ Size blockSize = descriptor->blockSize;
+ Size blockStride = descriptor->blockStride;
+ Size cellSize = descriptor->cellSize;
+ int i, j, nbins = descriptor->nbins;
+ int rawBlockSize = blockSize.width*blockSize.height;
+
+ nblocks = Size((winSize.width - blockSize.width)/blockStride.width + 1,
+ (winSize.height - blockSize.height)/blockStride.height + 1);
+ ncells = Size(blockSize.width/cellSize.width, blockSize.height/cellSize.height);
+ blockHistogramSize = ncells.width*ncells.height*nbins;
+
+ if ( useCache ) {
+ Size cacheSize((grad.cols - blockSize.width)/cacheStride.width+1,
+ (winSize.height/cacheStride.height)+1);
+ blockCache.create(cacheSize.height, cacheSize.width*blockHistogramSize);
+ blockCacheFlags.create(cacheSize);
+ size_t cacheRows = blockCache.rows;
+ ymaxCached.resize(cacheRows);
+ for (size_t ii = 0; ii < cacheRows; ii++ )
+ ymaxCached[ii] = -1;
+ }
+
+ Mat_<float> weights(blockSize);
+ float sigma = (float)descriptor->getWinSigma();
+ float scale = 1.f/(sigma*sigma*2);
+
+ float blockHalfHeight = blockSize.height*0.5f;
+ float blockHalfWidth = blockSize.width*0.5f;
+ for (i = 0; i < blockSize.height; i++)
+ for (j = 0; j < blockSize.width; j++) {
+ float di = i - blockHalfHeight;
+ float dj = j - blockHalfWidth;
+ weights(i, j) = std::exp(-(di*di + dj*dj)*scale);
+ }
+
+ blockData.resize(nblocks.width*nblocks.height);
+ pixData.resize(rawBlockSize*3);
+
+ /*
+ * Initialize 2 lookup tables, pixData & blockData.
+ * Here is why:
+ *
+ * The detection algorithm runs in 4 nested loops (at each pyramid layer):
+ * loop over the windows within the input image
+ * loop over the blocks within each window
+ * loop over the cells within each block
+ * loop over the pixels in each cell
+ *
+ * As each of the loops runs over a 2-dimensional array,
+ * we could get 8(!) nested loops in total, which is very-very slow.
+ *
+ * To speed the things up, we do the following:
+ * 1. loop over windows is unrolled in the HOGDescriptor::{compute|detect} methods;
+ * inside we compute the current search window using getWindow() method.
+ * Yes, it involves some overhead (function call + couple of divisions),
+ * but it's tiny in fact.
+ * 2. loop over the blocks is also unrolled. Inside we use pre-computed blockData[j]
+ * to set up gradient and histogram pointers.
+ * 3. loops over cells and pixels in each cell are merged
+ * (since there is no overlap between cells, each pixel in the block is processed once)
+ * and also unrolled. Inside we use PixData[k] to access the gradient values and
+ * update the histogram
+ */
+
+ count1 = count2 = count4 = 0;
+ for ( j = 0; j < blockSize.width; j++ )
+ for ( i = 0; i < blockSize.height; i++ ) {
+ PixData* data = 0;
+ float cellX = (j+0.5f)/cellSize.width - 0.5f;
+ float cellY = (i+0.5f)/cellSize.height - 0.5f;
+ int icellX0 = cvFloor(cellX);
+ int icellY0 = cvFloor(cellY);
+ int icellX1 = icellX0 + 1, icellY1 = icellY0 + 1;
+ cellX -= icellX0;
+ cellY -= icellY0;
+
+ if ( (unsigned)icellX0 < (unsigned)ncells.width &&
+ (unsigned)icellX1 < (unsigned)ncells.width ) {
+ if ( (unsigned)icellY0 < (unsigned)ncells.height &&
+ (unsigned)icellY1 < (unsigned)ncells.height ) {
+ data = &pixData[rawBlockSize*2 + (count4++)];
+ data->histOfs[0] = (icellX0*ncells.height + icellY0)*nbins;
+ data->histWeights[0] = (1.f - cellX)*(1.f - cellY);
+ data->histOfs[1] = (icellX1*ncells.height + icellY0)*nbins;
+ data->histWeights[1] = cellX*(1.f - cellY);
+ data->histOfs[2] = (icellX0*ncells.height + icellY1)*nbins;
+ data->histWeights[2] = (1.f - cellX)*cellY;
+ data->histOfs[3] = (icellX1*ncells.height + icellY1)*nbins;
+ data->histWeights[3] = cellX*cellY;
+ } else {
+ data = &pixData[rawBlockSize + (count2++)];
+ if ( (unsigned)icellY0 < (unsigned)ncells.height ) {
+ icellY1 = icellY0;
+ cellY = 1.f - cellY;
+ }
+ data->histOfs[0] = (icellX0*ncells.height + icellY1)*nbins;
+ data->histWeights[0] = (1.f - cellX)*cellY;
+ data->histOfs[1] = (icellX1*ncells.height + icellY1)*nbins;
+ data->histWeights[1] = cellX*cellY;
+ data->histOfs[2] = data->histOfs[3] = 0;
+ data->histWeights[2] = data->histWeights[3] = 0;
+ }
+ } else {
+ if ( (unsigned)icellX0 < (unsigned)ncells.width ) {
+ icellX1 = icellX0;
+ cellX = 1.f - cellX;
+ }
+
+ if ( (unsigned)icellY0 < (unsigned)ncells.height &&
+ (unsigned)icellY1 < (unsigned)ncells.height ) {
+ data = &pixData[rawBlockSize + (count2++)];
+ data->histOfs[0] = (icellX1*ncells.height + icellY0)*nbins;
+ data->histWeights[0] = cellX*(1.f - cellY);
+ data->histOfs[1] = (icellX1*ncells.height + icellY1)*nbins;
+ data->histWeights[1] = cellX*cellY;
+ data->histOfs[2] = data->histOfs[3] = 0;
+ data->histWeights[2] = data->histWeights[3] = 0;
+ } else {
+ data = &pixData[count1++];
+ if ( (unsigned)icellY0 < (unsigned)ncells.height ) {
+ icellY1 = icellY0;
+ cellY = 1.f - cellY;
+ }
+ data->histOfs[0] = (icellX1*ncells.height + icellY1)*nbins;
+ data->histWeights[0] = cellX*cellY;
+ data->histOfs[1] = data->histOfs[2] = data->histOfs[3] = 0;
+ data->histWeights[1] = data->histWeights[2] = data->histWeights[3] = 0;
+ }
+ }
+ data->gradOfs = (grad.cols*i + j)*2;
+ data->qangleOfs = (qangle.cols*i + j)*2;
+ data->gradWeight = weights(i, j);
+ }
+
+ assert(count1 + count2 + count4 == rawBlockSize);
+ /* defragment pixData */
+ for ( j = 0; j < count2; j++ )
+ pixData[j + count1] = pixData[j + rawBlockSize];
+ for ( j = 0; j < count4; j++ )
+ pixData[j + count1 + count2] = pixData[j + rawBlockSize*2];
+ count2 += count1;
+ count4 += count2;
+
+ /* initialize blockData */
+ for ( j = 0; j < nblocks.width; j++ )
+ for ( i = 0; i < nblocks.height; i++ ) {
+ BlockData& data = blockData[j*nblocks.height + i];
+ data.histOfs = (j*nblocks.height + i)*blockHistogramSize;
+ data.imgOffset = Point(j*blockStride.width, i*blockStride.height);
+ }
+}
+
+
+const float* HOGCache::getBlock(Point pt, float* buf)
+{
+ float* blockHist = buf;
+ assert(descriptor != 0);
+
+ Size blockSize = descriptor->blockSize;
+ pt += imgoffset;
+
+ CV_Assert( (unsigned)pt.x <= (unsigned)(grad.cols - blockSize.width) &&
+ (unsigned)pt.y <= (unsigned)(grad.rows - blockSize.height) );
+
+ if ( useCache ) {
+ CV_Assert(pt.x % cacheStride.width == 0 &&
+ pt.y % cacheStride.height == 0);
+ Point cacheIdx(pt.x/cacheStride.width,
+ (pt.y/cacheStride.height) % blockCache.rows);
+ if ( pt.y != ymaxCached[cacheIdx.y] ) {
+ Mat_<uchar> cacheRow = blockCacheFlags.row(cacheIdx.y);
+ cacheRow = (uchar)0;
+ ymaxCached[cacheIdx.y] = pt.y;
+ }
+
+ blockHist = &blockCache[cacheIdx.y][cacheIdx.x*blockHistogramSize];
+ uchar& computedFlag = blockCacheFlags(cacheIdx.y, cacheIdx.x);
+ if ( computedFlag != 0 )
+ return blockHist;
+ computedFlag = (uchar)1; /* set it at once, before actual computing */
+ }
+
+ int k, C1 = count1, C2 = count2, C4 = count4;
+ const float* gradPtr = (const float*)(grad.data + grad.step*pt.y) + pt.x*2;
+ const uchar* qanglePtr = qangle.data + qangle.step*pt.y + pt.x*2;
+
+ CV_Assert(blockHist != 0);
+ for ( k = 0; k < blockHistogramSize; k++ )
+ blockHist[k] = 0.f;
+
+ const PixData* _pixData = &pixData[0];
+
+ for ( k = 0; k < C1; k++ ) {
+ const PixData& pk = _pixData[k];
+ const float* a = gradPtr + pk.gradOfs;
+ float w = pk.gradWeight*pk.histWeights[0];
+ const uchar* h = qanglePtr + pk.qangleOfs;
+ int h0 = h[0], h1 = h[1];
+ float* hist = blockHist + pk.histOfs[0];
+ float t0 = hist[h0] + a[0]*w;
+ float t1 = hist[h1] + a[1]*w;
+ hist[h0] = t0;
+ hist[h1] = t1;
+ }
+
+ for ( ; k < C2; k++ ) {
+ const PixData& pk = _pixData[k];
+ const float* a = gradPtr + pk.gradOfs;
+ float w, t0, t1, a0 = a[0], a1 = a[1];
+ const uchar* h = qanglePtr + pk.qangleOfs;
+ int h0 = h[0], h1 = h[1];
+
+ float* hist = blockHist + pk.histOfs[0];
+ w = pk.gradWeight*pk.histWeights[0];
+ t0 = hist[h0] + a0*w;
+ t1 = hist[h1] + a1*w;
+ hist[h0] = t0;
+ hist[h1] = t1;
+
+ hist = blockHist + pk.histOfs[1];
+ w = pk.gradWeight*pk.histWeights[1];
+ t0 = hist[h0] + a0*w;
+ t1 = hist[h1] + a1*w;
+ hist[h0] = t0;
+ hist[h1] = t1;
+ }
+
+ for ( ; k < C4; k++ ) {
+ const PixData& pk = _pixData[k];
+ const float* a = gradPtr + pk.gradOfs;
+ float w, t0, t1, a0 = a[0], a1 = a[1];
+ const uchar* h = qanglePtr + pk.qangleOfs;
+ int h0 = h[0], h1 = h[1];
+
+ float* hist = blockHist + pk.histOfs[0];
+ w = pk.gradWeight*pk.histWeights[0];
+ t0 = hist[h0] + a0*w;
+ t1 = hist[h1] + a1*w;
+ hist[h0] = t0;
+ hist[h1] = t1;
+
+ hist = blockHist + pk.histOfs[1];
+ w = pk.gradWeight*pk.histWeights[1];
+ t0 = hist[h0] + a0*w;
+ t1 = hist[h1] + a1*w;
+ hist[h0] = t0;
+ hist[h1] = t1;
+
+ hist = blockHist + pk.histOfs[2];
+ w = pk.gradWeight*pk.histWeights[2];
+ t0 = hist[h0] + a0*w;
+ t1 = hist[h1] + a1*w;
+ hist[h0] = t0;
+ hist[h1] = t1;
+
+ hist = blockHist + pk.histOfs[3];
+ w = pk.gradWeight*pk.histWeights[3];
+ t0 = hist[h0] + a0*w;
+ t1 = hist[h1] + a1*w;
+ hist[h0] = t0;
+ hist[h1] = t1;
+ }
+
+ normalizeBlockHistogram(blockHist);
+
+ return blockHist;
+}
+
+void HOGCache::normalizeBlockHistogram(float* _hist) const
+{
+#ifdef ENABLE_NEON
+ /* NEON vector for loading the histogram to the memory */
+ float32x4_t hist_v;
+ /* Initialize the accumulator for summation storing */
+ float32x4_t acc = vdupq_n_f32(0.f);
+#endif
+
+ /* Histogram pointer in the memory */
+ float *hist_ptr = &_hist[0];
+ /* Variable to store values of summations */
+ float sum = 0.f;
+ size_t sz = blockHistogramSize;
+
+#ifdef ENABLE_NEON
+ for (; sz != 0u; sz -= 4u) {
+ hist_v = vld1q_f32(hist_ptr);
+ acc = vmlaq_f32(acc, hist_v, hist_v);
+ hist_ptr += 4;
+ }
+
+ sum += vgetq_lane_f32(acc, 0) + vgetq_lane_f32(acc, 1) +
+ vgetq_lane_f32(acc, 2) + vgetq_lane_f32(acc, 3);
+
+ /* Reset accumulator */
+ acc = vdupq_n_f32(0.f);
+
+ sz = blockHistogramSize;
+ hist_ptr = &_hist[0];
+#else
+ for (size_t i = 0; i < sz; ++i)
+ sum += hist_ptr[i] * hist_ptr[i];
+#endif
+
+ float scale = 1.f / (std::sqrt(sum) + sz * 0.1f);
+ sum = 0.f;
+
+#ifdef ENABLE_NEON
+ float32x4_t thres_v = vdupq_n_f32((float)descriptor->L2HysThreshold);
+
+ for (; sz != 0; sz -= 4) {
+ /* Find minimal value among threshold and histogram value, accumulate
+ * this value squared */
+ hist_v = vminq_f32(vmulq_n_f32(vld1q_f32(hist_ptr), scale), thres_v);
+ acc = vmlaq_f32(acc, hist_v, hist_v);
+ /* Update histograms in memory according with found min values */
+ vst1q_f32(hist_ptr, hist_v);
+ hist_ptr += 4;
+ }
+
+ sum += vgetq_lane_f32(acc, 0) + vgetq_lane_f32(acc, 1) +
+ vgetq_lane_f32(acc, 2) + vgetq_lane_f32(acc, 3);
+
+#else
+ float thresh = (float)descriptor->L2HysThreshold;
+ for (size_t i = 0; i < sz; ++i) {
+ hist_ptr[i] = std::min(hist_ptr[i] * scale, thresh);
+ sum += hist_ptr[i] * hist_ptr[i];
+ }
+#endif
+
+ scale = 1.f / (std::sqrt(sum) + 1e-3f);
+
+#ifdef ENABLE_NEON
+ sz = blockHistogramSize;
+ hist_ptr = &_hist[0];
+
+ /* Scale histogram (normalize): */
+ for (; sz != 0; sz -= 4) {
+ vst1q_f32(hist_ptr, vmulq_n_f32(vld1q_f32(hist_ptr), scale));
+ hist_ptr += 4;
+ }
+#else
+ for (size_t i = 0; i < sz; i++ )
+ hist_ptr[i] *= scale;
+#endif
+}
+
+
+Size HOGCache::windowsInImage(Size imageSize, Size winStride) const
+{
+ return Size((imageSize.width - winSize.width)/winStride.width + 1,
+ (imageSize.height - winSize.height)/winStride.height + 1);
+}
+
+Rect HOGCache::getWindow(Size imageSize, Size winStride, int idx) const
+{
+ int nwindowsX = (imageSize.width - winSize.width)/winStride.width + 1;
+ int y = idx / nwindowsX;
+ int x = idx - nwindowsX*y;
+ return Rect( x*winStride.width, y*winStride.height, winSize.width, winSize.height );
+}
+
+
+void HOGDescriptor::compute(const Mat& img, vector<float>& descriptors,
+ Size winStride, Size padding,
+ const vector<Point>& locations) const
+{
+ if ( winStride == Size() )
+ winStride = cellSize;
+ Size cacheStride(gcd(winStride.width, blockStride.width),
+ gcd(winStride.height, blockStride.height));
+ size_t nwindows = locations.size();
+ padding.width = (int)alignSize(std::max(padding.width, 0), cacheStride.width);
+ padding.height = (int)alignSize(std::max(padding.height, 0), cacheStride.height);
+ Size paddedImgSize(img.cols + padding.width*2, img.rows + padding.height*2);
+
+ HOGCache cache(this, img, padding, padding, nwindows == 0, cacheStride);
+
+ if ( !nwindows )
+ nwindows = cache.windowsInImage(paddedImgSize, winStride).area();
+
+ const HOGCache::BlockData* blockData = &cache.blockData[0];
+
+ int nblocks = cache.nblocks.area();
+ int blockHistogramSize = cache.blockHistogramSize;
+ size_t dsize = getDescriptorSize();
+ descriptors.resize(dsize*nwindows);
+
+ for ( size_t i = 0; i < nwindows; i++ ) {
+ float* descriptor = &descriptors[i*dsize];
+
+ Point pt0;
+ if ( !locations.empty() ) {
+ pt0 = locations[i];
+ if ( pt0.x < -padding.width || pt0.x > img.cols + padding.width - winSize.width ||
+ pt0.y < -padding.height || pt0.y > img.rows + padding.height - winSize.height )
+ continue;
+ } else {
+ pt0 = cache.getWindow(paddedImgSize, winStride, (int)i).tl() - Point(padding);
+ CV_Assert(pt0.x % cacheStride.width == 0 && pt0.y % cacheStride.height == 0);
+ }
+
+ for ( int j = 0; j < nblocks; j++ ) {
+ const HOGCache::BlockData& bj = blockData[j];
+ Point pt = pt0 + bj.imgOffset;
+
+ float* dst = descriptor + bj.histOfs;
+ const float* src = cache.getBlock(pt, dst);
+ if ( src != dst )
+ for ( int k = 0; k < blockHistogramSize; k++ )
+ dst[k] = src[k];
+ }
+ }
+}
+
+
+void HOGDescriptor::detect(const Mat& img,
+ vector<Point>& hits, vector<double>& weights, double hitThreshold,
+ Size winStride, Size padding, const vector<Point>& locations) const
+{
+ hits.clear();
+ if ( svmDetector.empty() )
+ return;
+
+ if ( winStride == Size() )
+ winStride = cellSize;
+ Size cacheStride(gcd(winStride.width, blockStride.width),
+ gcd(winStride.height, blockStride.height));
+ size_t nwindows = locations.size();
+ padding.width = (int)alignSize(std::max(padding.width, 0), cacheStride.width);
+ padding.height = (int)alignSize(std::max(padding.height, 0), cacheStride.height);
+ Size paddedImgSize(img.cols + padding.width*2, img.rows + padding.height*2);
+
+ HOGCache cache(this, img, padding, padding, nwindows == 0, cacheStride);
+
+ if ( !nwindows )
+ nwindows = cache.windowsInImage(paddedImgSize, winStride).area();
+
+ const HOGCache::BlockData* blockData = &cache.blockData[0];
+
+ int nblocks = cache.nblocks.area();
+ int blockHistogramSize = cache.blockHistogramSize;
+ size_t dsize = getDescriptorSize();
+
+ double rho = svmDetector.size() > dsize ? svmDetector[dsize] : 0;
+ vector<float> blockHist(blockHistogramSize);
+
+ for ( size_t i = 0; i < nwindows; i++ ) {
+ Point pt0;
+ if ( !locations.empty() ) {
+ pt0 = locations[i];
+ if ( pt0.x < -padding.width || pt0.x > img.cols + padding.width - winSize.width ||
+ pt0.y < -padding.height || pt0.y > img.rows + padding.height - winSize.height )
+ continue;
+ } else {
+ pt0 = cache.getWindow(paddedImgSize, winStride, (int)i).tl() - Point(padding);
+ CV_Assert(pt0.x % cacheStride.width == 0 && pt0.y % cacheStride.height == 0);
+ }
+ double s = rho;
+ const float* svmVec = &svmDetector[0];
+ int j, k;
+
+ for ( j = 0; j < nblocks; j++, svmVec += blockHistogramSize ) {
+ const HOGCache::BlockData& bj = blockData[j];
+ Point pt = pt0 + bj.imgOffset;
+
+ const float* vec = cache.getBlock(pt, &blockHist[0]);
+#ifdef ENABLE_NEON
+ float32x4_t vec_v; /* NEON feature vector */
+ float32x4_t svm_v; /* NEON SVM feature weights */
+ float32x4_t acc = vdupq_n_f32(0.f); /* NEON partial sum */
+ for ( k = 0; k <= blockHistogramSize - 4; k += 4 ) {
+ vec_v = vld1q_f32(vec + k);
+ svm_v = vld1q_f32(svmVec + k);
+ acc = vmlaq_f32(acc, vec_v, svm_v);
+ }
+
+ s += vgetq_lane_f32(acc, 0) + vgetq_lane_f32(acc, 1) +
+ vgetq_lane_f32(acc, 2) + vgetq_lane_f32(acc, 3);
+
+#else
+ for ( k = 0; k <= blockHistogramSize - 4; k += 4 )
+ s += vec[k]*svmVec[k] + vec[k+1]*svmVec[k+1] +
+ vec[k+2]*svmVec[k+2] + vec[k+3]*svmVec[k+3];
+#endif
+ for ( ; k < blockHistogramSize; k++ )
+ s += vec[k]*svmVec[k];
+ }
+
+ if ( s >= hitThreshold ) {
+ hits.push_back(pt0);
+ weights.push_back(s);
+ }
+ }
+}
+
+void HOGDescriptor::detect(const Mat& img, vector<Point>& hits, double hitThreshold,
+ Size winStride, Size padding, const vector<Point>& locations) const
+{
+ vector<double> weightsV;
+ detect(img, hits, weightsV, hitThreshold, winStride, padding, locations);
+}
+
+class HOGInvoker : public ParallelLoopBody {
+ public:
+ HOGInvoker(const HOGDescriptor* _hog, const Mat& _img,
+ double _hitThreshold, Size _winStride, Size _padding,
+ const double* _levelScale, std::vector<Rect> * _vec, Mutex* _mtx,
+ std::vector<double>* _weights = 0, std::vector<double>* _scales = 0) {
+ hog = _hog;
+ img = _img;
+ hitThreshold = _hitThreshold;
+ winStride = _winStride;
+ padding = _padding;
+ levelScale = _levelScale;
+ vec = _vec;
+ weights = _weights;
+ scales = _scales;
+ mtx = _mtx;
+ }
+
+ void operator()(const Range& range) const {
+ int i, i1 = range.start, i2 = range.end;
+ double minScale = i1 > 0 ? levelScale[i1] : i2 > 1 ? levelScale[i1+1] : std::max(img.cols, img.rows);
+ Size maxSz(cvCeil(img.cols/minScale), cvCeil(img.rows/minScale));
+ Mat smallerImgBuf(maxSz, img.type());
+ vector<Point> locations;
+ vector<double> hitsWeights;
+
+ Size wholeSize;
+ Point offset;
+ img.locateROI(wholeSize, offset);
+
+ for ( i = i1; i < i2; i++ ) {
+ double scale = levelScale[i];
+ Size sz(cvRound(img.cols/scale), cvRound(img.rows/scale));
+ Mat smallerImg(sz, img.type(), smallerImgBuf.data);
+ if (sz == img.size())
+ smallerImg = Mat(sz, img.type(), img.data, img.step);
+ else
+ resize(img, smallerImg, sz);
+ hog->detect(smallerImg, locations, hitsWeights, hitThreshold, winStride, padding);
+
+ Size scaledWinSize = Size(cvRound(hog->winSize.width*scale), cvRound(hog->winSize.height*scale));
+
+ mtx->lock();
+ for ( size_t j = 0; j < locations.size(); j++ ) {
+ vec->push_back(Rect(cvRound(locations[j].x*scale),
+ cvRound(locations[j].y*scale),
+ scaledWinSize.width, scaledWinSize.height));
+ if (scales) {
+ scales->push_back(scale);
+ }
+ }
+ mtx->unlock();
+
+ if (weights && (!hitsWeights.empty())) {
+ mtx->lock();
+ for (size_t j = 0; j < locations.size(); j++) {
+ weights->push_back(hitsWeights[j]);
+ }
+ mtx->unlock();
+ }
+ }
+ }
+
+ const HOGDescriptor* hog;
+ Mat img;
+ double hitThreshold;
+ Size winStride;
+ Size padding;
+ const double* levelScale;
+ std::vector<Rect>* vec;
+ std::vector<double>* weights;
+ std::vector<double>* scales;
+ Mutex* mtx;
+};
+
+
+void HOGDescriptor::detectMultiScale(
+ const Mat& img, vector<Rect>& foundLocations, vector<double>& foundWeights,
+ double hitThreshold, Size winStride, Size padding,
+ double scale0, double finalThreshold, bool useMeanshiftGrouping) const
+{
+ double scale = 1.;
+ int levels = 0;
+
+ vector<double> levelScale;
+ for ( levels = 0; levels < nlevels; levels++ ) {
+ levelScale.push_back(scale);
+ if ( cvRound(img.cols/scale) < winSize.width ||
+ cvRound(img.rows/scale) < winSize.height ||
+ scale0 <= 1 )
+ break;
+ scale *= scale0;
+ }
+ levels = std::max(levels, 1);
+ levelScale.resize(levels);
+
+ std::vector<Rect> allCandidates;
+ std::vector<double> tempScales;
+ std::vector<double> tempWeights;
+ std::vector<double> foundScales;
+ Mutex mtx;
+
+ modifiedcv::parallel_for_(Range(0, (int)levelScale.size()),
+ HOGInvoker(this, img, hitThreshold, winStride, padding, &levelScale[0], &allCandidates, &mtx, &tempWeights, &tempScales));
+
+ std::copy(tempScales.begin(), tempScales.end(), back_inserter(foundScales));
+ foundLocations.clear();
+ std::copy(allCandidates.begin(), allCandidates.end(), back_inserter(foundLocations));
+ foundWeights.clear();
+ std::copy(tempWeights.begin(), tempWeights.end(), back_inserter(foundWeights));
+
+ if ( useMeanshiftGrouping ) {
+ groupRectangles_meanshift(foundLocations, foundWeights, foundScales, finalThreshold, winSize);
+ } else {
+ groupRectangles(foundLocations, foundWeights, (int)finalThreshold, 0.2);
+ }
+}
+
+void HOGDescriptor::detectMultiScale(const Mat& img, vector<Rect>& foundLocations,
+ double hitThreshold, Size winStride, Size padding,
+ double scale0, double finalThreshold, bool useMeanshiftGrouping) const
+{
+ vector<double> foundWeights;
+ detectMultiScale(img, foundLocations, foundWeights, hitThreshold, winStride,
+ padding, scale0, finalThreshold, useMeanshiftGrouping);
+}
+
+void HOGDescriptor::groupRectangles(vector<cv::Rect>& rectList, vector<double>& weights, int groupThreshold, double eps) const
+{
+ if ( groupThreshold <= 0 || rectList.empty() ) {
+ return;
+ }
+
+ CV_Assert(rectList.size() == weights.size());
+
+ vector<int> labels;
+ int nclasses = partition(rectList, labels, SimilarRects(eps));
+
+ vector<cv::Rect_<double> > rrects(nclasses);
+ vector<int> numInClass(nclasses, 0);
+ vector<double> foundWeights(nclasses, DBL_MIN);
+ int i, j, nlabels = (int)labels.size();
+
+ for ( i = 0; i < nlabels; i++ ) {
+ int cls = labels[i];
+ rrects[cls].x += rectList[i].x;
+ rrects[cls].y += rectList[i].y;
+ rrects[cls].width += rectList[i].width;
+ rrects[cls].height += rectList[i].height;
+ foundWeights[cls] = max(foundWeights[cls], weights[i]);
+ numInClass[cls]++;
+ }
+
+ for ( i = 0; i < nclasses; i++ ) {
+ /* find the average of all ROI in the cluster */
+ cv::Rect_<double> r = rrects[i];
+ double s = 1.0/numInClass[i];
+ rrects[i] = cv::Rect_<double>(cv::saturate_cast<double>(r.x*s),
+ cv::saturate_cast<double>(r.y*s),
+ cv::saturate_cast<double>(r.width*s),
+ cv::saturate_cast<double>(r.height*s));
+ }
+
+ rectList.clear();
+ weights.clear();
+
+ for ( i = 0; i < nclasses; i++ ) {
+ cv::Rect r1 = rrects[i];
+ int n1 = numInClass[i];
+ double w1 = foundWeights[i];
+ if ( n1 <= groupThreshold )
+ continue;
+ /* filter out small rectangles inside large rectangles */
+ for ( j = 0; j < nclasses; j++ ) {
+ int n2 = numInClass[j];
+
+ if ( j == i || n2 <= groupThreshold )
+ continue;
+
+ cv::Rect r2 = rrects[j];
+
+ int dx = cv::saturate_cast<int>(r2.width * eps);
+ int dy = cv::saturate_cast<int>(r2.height * eps);
+
+ if ( r1.x >= r2.x - dx &&
+ r1.y >= r2.y - dy &&
+ r1.x + r1.width <= r2.x + r2.width + dx &&
+ r1.y + r1.height <= r2.y + r2.height + dy &&
+ (n2 > std::max(3, n1) || n1 < 3) )
+ break;
+ }
+
+ if ( j == nclasses ) {
+ rectList.push_back(r1);
+ weights.push_back(w1);
+ }
+ }
+}
+}
diff --git a/mv_surveillance/surveillance/src/SurveillanceHelper.cpp b/mv_surveillance/surveillance/src/SurveillanceHelper.cpp
new file mode 100644
index 00000000..bbd92e90
--- /dev/null
+++ b/mv_surveillance/surveillance/src/SurveillanceHelper.cpp
@@ -0,0 +1,200 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SurveillanceHelper.h"
+
+#include <mv_private.h>
+
+#include "opencv2/highgui/highgui.hpp"
+
+namespace mediavision {
+namespace surveillance {
+
+int SurveillanceHelper::convertSourceMV2GrayCV(mv_source_h mvSource, cv::Mat& cvSource)
+{
+ MEDIA_VISION_INSTANCE_CHECK(mvSource);
+
+ int depth = CV_8U; /* Default depth. 1 byte per channel. */
+ unsigned int channelsNumber = 0;
+ unsigned int width = 0, height = 0;
+ unsigned int bufferSize = 0;
+ unsigned char *buffer = NULL;
+
+ mv_colorspace_e colorspace = MEDIA_VISION_COLORSPACE_INVALID;
+
+ MEDIA_VISION_ASSERT(mv_source_get_width(mvSource, &width),
+ "Failed to get the width.");
+ MEDIA_VISION_ASSERT(mv_source_get_height(mvSource, &height),
+ "Failed to get the height.");
+ MEDIA_VISION_ASSERT(mv_source_get_colorspace(mvSource, &colorspace),
+ "Failed to get the colorspace.");
+ MEDIA_VISION_ASSERT(mv_source_get_buffer(mvSource, &buffer, &bufferSize),
+ "Failed to get the buffer size.");
+
+ int conversionType = -1; /* Type of conversion from given colorspace to gray */
+ switch(colorspace) {
+ case MEDIA_VISION_COLORSPACE_INVALID:
+ LOGE("Error: mv_source has invalid colorspace.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ case MEDIA_VISION_COLORSPACE_Y800:
+ channelsNumber = 1;
+ /* Without convertion */
+ break;
+ case MEDIA_VISION_COLORSPACE_I420:
+ channelsNumber = 1;
+ height *= 1.5;
+ conversionType = CV_YUV2GRAY_I420;
+ break;
+ case MEDIA_VISION_COLORSPACE_NV12:
+ channelsNumber = 1;
+ height *= 1.5;
+ conversionType = CV_YUV2GRAY_NV12;
+ break;
+ case MEDIA_VISION_COLORSPACE_YV12:
+ channelsNumber = 1;
+ height *= 1.5;
+ conversionType = CV_YUV2GRAY_YV12;
+ break;
+ case MEDIA_VISION_COLORSPACE_NV21:
+ channelsNumber = 1;
+ height *= 1.5;
+ conversionType = CV_YUV2GRAY_NV21;
+ break;
+ case MEDIA_VISION_COLORSPACE_YUYV:
+ channelsNumber = 2;
+ conversionType = CV_YUV2GRAY_YUYV;
+ break;
+ case MEDIA_VISION_COLORSPACE_UYVY:
+ channelsNumber = 2;
+ conversionType = CV_YUV2GRAY_UYVY;
+ break;
+ case MEDIA_VISION_COLORSPACE_422P:
+ channelsNumber = 2;
+ conversionType = CV_YUV2GRAY_Y422;
+ break;
+ case MEDIA_VISION_COLORSPACE_RGB565:
+ channelsNumber = 2;
+ conversionType = CV_BGR5652GRAY;
+ break;
+ case MEDIA_VISION_COLORSPACE_RGB888:
+ channelsNumber = 3;
+ conversionType = CV_RGB2GRAY;
+ break;
+ case MEDIA_VISION_COLORSPACE_RGBA:
+ channelsNumber = 4;
+ conversionType = CV_RGBA2GRAY;
+ break;
+ default:
+ LOGE("Error: mv_source has unsupported colorspace.");
+ return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT;
+ }
+
+ if (conversionType == -1) { /* Without conversion */
+ cvSource = cv::Mat(cv::Size(width, height),
+ CV_MAKETYPE(depth, channelsNumber), buffer).clone();
+ } else { /* Conversion */
+ /* Class for representation the given image as cv::Mat before conversion */
+ cv::Mat origin(cv::Size(width, height),
+ CV_MAKETYPE(depth, channelsNumber), buffer);
+ cv::cvtColor(origin, cvSource, conversionType);
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+#ifdef ENABLE_NEON
+int SurveillanceHelper::convertSourceMVRGB2GrayCVNeon(
+ mv_source_h mvSource,
+ cv::Mat& cvSource)
+{
+ MEDIA_VISION_INSTANCE_CHECK(mvSource);
+
+ const int depth = CV_8U; /* Default depth. 1 byte per channel. */
+ unsigned int width = 0, height = 0;
+ unsigned int bufferSize = 0;
+ unsigned char *src = NULL;
+
+ mv_colorspace_e colorspace = MEDIA_VISION_COLORSPACE_INVALID;
+
+ MEDIA_VISION_ASSERT(mv_source_get_width(mvSource, &width),
+ "Failed to get the width.");
+ MEDIA_VISION_ASSERT(mv_source_get_height(mvSource, &height),
+ "Failed to get the height.");
+ MEDIA_VISION_ASSERT(mv_source_get_colorspace(mvSource, &colorspace),
+ "Failed to get the colorspace.");
+ MEDIA_VISION_ASSERT(mv_source_get_buffer(mvSource, &src, &bufferSize),
+ "Failed to get the buffer size.");
+
+ if (colorspace != MEDIA_VISION_COLORSPACE_RGB888) {
+ LOGE("Error: mv_source has unsupported colorspace.");
+ return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT;
+ }
+
+ cvSource = cv::Mat(cv::Size(width, height), CV_MAKETYPE(depth, 1));
+ const unsigned int cvSourceSize = width * height;
+
+#if defined(__aarch64__)
+ asm volatile ("lsr %2, %2, #3 \n"
+ "# channel multimpliers: \n"
+ "mov w4, #28 \n"
+ "mov w5, #151 \n"
+ "mov w6, #77 \n"
+ "dup v3.8b, w4 \n"
+ "dup v4.8b, w5 \n"
+ "dup v5.8b, w6 \n"
+ ".loop: \n"
+ "# load 8 pixels: \n"
+ "ld3 {v0.8b,v1.8b,v2.8b}, [%0],#24 \n"
+ "# conversion: \n"
+ "umull v7.8h, v0.8b, v3.8b \n"
+ "umlal v7.8h, v1.8b, v4.8b \n"
+ "umlal v7.8h, v2.8b, v5.8b \n"
+ "# shift and store: \n"
+ "shrn v6.8b, v7.8h, #8 \n"
+ "st1 {v6.8b}, [%1],#8 \n"
+ "subs %2, %2, #1 \n"
+ "bne .loop \n"::"r" (src), "r" (cvSource.data), "r" (cvSourceSize)
+ :"memory", "w4", "w5", "w6");
+#else
+ asm volatile ("lsr %2, %2, #3 \n"
+ "# channel multimpliers: \n"
+ "mov r4, #77 \n"
+ "mov r5, #151 \n"
+ "mov r6, #28 \n"
+ "vdup.8 d3, r4 \n"
+ "vdup.8 d4, r5 \n"
+ "vdup.8 d5, r6 \n"
+ ".loop: \n"
+ "# load 8 pixels: \n"
+ "vld3.8 {d0-d2}, [%0]! \n"
+ "# conversion: \n"
+ "vmull.u8 q7, d0, d3 \n"
+ "vmlal.u8 q7, d1, d4 \n"
+ "vmlal.u8 q7, d2, d5 \n"
+ "# shift and store: \n"
+ "vshrn.u16 d6, q7, #8 \n"
+ "vst1.8 {d6}, [%1]! \n"
+ "subs %2, %2, #1 \n"
+ "bne .loop \n"::"r" (src), "r" (cvSource.data), "r" (cvSourceSize)
+ :"memory", "r4", "r5", "r6");
+#endif
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+#endif
+
+} /* surveillance */
+} /* mediavision */
diff --git a/mv_surveillance/surveillance/src/mv_absdiff.c b/mv_surveillance/surveillance/src/mv_absdiff.c
new file mode 100644
index 00000000..9e122e66
--- /dev/null
+++ b/mv_surveillance/surveillance/src/mv_absdiff.c
@@ -0,0 +1,81 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mv_absdiff.h"
+
+#include "mv_common.h"
+#include "mv_private.h"
+
+#ifdef ENABLE_NEON
+#include <arm_neon.h>
+#endif
+
+int mv_absdiff(
+ uint8_t *__restrict__ src1,
+ uint8_t *__restrict__ src2,
+ int width,
+ int height,
+ int stride,
+ uint8_t *__restrict__ dst)
+{
+ if (src1 == NULL || src2 == NULL || width <= 0 || height <= 0 ||
+ stride <= 0 || dst == NULL) {
+ LOGE("Wrong input parameter. Aplpying mask failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ int column = 0;
+ int row = 0;
+ const int padding = stride - width;
+
+#ifdef ENABLE_NEON
+ const int batch_size = 16;
+ const int batch_columns_count = width / batch_size;
+#endif
+
+ for (; row < height; ++row) {
+#ifdef ENABLE_NEON
+ for (column = 0; column < batch_columns_count; ++column) {
+ uint8x16_t gray1 = vld1q_u8 (src1);
+ uint8x16_t gray2 = vld1q_u8 (src2);
+
+ uint8x16_t dst_temp = vabdq_u8(gray1, gray2);
+
+ vst1q_u8 (dst, dst_temp);
+
+ src1 += batch_size;
+ src2 += batch_size;
+ dst += batch_size;
+ }
+#else
+ for (column = 0; column < width; ++column) {
+ uint8_t gray1 = *src1;
+ uint8_t gray2 = *src2;
+
+ (*dst) = abs((*src1) - (*src2));
+
+ ++src1;
+ ++src2;
+ ++dst;
+ }
+#endif
+ src1 += padding;
+ src2 += padding;
+ dst += padding;
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
diff --git a/mv_surveillance/surveillance/src/mv_apply_mask.c b/mv_surveillance/surveillance/src/mv_apply_mask.c
new file mode 100644
index 00000000..f156d072
--- /dev/null
+++ b/mv_surveillance/surveillance/src/mv_apply_mask.c
@@ -0,0 +1,77 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mv_apply_mask.h"
+
+#include "mv_common.h"
+#include "mv_private.h"
+
+#ifdef ENABLE_NEON
+#include <arm_neon.h>
+#endif
+
+int mv_apply_mask(
+ uint8_t *src_buffer,
+ uint8_t *__restrict mask,
+ int width,
+ int height,
+ int stride,
+ uint8_t *dst_buffer)
+{
+ if (src_buffer == NULL || mask == NULL || width <= 0 || height <= 0 ||
+ stride <= 0 || dst_buffer == NULL) {
+ LOGE("Wrong input parameter. Aplpying mask failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ const int padding = stride - width;
+
+#ifdef ENABLE_NEON
+ const int batch_size = 16;
+ const int batch_columns_count = width / batch_size;
+#endif
+
+ int row = 0;
+ int column = 0;
+ for (; row < height; ++row) {
+#ifdef ENABLE_NEON
+ for (column = 0; column < batch_columns_count; ++column) {
+ uint8x16_t src_v = vld1q_u8(src_buffer);
+ uint8x16_t mask_v = vld1q_u8(mask);
+
+ uint8x16_t dst_v = vandq_u8(src_v, mask_v);
+
+ vst1q_u8(dst_buffer, dst_v);
+
+ dst_buffer += batch_size;
+ src_buffer += batch_size;
+ mask += batch_size;
+ }
+#else
+ for (column = 0; column < width; ++column) {
+ (*dst_buffer) = ((*src_buffer) & (*mask));
+ ++dst_buffer;
+ ++src_buffer;
+ ++mask;
+ }
+#endif
+ dst_buffer += padding;
+ src_buffer += padding;
+ mask += padding;
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
diff --git a/mv_surveillance/surveillance/src/mv_mask_buffer.c b/mv_surveillance/surveillance/src/mv_mask_buffer.c
new file mode 100644
index 00000000..f1d50efe
--- /dev/null
+++ b/mv_surveillance/surveillance/src/mv_mask_buffer.c
@@ -0,0 +1,89 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mv_mask_buffer.h"
+
+#include "mv_common.h"
+#include "mv_private.h"
+
+#include <stdio.h>
+
+int mv_get_mask_buffer(
+ unsigned int buffer_width,
+ unsigned int buffer_height,
+ mv_point_s *polygon,
+ unsigned int points_number,
+ unsigned char **mask_buffer)
+{
+ if (buffer_width == 0u || buffer_height == 0u ||
+ polygon == NULL|| points_number == 0u || mask_buffer == NULL) {
+ LOGE("Wrong input parameter. Getting mask buffer failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ const unsigned int buffer_size = buffer_width * buffer_height;
+
+ *mask_buffer = (unsigned char*) malloc(sizeof(unsigned char) * buffer_size);
+
+ unsigned int i = 0u;
+ unsigned int j = 0u;
+ unsigned int k = 0u;
+
+ int max_x = polygon[0].x;
+ int max_y = polygon[0].y;
+ int min_x = polygon[0].x;
+ int min_y = polygon[0].y;
+
+ for (k = 1u; k < points_number; ++k) {
+ if (polygon[k].x > max_x) {
+ max_x = polygon[k].x;
+ } else if (polygon[k].x < min_x) {
+ min_x = polygon[k].x;
+ }
+
+ if (polygon[k].y > max_y) {
+ max_y = polygon[k].y;
+ } else if (polygon[k].y < min_y) {
+ min_y = polygon[k].y;
+ }
+ }
+
+
+ for (k = 0u; k < buffer_size; ++k) {
+ bool inside_polygon = false;
+
+ const int test_x = (int) k % buffer_width;
+ const int test_y = (int) k / buffer_width;
+
+ if (test_x > max_x || test_x < min_x || test_y > max_y || test_y < min_y) {
+ (*mask_buffer)[k] = 0;
+ continue;
+ }
+
+ for (i = 0u, j = points_number - 1; i < points_number; j = i++) {
+ if (((polygon[i].y > test_y) != (polygon[j].y > test_y)) &&
+ ((float) test_x < (float) (polygon[j].x - polygon[i].x) *
+ (test_y - polygon[i].y) /
+ (polygon[j].y - polygon[i].y) +
+ polygon[i].x)) {
+ inside_polygon = !inside_polygon;
+ }
+ }
+ inside_polygon ? ((*mask_buffer)[k] = 255) : ((*mask_buffer)[k] = 0);
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
diff --git a/mv_surveillance/surveillance/src/mv_surveillance_open.cpp b/mv_surveillance/surveillance/src/mv_surveillance_open.cpp
new file mode 100644
index 00000000..4d4c3281
--- /dev/null
+++ b/mv_surveillance/surveillance/src/mv_surveillance_open.cpp
@@ -0,0 +1,140 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mv_surveillance_open.h"
+
+#include "EventManager.h"
+#include "EventResult.h"
+
+#include <mv_private.h>
+
+using namespace mediavision::surveillance;
+
+int mv_surveillance_subscribe_event_trigger_open(
+ mv_surveillance_event_trigger_h event_trigger,
+ int video_stream_id,
+ mv_engine_config_h engine_cfg,
+ mv_surveillance_event_occurred_cb callback,
+ void *user_data)
+{
+ mv_surveillance_event_trigger_s *handle =
+ (mv_surveillance_event_trigger_s *)event_trigger;
+
+ return EventManager::getInstance().registerEvent(
+ event_trigger,
+ static_cast<long int>(handle->trigger_id),
+ handle->event_type,
+ video_stream_id,
+ engine_cfg,
+ callback,
+ user_data,
+ handle->number_of_roi_points,
+ handle->roi);
+}
+
+int mv_surveillance_unsubscribe_event_trigger_open(
+ mv_surveillance_event_trigger_h event_trigger,
+ int video_stream_id)
+{
+ mv_surveillance_event_trigger_s *handle =
+ (mv_surveillance_event_trigger_s *)event_trigger;
+
+ return EventManager::getInstance().unregisterEvent(
+ static_cast<long int>(handle->trigger_id),
+ video_stream_id);
+}
+
+int mv_surveillance_push_source_open(
+ mv_source_h source,
+ int video_stream_id)
+{
+ MEDIA_VISION_INSTANCE_CHECK(source);
+
+ return EventManager::getInstance().pushSource(source, video_stream_id);
+}
+
+int mv_surveillance_foreach_event_type_open(
+ mv_surveillance_event_type_cb callback,
+ void *user_data)
+{
+ StringVector eventTypes;
+ const int error = EventManager::getInstance().getSupportedEventTypes(eventTypes);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ LOGE("Query events failed due to internal issues. Error code: %i",
+ error);
+ return error;
+ }
+
+ StringConstIter eventIter = eventTypes.begin();
+ while (eventIter != eventTypes.end()) {
+ if (!callback((*eventIter).c_str(), user_data)) {
+ break;
+ }
+ ++eventIter;
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int mv_surveillance_foreach_event_result_value_name_open(
+ const char *event_type,
+ mv_surveillance_event_result_name_cb callback,
+ void *user_data)
+{
+ StringVector eventResultValueNames;
+
+ int error = MEDIA_VISION_ERROR_NONE;
+
+ if (NULL == event_type) {
+ error = EventManager::getInstance().getSupportedEventResultValueNames(
+ eventResultValueNames);
+ } else {
+ error = EventManager::getInstance().getSupportedEventResultValueNames(
+ event_type,
+ eventResultValueNames);
+ }
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ LOGE("Query result value names failed due to internal issues. "
+ "Error code: %i", error);
+ return error;
+ }
+
+ StringConstIter ervnIter = eventResultValueNames.begin();
+ while (ervnIter != eventResultValueNames.end()) {
+ if (!callback((*ervnIter).c_str(), user_data)) {
+ break;
+ }
+ ++ervnIter;
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int mv_surveillance_get_result_value_open(
+ mv_surveillance_result_h result,
+ const char *value_name,
+ void *value)
+{
+ MEDIA_VISION_INSTANCE_CHECK(result);
+ MEDIA_VISION_NULL_ARG_CHECK(value_name);
+ MEDIA_VISION_NULL_ARG_CHECK(value);
+
+ EventResult *eventResult = (EventResult*) result;
+
+ return eventResult->getResultValue(value_name, value);
+}
diff --git a/mv_surveillance/surveillance_lic/CMakeLists.txt b/mv_surveillance/surveillance_lic/CMakeLists.txt
new file mode 100644
index 00000000..266b94aa
--- /dev/null
+++ b/mv_surveillance/surveillance_lic/CMakeLists.txt
@@ -0,0 +1,25 @@
+project(${MV_SURVEILLANCE_LIB_NAME})
+cmake_minimum_required(VERSION 2.6)
+
+set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG _DEBUG)
+
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+
+include_directories("${INC_DIR}")
+include_directories("${PROJECT_SOURCE_DIR}/include")
+include_directories("${PROJECT_SOURCE_DIR}/src")
+
+file(GLOB MV_SURVEILLANCE_INC_LIST "${PROJECT_SOURCE_DIR}/include/*.h")
+file(GLOB MV_SURVEILLANCE_SRC_LIST "${PROJECT_SOURCE_DIR}/src/*.c")
+
+if(FORCED_STATIC_BUILD)
+ add_library(${PROJECT_NAME} STATIC ${MV_SURVEILLANCE_INC_LIST} ${MV_SURVEILLANCE_SRC_LIST})
+else()
+ add_library(${PROJECT_NAME} SHARED ${MV_SURVEILLANCE_INC_LIST} ${MV_SURVEILLANCE_SRC_LIST})
+endif()
+
+target_link_libraries(${PROJECT_NAME} ${MV_COMMON_LIB_NAME})
+
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION lib)
diff --git a/mv_surveillance/surveillance_lic/include/mv_surveillance_lic.h b/mv_surveillance/surveillance_lic/include/mv_surveillance_lic.h
new file mode 100644
index 00000000..16bd4fca
--- /dev/null
+++ b/mv_surveillance/surveillance_lic/include/mv_surveillance_lic.h
@@ -0,0 +1,187 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TIZEN_MEDIAVISION_SURVEILLANCE_LIC_H__
+#define __TIZEN_MEDIAVISION_SURVEILLANCE_LIC_H__
+
+#include <mv_surveillance.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @file mv_surveillance_lic.h
+ * @brief This file contains the Media Vision surveillance API
+ */
+
+/**
+ * @brief Allows to subscribe to the event and start calling @a callback
+ * each time when the @a source is pushed using
+ * @ref mv_surveillance_push_source_lic() and event is detected.
+ *
+ * @since_tizen 3.0
+ * @remarks To stop handling triggering use
+ * @ref mv_surveillance_unsubscribe_event_trigger_lic().
+ * @param [in] event_trigger The event trigger activating calls of the
+ * @a callback function
+ * @param [in] engine_cfg The engine configuration of the event
+ * @param [in] callback Callback to be called each time when event
+ * occurrence is detected
+ * @param [in] user_data The user data to be passed to the callback function
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @post @ref mv_surveillance_event_occurred_cb
+ *
+ * @see mv_surveillance_event_trigger_s
+ * @see mv_surveillance_unsubscribe_event_trigger_lic()
+ */
+int mv_surveillance_subscribe_event_trigger_lic(
+ mv_surveillance_event_trigger_h event_trigger,
+ mv_engine_config_h engine_cfg,
+ mv_surveillance_event_occurred_cb callback,
+ void *user_data);
+
+/**
+ * @brief Allows to unsubscribe from the event and stop calling @a callback.
+ *
+ * @since_tizen 3.0
+ * @remarks To start handling trigger activation use
+ @ref mv_surveillance_subscribe_event_trigger_lic().
+ * @param [in] event_trigger The event trigger for which subscription will be
+ * stopped
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @post @ref mv_surveillance_event_occurred_cb
+ *
+ * @see mv_surveillance_event_trigger_s
+ * @see mv_surveillance_subscribe_event_trigger_lic()
+ */
+int mv_surveillance_unsubscribe_event_trigger_lic(
+ mv_surveillance_event_trigger_h event_trigger);
+
+/**
+ * @brief Allows to push source to the event trigger and start calling @a callback.
+ *
+ * @since_tizen 3.0
+ * @param [in] source The handle to the media source
+ * @param [in] video_stream_id The video stream, wthich will be updated
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @see mv_surveillance_event_trigger_s
+ * @see mv_surveillance_event_occurred_cb
+ * @see mv_surveillance_subscribe_event_trigger_lic()
+ * @see mv_surveillance_unsubscribe_event_trigger_lic()
+ */
+int mv_surveillance_push_source_lic(
+ mv_source_h source,
+ int video_stream_id);
+
+/**
+ * @brief Starts traversing through list of supported event types.
+ *
+ * @since_tizen 3.0
+ * @remarks Supported event types and their descriptions can be found in
+ * @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES documentation
+ * section
+ * @param [in] callback The callback function to be called for each
+ * supported event type
+ * @param [in] user_data The user data to be passed to the @a callback
+ * function
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @see mv_surveillance_event_type_cb
+ * @see mv_surveillance_foreach_event_result_value_name_lic()
+ */
+int mv_surveillance_foreach_event_type_lic(
+ mv_surveillance_event_type_cb callback,
+ void *user_data);
+
+/**
+ * @brief Starts traversing through list of supported event result value names.
+ *
+ * @since_tizen 3.0
+ * @remarks Supported event types, event result value names and their
+ * descriptions can be found in
+ * @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES documentation
+ * section
+ * @param [in] event_type The name of the event type for which result value
+ * names will be passed to the @a callback. Can be
+ * set @c NULL. If set @c NULL then all supported
+ * event result value names will be traversed
+ * @param [in] callback The callback function to be called for each
+ * supported event result value name
+ * @param [in] user_data The user data to be passed to the @a callback
+ * function
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @see mv_surveillance_event_result_value_name_cb
+ * @see mv_surveillance_foreach_event_type_lic()
+ * @see mv_surveillance_get_result_value_lic()
+ */
+int mv_surveillance_foreach_event_result_value_name_lic(
+ const char *event_type,
+ mv_surveillance_event_result_value_name_cb callback,
+ void *user_data);
+
+/**
+ * @brief Gets result value.
+ * @details See the output values names in the event types descriptions located
+ * in /usr/share/config/capi-media-vision/surveillance-event-types.txt.
+ *
+ * @since_tizen 3.0
+ * @param [in] result The handle to the event result
+ * @param [in] value_name The name of the value to be gotten
+ * @param [in, out] value The pointer to variable which will be filled
+ * by result value
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @pre Memory for value has to be allocated
+ *
+ * @see mv_surveillance_event_trigger_s
+ * @see mv_surveillance_event_occurred_cb
+ * @see mv_surveillance_subscribe_event_trigger_lic()
+ * @see mv_surveillance_unsubscribe_event_trigger_lic()
+ * @see mv_surveillance_query_events_lic()
+ */
+int mv_surveillance_get_result_value_lic(
+ mv_surveillance_result_h result,
+ const char *value_name,
+ void *value);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TIZEN_MEDIAVISION_SURVEILLANCE_LIC_H__ */
diff --git a/mv_surveillance/surveillance_lic/src/mv_surveillance_lic.c b/mv_surveillance/surveillance_lic/src/mv_surveillance_lic.c
new file mode 100644
index 00000000..95acb63c
--- /dev/null
+++ b/mv_surveillance/surveillance_lic/src/mv_surveillance_lic.c
@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mv_surveillance_lic.h"
+
+int mv_surveillance_subscribe_event_trigger_lic(
+ mv_surveillance_event_trigger_h event_trigger,
+ mv_engine_config_h engine_cfg,
+ mv_surveillance_event_occurred_cb callback,
+ void *user_data)
+{
+ return MEDIA_VISION_ERROR_NOT_SUPPORTED;
+}
+
+
+int mv_surveillance_unsubscribe_event_trigger_lic(
+ mv_surveillance_event_trigger_h event_trigger)
+{
+ return MEDIA_VISION_ERROR_NOT_SUPPORTED;
+}
+
+int mv_surveillance_push_source_lic(
+ mv_source_h source,
+ int video_stream_id)
+{
+ return MEDIA_VISION_ERROR_NOT_SUPPORTED;
+}
+
+int mv_surveillance_foreach_event_type_lic(
+ mv_surveillance_event_type_cb callback,
+ void *user_data)
+{
+ return MEDIA_VISION_ERROR_NOT_SUPPORTED;
+}
+
+int mv_surveillance_foreach_event_result_value_name_lic(
+ const char *event_type,
+ mv_surveillance_event_result_value_name_cb callback,
+ void *user_data)
+{
+ return MEDIA_VISION_ERROR_NOT_SUPPORTED;
+}
+
+int mv_surveillance_get_result_value_lic(
+ mv_surveillance_result_h result,
+ const char *value_name,
+ void *value)
+{
+ return MEDIA_VISION_ERROR_NOT_SUPPORTED;
+}
diff --git a/packaging/capi-media-vision.spec b/packaging/capi-media-vision.spec
index db59b53c..d7eac4ad 100644
--- a/packaging/capi-media-vision.spec
+++ b/packaging/capi-media-vision.spec
@@ -1,6 +1,6 @@
Name: capi-media-vision
Summary: Media Vision library for Tizen Native API
-Version: 0.2.5
+Version: 0.3.0
Release: 0
Group: Multimedia/Framework
License: Apache-2.0 and BSD-2.0
@@ -49,6 +49,17 @@ export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE"
export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE"
export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE"
%endif
+
+%ifarch %{arm}
+export CFLAGS="$CFLAGS -DENABLE_NEON"
+export CXXFLAGS="$CXXFLAGS -DENABLE_NEON"
+%endif
+
+%ifarch %{aarch64}
+export CFLAGS="$CFLAGS -DENABLE_NEON"
+export CXXFLAGS="$CXXFLAGS -DENABLE_NEON"
+%endif
+
MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
%cmake . -DFULLVER=%{version} -DMAJORVER=${MAJORVER}
diff --git a/src/mv_surveillance.c b/src/mv_surveillance.c
new file mode 100644
index 00000000..48aa2692
--- /dev/null
+++ b/src/mv_surveillance.c
@@ -0,0 +1,363 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mv_surveillance.h"
+
+#include "mv_surveillance_private.h"
+#include "mv_private.h"
+
+#ifdef MEDIA_VISION_SURVEILLANCE_LICENSE_PORT
+
+/* Include headers of licensed surveillance module here. */
+#include "mv_surveillance_lic.h"
+
+#else
+
+/* Include headers of open surveillance module here. */
+#include "mv_surveillance_open.h"
+
+#endif /* MEDIA_VISION_SURVEILLANCE_LICENSE_PORT */
+
+/**
+ * @file mv_surveillance.c
+ * @brief This file contains the porting layer for Media Vision surveillance module.
+ */
+
+static size_t __mv_surveillance_id_counter = 0;
+
+int mv_surveillance_event_trigger_create(
+ const char *event_type,
+ mv_surveillance_event_trigger_h * trigger)
+{
+ MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+ MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+ MEDIA_VISION_NULL_ARG_CHECK(event_type);
+ MEDIA_VISION_NULL_ARG_CHECK(trigger);
+ MEDIA_VISION_FUNCTION_ENTER();
+
+ mv_surveillance_event_trigger_s *handle =
+ (mv_surveillance_event_trigger_s *) malloc(
+ sizeof(mv_surveillance_event_trigger_s));
+ if (NULL == handle) {
+ LOGE("[%s] malloc fail", __func__);
+ return MEDIA_VISION_ERROR_OUT_OF_MEMORY;
+ }
+
+ memset(handle, 0, sizeof(mv_surveillance_event_trigger_s));
+
+ // default values:
+ handle->trigger_id = ++__mv_surveillance_id_counter;
+ handle->event_type = strndup(event_type, 255);
+ handle->number_of_roi_points = 0;
+ handle->roi = NULL;
+
+ *trigger = (mv_surveillance_event_trigger_h) handle;
+
+ MEDIA_VISION_FUNCTION_LEAVE();
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int mv_surveillance_event_trigger_destroy(
+ mv_surveillance_event_trigger_h trigger)
+{
+ MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+ MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+ MEDIA_VISION_NULL_ARG_CHECK(trigger);
+ MEDIA_VISION_FUNCTION_ENTER();
+
+ mv_surveillance_event_trigger_s *handle =
+ (mv_surveillance_event_trigger_s *) trigger;
+ free(handle->event_type);
+ free(handle->roi);
+ free((mv_surveillance_event_trigger_s *) trigger);
+
+ MEDIA_VISION_FUNCTION_LEAVE();
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int mv_surveillance_get_event_trigger_type(
+ mv_surveillance_event_trigger_h trigger,
+ char **event_type)
+{
+ MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+ MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+ MEDIA_VISION_INSTANCE_CHECK(trigger);
+ MEDIA_VISION_NULL_ARG_CHECK(event_type);
+ MEDIA_VISION_FUNCTION_ENTER();
+
+ mv_surveillance_event_trigger_s *handle =
+ (mv_surveillance_event_trigger_s *)trigger;
+ *event_type = strndup(handle->event_type, 255);
+
+ MEDIA_VISION_FUNCTION_LEAVE();
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int mv_surveillance_set_event_trigger_roi(
+ mv_surveillance_event_trigger_h trigger,
+ int number_of_points,
+ mv_point_s *roi)
+{
+ MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+ MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+ MEDIA_VISION_INSTANCE_CHECK(trigger);
+ MEDIA_VISION_NULL_ARG_CHECK(roi);
+ MEDIA_VISION_FUNCTION_ENTER();
+
+ mv_surveillance_event_trigger_s *handle =
+ (mv_surveillance_event_trigger_s *)trigger;
+
+ handle->number_of_roi_points = number_of_points;
+ handle->roi = (mv_point_s*) malloc(sizeof(mv_point_s) * number_of_points);
+
+ if (NULL == handle->roi) {
+ LOGE("[%s] malloc fail", __func__);
+ return MEDIA_VISION_ERROR_OUT_OF_MEMORY;
+ }
+
+ int i = 0;
+ for (; i < number_of_points; ++i) {
+ handle->roi[i].x = roi[i].x;
+ handle->roi[i].y = roi[i].y;
+ }
+
+ MEDIA_VISION_FUNCTION_LEAVE();
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int mv_surveillance_get_event_trigger_roi(
+ mv_surveillance_event_trigger_h trigger,
+ int *number_of_points,
+ mv_point_s ** roi)
+{
+ MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+ MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+ MEDIA_VISION_INSTANCE_CHECK(trigger);
+ MEDIA_VISION_NULL_ARG_CHECK(number_of_points);
+ MEDIA_VISION_NULL_ARG_CHECK(roi);
+ MEDIA_VISION_FUNCTION_ENTER();
+
+ mv_surveillance_event_trigger_s *handle =
+ (mv_surveillance_event_trigger_s *) trigger;
+
+ *number_of_points = handle->number_of_roi_points;
+ if (0 == *number_of_points)
+ {
+ MEDIA_VISION_FUNCTION_LEAVE();
+ return MEDIA_VISION_ERROR_NONE;
+ }
+ *roi = (mv_point_s *) malloc(
+ sizeof(mv_point_s) * handle->number_of_roi_points);
+
+ int i = 0;
+ for (; i < handle->number_of_roi_points; ++i) {
+ (*roi)[i].x = handle->roi[i].x;
+ (*roi)[i].y = handle->roi[i].y;
+ }
+
+ MEDIA_VISION_FUNCTION_LEAVE();
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int mv_surveillance_subscribe_event_trigger(
+ mv_surveillance_event_trigger_h event_trigger,
+ int video_stream_id,
+ mv_engine_config_h engine_cfg,
+ mv_surveillance_event_occurred_cb callback,
+ void *user_data)
+{
+ MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+ MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+ MEDIA_VISION_INSTANCE_CHECK(event_trigger);
+ MEDIA_VISION_NULL_ARG_CHECK(callback);
+ MEDIA_VISION_FUNCTION_ENTER();
+
+#ifdef MEDIA_VISION_SURVEILLANCE_LICENSE_PORT
+
+ /* Use licensed surveillance functionality here. */
+ const int ret = mv_surveillance_subscribe_event_trigger_lic(
+ event_trigger,
+ video_stream_id,
+ engine_cfg,
+ callback,
+ user_data);
+
+#else
+
+ /* Use open surveillance functionality here. */
+ const int ret = mv_surveillance_subscribe_event_trigger_open(
+ event_trigger,
+ video_stream_id,
+ engine_cfg,
+ callback,
+ user_data);
+
+#endif /* MEDIA_VISION_SURVEILLANCE_LICENSE_PORT */
+
+ MEDIA_VISION_FUNCTION_LEAVE();
+ return ret;
+}
+
+int mv_surveillance_unsubscribe_event_trigger(
+ mv_surveillance_event_trigger_h event_trigger,
+ int video_stream_id)
+{
+ MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+ MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+ MEDIA_VISION_INSTANCE_CHECK(event_trigger);
+ MEDIA_VISION_FUNCTION_ENTER();
+
+#ifdef MEDIA_VISION_SURVEILLANCE_LICENSE_PORT
+
+ /* Use licensed surveillance functionality here. */
+ const int ret = mv_surveillance_unsubscribe_event_trigger_lic(
+ event_trigger,
+ video_stream_id);
+
+#else
+
+ /* Use open surveillance functionality here. */
+ const int ret = mv_surveillance_unsubscribe_event_trigger_open(
+ event_trigger,
+ video_stream_id);
+
+#endif /* MEDIA_VISION_SURVEILLANCE_LICENSE_PORT */
+
+ MEDIA_VISION_FUNCTION_LEAVE();
+ return ret;
+}
+
+int mv_surveillance_push_source(
+ mv_source_h source,
+ int video_stream_id)
+{
+ MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+ MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+ MEDIA_VISION_INSTANCE_CHECK(source);
+ MEDIA_VISION_FUNCTION_ENTER();
+
+#ifdef MEDIA_VISION_SURVEILLANCE_LICENSE_PORT
+
+ /* Use licensed surveillance functionality here. */
+ const int ret = mv_surveillance_push_source_lic(source, video_stream_id);
+
+#else
+
+ /* Use open surveillance functionality here. */
+ const int ret = mv_surveillance_push_source_open(source, video_stream_id);
+
+#endif /* MEDIA_VISION_SURVEILLANCE_LICENSE_PORT */
+
+ MEDIA_VISION_FUNCTION_LEAVE();
+ return ret;
+}
+
+int mv_surveillance_foreach_supported_event_type(
+ mv_surveillance_event_type_cb callback,
+ void *user_data)
+{
+ MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+ MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+ MEDIA_VISION_NULL_ARG_CHECK(callback);
+ MEDIA_VISION_FUNCTION_ENTER();
+
+#ifdef MEDIA_VISION_SURVEILLANCE_LICENSE_PORT
+
+ /* Use licensed surveillance functionality here. */
+ const int ret = mv_surveillance_foreach_event_type_lic(
+ callback,
+ user_data);
+
+#else
+
+ /* Use open surveillance functionality here. */
+ const int ret = mv_surveillance_foreach_event_type_open(
+ callback,
+ user_data);
+
+#endif /* MEDIA_VISION_SURVEILLANCE_LICENSE_PORT */
+
+ MEDIA_VISION_FUNCTION_LEAVE();
+ return ret;
+}
+
+int mv_surveillance_foreach_event_result_name(
+ const char *event_type,
+ mv_surveillance_event_result_name_cb callback,
+ void *user_data)
+{
+ MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+ MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+ MEDIA_VISION_NULL_ARG_CHECK(event_type);
+ MEDIA_VISION_NULL_ARG_CHECK(callback);
+ MEDIA_VISION_FUNCTION_ENTER();
+
+#ifdef MEDIA_VISION_SURVEILLANCE_LICENSE_PORT
+
+ /* Use licensed surveillance functionality here. */
+ const int ret = mv_surveillance_foreach_event_result_value_name_lic(
+ event_type,
+ callback,
+ user_data);
+
+#else
+
+ /* Use open surveillance functionality here. */
+ const int ret = mv_surveillance_foreach_event_result_value_name_open(
+ event_type,
+ callback,
+ user_data);
+
+#endif /* MEDIA_VISION_SURVEILLANCE_LICENSE_PORT */
+
+ MEDIA_VISION_FUNCTION_LEAVE();
+
+ return ret;
+}
+
+int mv_surveillance_get_result_value(
+ mv_surveillance_result_h result,
+ const char *value_name,
+ void *value)
+{
+ MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+ MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+ MEDIA_VISION_INSTANCE_CHECK(result);
+ MEDIA_VISION_NULL_ARG_CHECK(value_name);
+ MEDIA_VISION_NULL_ARG_CHECK(value);
+ MEDIA_VISION_FUNCTION_ENTER();
+
+#ifdef MEDIA_VISION_SURVEILLANCE_LICENSE_PORT
+
+ /* Use licensed surveillance functionality here. */
+ const int ret = mv_surveillance_get_result_value_lic(
+ result,
+ value_name,
+ value);
+
+#else
+
+ /* Use open surveillance functionality here. */
+ const int ret = mv_surveillance_get_result_value_open(
+ result,
+ value_name,
+ value);
+
+#endif /* MEDIA_VISION_SURVEILLANCE_LICENSE_PORT */
+
+ MEDIA_VISION_FUNCTION_LEAVE();
+ return ret;
+}
diff --git a/test/testsuites/CMakeLists.txt b/test/testsuites/CMakeLists.txt
index 16a2eb6d..fdb2d204 100644
--- a/test/testsuites/CMakeLists.txt
+++ b/test/testsuites/CMakeLists.txt
@@ -11,3 +11,4 @@ add_subdirectory(${PROJECT_SOURCE_DIR}/common)
add_subdirectory(${PROJECT_SOURCE_DIR}/barcode)
add_subdirectory(${PROJECT_SOURCE_DIR}/face)
add_subdirectory(${PROJECT_SOURCE_DIR}/image)
+add_subdirectory(${PROJECT_SOURCE_DIR}/surveillance) \ No newline at end of file
diff --git a/test/testsuites/surveillance/CMakeLists.txt b/test/testsuites/surveillance/CMakeLists.txt
new file mode 100644
index 00000000..80ac1ac5
--- /dev/null
+++ b/test/testsuites/surveillance/CMakeLists.txt
@@ -0,0 +1,31 @@
+project(mv_surveillance_test_suite)
+cmake_minimum_required(VERSION 2.6)
+
+set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG _DEBUG)
+
+if(NOT SKIP_WARNINGS)
+ set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror")
+endif()
+
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${LIB_INSTALL_DIR})
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${LIB_INSTALL_DIR})
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+
+include_directories(${PROJECT_SOURCE_DIR})
+include_directories(${MV_CAPI_MEDIA_VISION_INC_DIR})
+include_directories(${INC_TS_COMMON})
+include_directories(${INC_VIDEO_HELPER})
+include_directories(${INC_IMAGE_HELPER})
+
+file(GLOB MV_SURVEILLANCE_TS_INC_LIST "${PROJECT_SOURCE_DIR}/*.h")
+file(GLOB MV_SURVEILLANCE_TS_SRC_LIST "${PROJECT_SOURCE_DIR}/*.c")
+
+add_executable(${PROJECT_NAME} ${MV_SURVEILLANCE_TS_SRC_LIST}
+ ${MV_SURVEILLANCE_TS_INC_LIST}
+ ${MV_CAPI_MEDIA_VISION_INC_LIST})
+
+target_link_libraries(${PROJECT_NAME} capi-media-vision
+ mv_testsuite_common
+ mv_image_helper)
+
+install(TARGETS ${PROJECT_NAME} DESTINATION ${testsuites_dir})
diff --git a/test/testsuites/surveillance/surveillance_test_suite.c b/test/testsuites/surveillance/surveillance_test_suite.c
new file mode 100644
index 00000000..60571212
--- /dev/null
+++ b/test/testsuites/surveillance/surveillance_test_suite.c
@@ -0,0 +1,1137 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mv_testsuite_common.h"
+#include "image_helper.h"
+
+#include "mv_log_cfg.h"
+
+#include "mv_private.h"
+#include "mv_surveillance.h"
+
+#include <limits.h>
+
+#define MAX_EVENTS_NUMBER 101
+
+#define MAX_EVENT_TYPE_LEN 255
+
+#define MIN_NUMBER_OF_ROI_POINTS 3
+#define MAX_NUMBER_OF_ROI_POINTS 100
+
+#define MIN_ROI_X_COORD 0
+#define MAX_ROI_X_COORD 10000
+#define MIN_ROI_Y_COORD 0
+#define MAX_ROI_Y_COORD 10000
+
+/*----------------------------------------------------*/
+
+#define PRINT_R(MSG) printf(TEXT_RED MSG "\n" TEXT_RESET)
+#define PRINT_Y(MSG) printf(TEXT_YELLOW MSG "\n" TEXT_RESET)
+#define PRINT_G(MSG) printf(TEXT_GREEN MSG "\n" TEXT_RESET);
+
+#define PRINT_E(MSG, ERR) printf(TEXT_RED MSG "\n" TEXT_RESET, ERR)
+#define PRINT_W(MSG, WARN) printf(TEXT_YELLOW MSG "\n" TEXT_RESET, WARN)
+#define PRINT_S(MSG, RES) printf(TEXT_GREEN MSG "\n" TEXT_RESET, RES)
+
+/*----------------------------------------------------*/
+/* static */
+static mv_surveillance_event_trigger_h is_subscribed[MAX_EVENTS_NUMBER];
+static int video_streams_ids[MAX_EVENTS_NUMBER];
+static unsigned int trigger_id_cnt = 0;
+static const int green_color[] = {0, 255, 0};
+static const int red_color[] = {0, 0, 255};
+static const int blue_color[] = {255, 0, 0};
+static bool save_results_to_image = false;
+/*----------------------------------------------------*/
+/*functions*/
+
+/* initializes is_subscribed by false */
+void init_is_subscribed();
+
+/* prints identificators of subscribed events */
+void print_is_subscribed();
+
+/* prints names of all available event types */
+void print_supported_events();
+
+/* select event name from all available event types and creates trigger handle */
+int create_trigger_handle_by_event_name(mv_surveillance_event_trigger_h *handle);
+
+/* subscribes event */
+void subscribe_to_event();
+
+/* adds ROI to event */
+void add_roi_to_event(mv_surveillance_event_trigger_h event_trigger);
+
+/* unsubscribes from event */
+void unsubscribe_from_event();
+
+/* unsubscribes from all event */
+void unsubscribe_from_all_events();
+
+/* pushes media source to event manager */
+void push_source();
+
+/* fills engine configuration for person recognized event */
+bool fill_engine_cfg_person_recognized(mv_engine_config_h engine_cfg);
+
+/* Turn on (off) saving event results to image file */
+void turn_on_off_saving_to_image();
+
+/*----------------------------------------------------*/
+/* callbacks */
+
+void detect_person_appeared_cb(
+ mv_surveillance_event_trigger_h handle,
+ mv_source_h source,
+ int video_stream_id,
+ mv_surveillance_result_h event_result,
+ void *user_data);
+
+void person_recognized_cb(
+ mv_surveillance_event_trigger_h handle,
+ mv_source_h source,
+ int video_stream_id,
+ mv_surveillance_result_h event_result,
+ void *user_data);
+
+void movement_detected_cb(
+ mv_surveillance_event_trigger_h handle,
+ mv_source_h source,
+ int video_stream_id,
+ mv_surveillance_result_h event_result,
+ void *user_data);
+
+/*----------------------------------------------------*/
+
+int main(void)
+{
+ LOGI("Surveillance Media Vision Testsuite is launched.");
+
+ PRINT_W("Maximal number of events is %d", MAX_EVENTS_NUMBER - 1);
+
+ init_is_subscribed();
+
+ const int options[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ const char *names[8] = {
+ "Get list of supported events",
+ "Get identificators of subscribed events",
+ "Subscribe to event",
+ "Unsubscribe from event",
+ "Unsubscribe from all events",
+ "Push source",
+ "Turn on (off) saving event result to image",
+ "Exit"
+ };
+
+ while(1) {
+ char exit = 'n';
+ int sel_opt = show_menu("Select action:", options, names, 8);
+ switch (sel_opt) {
+ case 1: /* Get list of supported events */
+ print_supported_events();
+ break;
+ case 2: /* Get identificators of subscribed events */
+ print_is_subscribed();
+ break;
+ case 3: /* Subscribe to event */
+ subscribe_to_event();
+ break;
+ case 4: /* Unsubscribe from event */
+ unsubscribe_from_event();
+ break;
+ case 5: /* Unsubscribe from all events */
+ unsubscribe_from_all_events();
+ break;
+ case 6: /* Push source */
+ push_source();
+ break;
+ case 7: /* Save event results to image */
+ turn_on_off_saving_to_image();
+ break;
+ case 8: /* Exit */
+ exit = 'y';
+ break;
+ default:
+ PRINT_R("Invalid option.");
+ sel_opt = 0;
+ continue;
+ }
+
+ if ('y' == exit) {
+ sel_opt = 0;
+ const int options_last[2] = { 1, 2 };
+ const char *names_last[2] = { "No", "Yes" };
+
+ while (sel_opt == 0) {
+ sel_opt = show_menu("Are you sure?",
+ options_last, names_last, 2);
+ switch (sel_opt) {
+ case 1:
+ exit = 'n';
+ break;
+ case 2:
+ exit = 'y';
+ break;
+ default:
+ PRINT_R("Invalid option. Back to the main menu.");
+ sel_opt = 0;
+ break;
+ }
+ }
+
+ if ('y' == exit) {
+ unsubscribe_from_all_events();
+ break;
+ }
+ }
+ }
+
+ LOGI("Surveillance Media Vision Testsuite is closed");
+
+ return 0;
+}
+
+void init_is_subscribed()
+{
+ int i = 0;
+ for (; i < MAX_EVENTS_NUMBER; ++i) {
+ is_subscribed[i] = NULL;
+ video_streams_ids[i] = -1;
+ }
+}
+
+void print_is_subscribed()
+{
+ PRINT_Y("List of subscribed events identificators:");
+
+ bool is_empty = true;
+
+ int i = 0;
+ for (; i < MAX_EVENTS_NUMBER; ++i) {
+ if (NULL != is_subscribed[i]) {
+ printf("%d ", i);
+ is_empty = false;
+ }
+ }
+
+ if (is_empty)
+ PRINT_Y("List of subscribed events is empty");
+}
+
+static const char *EVENT_TYPES_NAMES[MAX_EVENT_TYPE_LEN] = {
+ MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED,
+ MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED,
+ MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED
+};
+
+static const unsigned int NUMBER_OF_TYPES = 3u;
+
+bool foreach_event_result_value_name_cb(const char *value_name, void *user_data)
+{
+ if (NULL == value_name) {
+ PRINT_R("\tError occurred. Value name is NULL");
+ return true;
+ }
+ PRINT_W("%s", value_name);
+ return true;
+}
+
+bool foreach_event_type_cb(const char *event_type, void *user_data)
+{
+ if (NULL == event_type) {
+ PRINT_R("Error occurred. Event type name is NULL");
+ return true;
+ }
+
+ PRINT_W("%s", event_type);
+ PRINT_G("\tList of supported event result value names is:");
+
+ const int error = mv_surveillance_foreach_event_result_name(
+ event_type, foreach_event_result_value_name_cb, user_data);
+ if (MEDIA_VISION_ERROR_NONE != error) {
+ PRINT_E("Error occurred when trying to get value names for "
+ "event named '%s'", event_type);
+ return true;
+ }
+ return true;
+}
+
+void print_supported_events()
+{
+ PRINT_G("List of supported events is:");
+
+ const int error = mv_surveillance_foreach_supported_event_type(
+ foreach_event_type_cb, NULL);
+
+ if (MEDIA_VISION_ERROR_NONE != error)
+ PRINT_R("Error occurred when trying to get list of event type names \n");
+}
+
+int create_trigger_handle_by_event_name(
+ mv_surveillance_event_trigger_h *handle)
+{
+ PRINT_G("\nSelect event type:");
+
+ unsigned int i = 0u;
+ for (; i < NUMBER_OF_TYPES; ++i)
+ printf("#%d. %s\n", i, EVENT_TYPES_NAMES[i]);
+
+ unsigned int event_id = 0u;
+ while (input_size("Input event type (unsigned integer value):",
+ NUMBER_OF_TYPES - 1, &event_id) == -1) {
+ PRINT_R("Incorrect input! Try again.\n List of supported events is:");
+
+ unsigned int i = 0u;
+ for (; i < NUMBER_OF_TYPES; ++i)
+ printf("%d\t%s\n", i, EVENT_TYPES_NAMES[i]);
+ }
+
+ const int error = mv_surveillance_event_trigger_create(
+ EVENT_TYPES_NAMES[event_id], handle);
+ if (MEDIA_VISION_ERROR_NONE != error) {
+ PRINT_E("mv_surveillance_event_trigger_create() error!\n"
+ "Error code: %i\n", error);
+ return error;
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+bool try_destroy_event_trigger(mv_surveillance_event_trigger_h trigger)
+{
+ const int error = mv_surveillance_event_trigger_destroy(trigger);
+ if (MEDIA_VISION_ERROR_NONE != error) {
+ PRINT_E("Error with code %d was occured when try to destroy "
+ "event trigger.", error);
+ return false;
+ }
+ return true;
+}
+
+void subscribe_to_event()
+{
+ if (++trigger_id_cnt >= MAX_EVENTS_NUMBER) {
+ PRINT_R("Maximal value of event trigger id is reached. "
+ "Subscription impossible");
+ return;
+ }
+
+ mv_surveillance_event_trigger_h event_trigger = NULL;
+ int error = create_trigger_handle_by_event_name(&event_trigger);
+ if (MEDIA_VISION_ERROR_NONE != error) {
+ PRINT_E("Error occurred when creating of event trigger. "
+ "Error code: %i", error);
+ try_destroy_event_trigger(event_trigger);
+ return;
+ }
+
+ int video_stream_id = 0;
+
+ while (input_int("Input video stream identificator (integer value):",
+ INT_MIN,
+ INT_MAX,
+ &video_stream_id) == -1)
+ PRINT_R("Incorrect input! Try again.");
+
+ char *event_type = NULL;
+ error = mv_surveillance_get_event_trigger_type(event_trigger, &event_type);
+ if (MEDIA_VISION_ERROR_NONE != error) {
+ PRINT_E("Error occurred when getting of event trigger type. "
+ "Error code: %i", error);
+ try_destroy_event_trigger(event_trigger);
+ return;
+ }
+
+ if (show_confirm_dialog("Would you like to set ROI (Region Of Interest)?"))
+ add_roi_to_event(event_trigger);
+
+ if (strncmp(event_type,
+ MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED,
+ MAX_EVENT_TYPE_LEN) == 0) {
+ error = mv_surveillance_subscribe_event_trigger(
+ event_trigger,
+ video_stream_id,
+ NULL,
+ detect_person_appeared_cb,
+ NULL);
+ } else if (strncmp(event_type,
+ MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED,
+ MAX_EVENT_TYPE_LEN) == 0) {
+ PRINT_Y("Please create and save face recognition models\n"
+ "before subscribing to event. Use mv_face_test_suite.");
+
+ mv_engine_config_h engine_cfg = NULL;
+ error = mv_create_engine_config(&engine_cfg);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ PRINT_R("Failed to create engine configuration for event trigger.");
+ try_destroy_event_trigger(event_trigger);
+ free(event_type);
+ return;
+ }
+
+ const bool is_filled = fill_engine_cfg_person_recognized(engine_cfg);
+
+ if (!is_filled) {
+ PRINT_R("Failed to fill engine configuration for event trigger.");
+ try_destroy_event_trigger(event_trigger);
+ if (mv_destroy_engine_config(engine_cfg) != MEDIA_VISION_ERROR_NONE)
+ PRINT_E("Failed to destroy engine configuration for event trigger.",
+ error);
+ free(event_type);
+ return;
+ }
+
+ error = mv_surveillance_subscribe_event_trigger(
+ event_trigger,
+ video_stream_id,
+ engine_cfg,
+ person_recognized_cb,
+ NULL);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ PRINT_E("Subscription failed. Error code: %i.", error);
+ try_destroy_event_trigger(event_trigger);
+ if (mv_destroy_engine_config(engine_cfg) != MEDIA_VISION_ERROR_NONE)
+ PRINT_E("Failed to destroy engine configuration for event trigger.",
+ error);
+ free(event_type);
+ return;
+ }
+
+ if (mv_destroy_engine_config(engine_cfg) != MEDIA_VISION_ERROR_NONE)
+ PRINT_E("Failed to destroy engine configuration for event trigger.",
+ error);
+ } else if (strncmp(event_type,
+ MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED,
+ MAX_EVENT_TYPE_LEN) == 0) {
+ error = mv_surveillance_subscribe_event_trigger(
+ event_trigger,
+ video_stream_id,
+ NULL,
+ movement_detected_cb,
+ NULL);
+ }
+
+ free(event_type);
+
+ if (MEDIA_VISION_ERROR_NONE != error) {
+ PRINT_E("Error with code %d was occurred in subscribe event.", error);
+ try_destroy_event_trigger(event_trigger);
+ return;
+ }
+
+ is_subscribed[trigger_id_cnt] = event_trigger;
+ video_streams_ids[trigger_id_cnt] = video_stream_id;
+ PRINT_S("Event trigger %i has been successfully subscribed", trigger_id_cnt);
+}
+
+void add_roi_to_event(mv_surveillance_event_trigger_h event_trigger)
+{
+ int number_of_roi_points = 0;
+ while (input_int("Input number of ROI points (integer value >2):",
+ MIN_NUMBER_OF_ROI_POINTS,
+ MAX_NUMBER_OF_ROI_POINTS,
+ &number_of_roi_points) == -1)
+ PRINT_R("Incorrect input! Try again.");
+
+ mv_point_s* roi = (mv_point_s*) malloc(sizeof(mv_point_s) * number_of_roi_points);
+
+ int x = 0;
+ int y = 0;
+
+ int i = 0;
+ for (; i < number_of_roi_points; ++i) {
+ printf("Point %d \n", i + 1);
+
+ while (input_int("Input x (integer value):",
+ MIN_ROI_X_COORD,
+ MAX_ROI_X_COORD,
+ &x) == -1)
+ PRINT_R("Incorrect input! Try again.");
+
+ while (input_int("Input y (integer value):",
+ MIN_ROI_Y_COORD,
+ MAX_ROI_Y_COORD,
+ &y) == -1)
+ PRINT_R("Incorrect input! Try again.");
+
+ roi[i].x = x;
+ roi[i].y = y;
+ }
+
+ const int error = mv_surveillance_set_event_trigger_roi(
+ event_trigger,
+ number_of_roi_points,
+ roi);
+
+ if (error == MEDIA_VISION_ERROR_NONE)
+ PRINT_G("ROI was successfully set")
+ else
+ PRINT_R("Setting ROI failed. Please try again") ;
+
+ if (roi != NULL)
+ free(roi);
+}
+
+void unsubscribe_from_event()
+{
+ int trigger_id = 0;
+ while (input_int("Input event identificator (1-100):",
+ 1,
+ MAX_EVENTS_NUMBER - 1,
+ &trigger_id) == -1)
+ PRINT_R("Incorrect input! Try again.");
+
+ mv_surveillance_event_trigger_h event_trigger = is_subscribed[trigger_id];
+ if (NULL == event_trigger) {
+ PRINT_E("Sorry, event trigger with %i identifier wasn't subscribed.",
+ trigger_id);
+ return;
+ }
+
+ const int error = mv_surveillance_unsubscribe_event_trigger(
+ event_trigger,
+ video_streams_ids[trigger_id]);
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ PRINT_E("Error with code %d was occured in unsubscribe event.", error);
+ return;
+ }
+
+ try_destroy_event_trigger(event_trigger);
+ is_subscribed[trigger_id] = NULL;
+ video_streams_ids[trigger_id] = -1;
+ PRINT_S("Event with id %d was successfully unsubscribed", trigger_id);
+}
+
+void unsubscribe_from_all_events()
+{
+ int error = MEDIA_VISION_ERROR_NONE;
+ unsigned int trigger_id = 0;
+ int unsubscribed_number = 0;
+ for (; trigger_id < MAX_EVENTS_NUMBER; ++trigger_id) {
+ mv_surveillance_event_trigger_h event_trigger =
+ is_subscribed[trigger_id];
+ if (NULL != event_trigger) {
+ error = mv_surveillance_unsubscribe_event_trigger(
+ event_trigger,
+ video_streams_ids[trigger_id]);
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ PRINT_E("Error with code %d was occurred in unsubscribe event.",
+ error);
+ continue;
+ }
+ ++unsubscribed_number;
+
+ PRINT_S("Event with id %d was successfully unsubscribed", trigger_id);
+
+ try_destroy_event_trigger(event_trigger);
+ is_subscribed[trigger_id] = NULL;
+ video_streams_ids[trigger_id] = -1;
+ }
+ }
+
+ unsubscribed_number > 0 ?
+ PRINT_S("%d event(s) was successfully unsubscribed", unsubscribed_number):
+ PRINT_Y("\nThere are no triggers can be unsubscribed.");
+}
+
+void push_source()
+{
+ mv_source_h source;
+ int error = mv_create_source(&source);
+ if (MEDIA_VISION_ERROR_NONE != error) {
+ PRINT_E("ERROR: Errors were occurred during source creating!!! Code %i" ,
+ error);
+ return;
+ }
+
+ char *path_to_image = NULL;
+
+ while (input_string("Input file name with image to be analyzed:",
+ 1024, &path_to_image) == -1)
+ PRINT_R("Incorrect input! Try again.");
+
+ error = load_mv_source_from_file(path_to_image, source);
+ if (MEDIA_VISION_ERROR_NONE != error) {
+ PRINT_E("Errors were occurred during source loading, code %i", error);
+ return;
+ }
+
+ if (path_to_image != NULL)
+ free(path_to_image);
+
+ int video_stream_id = 0;
+
+ while (input_int("Input video stream identificator (integer value):",
+ INT_MIN,
+ INT_MAX,
+ &video_stream_id) == -1)
+ PRINT_R("Incorrect input! Try again.");
+
+ error = mv_surveillance_push_source(source, video_stream_id);
+ if (MEDIA_VISION_ERROR_NONE != error) {
+ PRINT_E("Errors were occurred during source pushing, code %i", error);
+ return;
+ }
+
+ error = mv_destroy_source(source);
+ if (MEDIA_VISION_ERROR_NONE != error) {
+ PRINT_E("Errors were occurred during source destroying, code %i", error);
+ return;
+ }
+
+ PRINT_G("Media source was successfully pushed");
+}
+
+bool fill_engine_cfg_person_recognized(mv_engine_config_h engine_cfg)
+{
+ char *path_to_model = NULL;
+
+ while (input_string("Input file name with face recognition model:",
+ 1024, &path_to_model) == -1)
+ PRINT_R("Incorrect input! Try again.");
+
+ const int error = mv_engine_config_set_string_attribute(
+ engine_cfg,
+ MV_SURVEILLANCE_FACE_RECOGNITION_MODEL_FILE_PATH,
+ path_to_model);
+
+ if (error != MEDIA_VISION_ERROR_NONE)
+ PRINT_E("Setting path to face recognition model failed, code %i",
+ error);
+ else
+ printf("\nModel path is %s \n", path_to_model);
+
+ if (path_to_model != NULL)
+ free(path_to_model);
+
+ return true;
+}
+
+void turn_on_off_saving_to_image()
+{
+ save_results_to_image = !save_results_to_image;
+
+ save_results_to_image ?
+ PRINT_Y("Save event results to image files ON."):
+ PRINT_Y("Save event results to image files OFF.");
+}
+
+void detect_person_appeared_cb(
+ mv_surveillance_event_trigger_h handle,
+ mv_source_h source,
+ int video_stream_id,
+ mv_surveillance_result_h event_result,
+ void *user_data)
+{
+ PRINT_G("Person appeared / disappeared event was occured");
+ if (save_results_to_image)
+ PRINT_G("Output image will be saved to /tmp/person_app.jpg.\n"
+ "Appeared locations - green;\n"
+ "Tracked locations - blue;\n"
+ "Disappeared locations - red.");
+
+ unsigned char *out_buffer = NULL;
+ unsigned int buf_size = 0;
+ image_data_s image_data = { 0, 0, MEDIA_VISION_COLORSPACE_INVALID };
+
+ if (save_results_to_image &&
+ (mv_source_get_buffer(source, &out_buffer, &buf_size) ||
+ mv_source_get_width(source, &(image_data.image_width)) ||
+ mv_source_get_height(source, &(image_data.image_height)) ||
+ mv_source_get_colorspace(source, &(image_data.image_colorspace)) ||
+ out_buffer == NULL ||
+ buf_size == 0))
+ {
+ PRINT_R("ERROR: Creating out image is impossible.");
+
+ return;
+ }
+
+ unsigned char *out_buffer_copy = NULL;
+ if (save_results_to_image) {
+ out_buffer_copy = (unsigned char *) malloc(buf_size);
+ memcpy(out_buffer_copy, out_buffer, buf_size);
+ }
+
+ int number_of_appeared_persons = 0;
+ int error = mv_surveillance_get_result_value(
+ event_result,
+ MV_SURVEILLANCE_PERSONS_APPEARED_NUMBER,
+ &number_of_appeared_persons);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ PRINT_E("Error with code %d was occured in getting number of "
+ "appeared persons.", error);
+ if (out_buffer_copy != NULL)
+ free(out_buffer_copy);
+
+ return;
+ }
+
+ printf("\nNumber of appeared persons is %d \n", number_of_appeared_persons);
+
+ mv_rectangle_s *appeared_locations =
+ malloc(sizeof(mv_rectangle_s) * number_of_appeared_persons);
+
+ error = mv_surveillance_get_result_value(
+ event_result,
+ MV_SURVEILLANCE_PERSONS_APPEARED_LOCATIONS,
+ appeared_locations);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ PRINT_E("Error with code %d was occured in getting locations of "
+ "appeared persons.", error);
+
+ if (appeared_locations != NULL)
+ free(appeared_locations);
+
+ if (out_buffer_copy != NULL)
+ free(out_buffer_copy);
+
+ return;
+ }
+
+ int i = 0;
+ for (; i < number_of_appeared_persons; ++i) {
+ printf("Person #%d location is: x - %d, y - %d, w - %d, h - %d.\n",
+ i,
+ appeared_locations[i].point.x,
+ appeared_locations[i].point.y,
+ appeared_locations[i].width,
+ appeared_locations[i].height);
+
+ if (save_results_to_image)
+ draw_rectangle_on_buffer(
+ appeared_locations[i].point.x,
+ appeared_locations[i].point.y,
+ appeared_locations[i].point.x + appeared_locations[i].width,
+ appeared_locations[i].point.y + appeared_locations[i].height,
+ 3,
+ green_color,
+ &image_data,
+ out_buffer_copy);
+ }
+
+ int number_of_tracked_persons = 0;
+ error = mv_surveillance_get_result_value(
+ event_result,
+ MV_SURVEILLANCE_PERSONS_TRACKED_NUMBER,
+ &number_of_tracked_persons);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ PRINT_E("Error with code %d was occured in getting number of "
+ "tracked persons.", error);
+
+ if (appeared_locations != NULL)
+ free(appeared_locations);
+
+ if (out_buffer_copy != NULL)
+ free(out_buffer_copy);
+
+ return;
+ }
+
+ printf("\nNumber of tracked persons is %d \n", number_of_tracked_persons);
+
+ mv_rectangle_s *tracked_locations =
+ malloc(sizeof(mv_rectangle_s) * number_of_tracked_persons);
+
+ error = mv_surveillance_get_result_value(
+ event_result,
+ MV_SURVEILLANCE_PERSONS_TRACKED_LOCATIONS,
+ tracked_locations);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ PRINT_E("Error with code %d was occured in getting locations of "
+ "tracked persons.", error);
+
+ if (appeared_locations != NULL)
+ free(appeared_locations);
+
+ if (tracked_locations != NULL)
+ free(tracked_locations);
+
+ if (out_buffer_copy != NULL)
+ free(out_buffer_copy);
+
+ return;
+ }
+
+ for (i = 0; i < number_of_tracked_persons; ++i) {
+ printf("Person #%d location is: x - %d, y - %d, w - %d, h - %d.\n",
+ i,
+ tracked_locations[i].point.x,
+ tracked_locations[i].point.y,
+ tracked_locations[i].width,
+ tracked_locations[i].height);
+
+ if (save_results_to_image)
+ draw_rectangle_on_buffer(
+ tracked_locations[i].point.x,
+ tracked_locations[i].point.y,
+ tracked_locations[i].point.x + tracked_locations[i].width,
+ tracked_locations[i].point.y + tracked_locations[i].height,
+ 3,
+ blue_color,
+ &image_data,
+ out_buffer_copy);
+ }
+
+ int number_of_disappeared_persons = 0;
+ error = mv_surveillance_get_result_value(
+ event_result,
+ MV_SURVEILLANCE_PERSONS_DISAPPEARED_NUMBER,
+ &number_of_disappeared_persons);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ PRINT_E("Error with code %d was occured in getting number of "
+ "disappeared persons.", error);
+
+ if (appeared_locations != NULL)
+ free(appeared_locations);
+
+ if (tracked_locations != NULL)
+ free(tracked_locations);
+
+ if (out_buffer_copy != NULL)
+ free(out_buffer_copy);
+
+ return;
+ }
+
+ printf("\nNumber of disappeared persons is %d \n", number_of_disappeared_persons);
+
+ mv_rectangle_s *disappeared_locations =
+ malloc(sizeof(mv_rectangle_s) * number_of_disappeared_persons);
+
+ error = mv_surveillance_get_result_value(
+ event_result,
+ MV_SURVEILLANCE_PERSONS_DISAPPEARED_LOCATIONS,
+ disappeared_locations);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ PRINT_E("Error with code %d was occured in getting locations of "
+ "disappeared persons.", error);
+
+ if (appeared_locations != NULL)
+ free(appeared_locations);
+
+ if (tracked_locations != NULL)
+ free(tracked_locations);
+
+ if (disappeared_locations != NULL)
+ free(disappeared_locations);
+
+ if (out_buffer_copy != NULL)
+ free(out_buffer_copy);
+
+ return;
+ }
+
+ for (i = 0; i < number_of_disappeared_persons; ++i) {
+ printf("Person #%d location is: x - %d, y - %d, w - %d, h - %d.\n",
+ i,
+ disappeared_locations[i].point.x,
+ disappeared_locations[i].point.y,
+ disappeared_locations[i].width,
+ disappeared_locations[i].height);
+
+ if (save_results_to_image)
+ draw_rectangle_on_buffer(
+ disappeared_locations[i].point.x,
+ disappeared_locations[i].point.y,
+ disappeared_locations[i].point.x + disappeared_locations[i].width,
+ disappeared_locations[i].point.y + disappeared_locations[i].height,
+ 3,
+ red_color,
+ &image_data,
+ out_buffer_copy);
+ }
+
+ if (save_results_to_image)
+ save_image_from_buffer("/tmp/person_app.jpg", out_buffer_copy, &image_data, 100);
+
+ printf("\n");
+
+ if (appeared_locations != NULL)
+ free(appeared_locations);
+
+ if (tracked_locations != NULL)
+ free(tracked_locations);
+
+ if (disappeared_locations != NULL)
+ free(disappeared_locations);
+
+ if (out_buffer_copy != NULL)
+ free(out_buffer_copy);
+}
+
+void person_recognized_cb(
+ mv_surveillance_event_trigger_h handle,
+ mv_source_h source,
+ int video_stream_id,
+ mv_surveillance_result_h event_result,
+ void *user_data)
+{
+ PRINT_G("Person recognized event was occurred");
+ if (save_results_to_image)
+ PRINT_G("Output image will be saved to /tmp/person_rec.jpg.\n"
+ "Person recognized locations - red.");
+
+ int number_of_persons = 0;
+ int error = mv_surveillance_get_result_value(
+ event_result,
+ MV_SURVEILLANCE_PERSONS_RECOGNIZED_NUMBER,
+ &number_of_persons);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ PRINT_E("Error with code %d was occured in getting number of persons.",
+ error);
+ return;
+ }
+
+ printf("\nNumber of persons is %d \n\n", number_of_persons);
+
+ mv_rectangle_s *locations = malloc(sizeof(mv_rectangle_s) * number_of_persons);
+
+ error = mv_surveillance_get_result_value(
+ event_result,
+ MV_SURVEILLANCE_PERSONS_RECOGNIZED_LOCATIONS,
+ locations);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ PRINT_E("Error with code %d was occured in getting locations of persons.",
+ error);
+
+ if (locations != NULL)
+ free(locations);
+
+ return;
+ }
+
+ int *labels = malloc(sizeof(int) * number_of_persons);
+
+ error = mv_surveillance_get_result_value(
+ event_result,
+ MV_SURVEILLANCE_PERSONS_RECOGNIZED_LABELS,
+ labels);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ PRINT_E("Error with code %d was occured in getting labels of persons.",
+ error);
+
+ if (locations != NULL)
+ free(locations);
+
+ if (labels != NULL)
+ free(labels);
+
+ return;
+ }
+
+ double *confidences = malloc(sizeof(double) * number_of_persons);
+
+ error = mv_surveillance_get_result_value(
+ event_result,
+ MV_SURVEILLANCE_PERSONS_RECOGNIZED_CONFIDENCES,
+ confidences);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ PRINT_E("Error with code %d was occured in getting confidences of persons.",
+ error);
+
+ if (locations != NULL)
+ free(locations);
+
+ if (labels != NULL)
+ free(labels);
+
+ if (confidences != NULL)
+ free(confidences);
+
+ return;
+ }
+
+ unsigned char *out_buffer = NULL;
+ unsigned int buf_size = 0;
+ image_data_s image_data = { 0, 0, MEDIA_VISION_COLORSPACE_INVALID };
+
+ if (save_results_to_image &&
+ (mv_source_get_buffer(source, &out_buffer, &buf_size) ||
+ mv_source_get_width(source, &(image_data.image_width)) ||
+ mv_source_get_height(source, &(image_data.image_height)) ||
+ mv_source_get_colorspace(source, &(image_data.image_colorspace)) ||
+ out_buffer == NULL ||
+ buf_size == 0))
+ {
+ PRINT_R("ERROR: Creating out image is impossible.");
+
+ return;
+ }
+
+ unsigned char *out_buffer_copy = NULL;
+ if (save_results_to_image) {
+ out_buffer_copy = (unsigned char *) malloc(buf_size);
+ memcpy(out_buffer_copy, out_buffer, buf_size);
+ }
+
+ int i = 0;
+ for (; i < number_of_persons; ++i) {
+ printf("Person %d:\n", labels[i]);
+ printf("Location is: x - %d, y - %d, w - %d, h - %d.\n",
+ locations[i].point.x,
+ locations[i].point.y,
+ locations[i].width,
+ locations[i].height);
+ printf("Model confidence - %3.2f", confidences[i]);
+ printf("\n");
+
+ if (save_results_to_image)
+ draw_rectangle_on_buffer(
+ locations[i].point.x,
+ locations[i].point.y,
+ locations[i].point.x + locations[i].width,
+ locations[i].point.y + locations[i].height,
+ 3,
+ red_color,
+ &image_data,
+ out_buffer_copy);
+ }
+
+ printf("\n");
+
+ if (save_results_to_image)
+ save_image_from_buffer("/tmp/person_rec.jpg", out_buffer_copy, &image_data, 100);
+
+ if (locations != NULL)
+ free(locations);
+
+ if (labels != NULL)
+ free(labels);
+
+ if (confidences != NULL)
+ free(confidences);
+
+ if (out_buffer_copy != NULL)
+ free(out_buffer_copy);
+}
+
+void movement_detected_cb(
+ mv_surveillance_event_trigger_h event_trigger,
+ mv_source_h source,
+ int video_stream_id,
+ mv_surveillance_result_h event_result,
+ void *user_data)
+{
+ PRINT_G("Movement detected event was occured");
+ if (save_results_to_image)
+ PRINT_G("Output image will be saved to /tmp/move_detect.jpg.\n"
+ "Movement detected locations - blue.");
+
+ int number_of_movement_regions = 0;
+ int error = mv_surveillance_get_result_value(
+ event_result,
+ MV_SURVEILLANCE_MOVEMENT_NUMBER_OF_REGIONS,
+ &number_of_movement_regions);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ PRINT_E("Error with code %d was occured in getting number of "
+ "movement regions.", error);
+
+ return;
+ }
+
+ printf("\nNumber of movement regions is %d \n", number_of_movement_regions);
+
+ mv_rectangle_s *movement_regions =
+ malloc(sizeof(mv_rectangle_s) * number_of_movement_regions);
+
+ error = mv_surveillance_get_result_value(
+ event_result,
+ MV_SURVEILLANCE_MOVEMENT_REGIONS,
+ movement_regions);
+
+ if (error != MEDIA_VISION_ERROR_NONE) {
+ PRINT_E("Error with code %d was occured in getting movement regions.",
+ error);
+
+ if (movement_regions != NULL)
+ free(movement_regions);
+
+ return;
+ }
+
+ unsigned char *out_buffer = NULL;
+ unsigned int buf_size = 0;
+ image_data_s image_data = { 0, 0, MEDIA_VISION_COLORSPACE_INVALID };
+
+ if (save_results_to_image &&
+ (mv_source_get_buffer(source, &out_buffer, &buf_size) ||
+ mv_source_get_width(source, &(image_data.image_width)) ||
+ mv_source_get_height(source, &(image_data.image_height)) ||
+ mv_source_get_colorspace(source, &(image_data.image_colorspace)) ||
+ out_buffer == NULL ||
+ buf_size == 0))
+ {
+ PRINT_R("ERROR: Creating out image is impossible.");
+
+ if (movement_regions != NULL)
+ free(movement_regions);
+
+ return;
+ }
+
+ unsigned char *out_buffer_copy = NULL;
+ if (save_results_to_image) {
+ out_buffer_copy = (unsigned char *) malloc(buf_size);
+ memcpy(out_buffer_copy, out_buffer, buf_size);
+ }
+
+ int i = 0;
+ for (; i < number_of_movement_regions; ++i) {
+ printf("Movement #%d region is: x - %d, y - %d, w - %d, h - %d.\n",
+ i,
+ movement_regions[i].point.x,
+ movement_regions[i].point.y,
+ movement_regions[i].width,
+ movement_regions[i].height);
+
+ if (save_results_to_image)
+ draw_rectangle_on_buffer(
+ movement_regions[i].point.x,
+ movement_regions[i].point.y,
+ movement_regions[i].point.x + movement_regions[i].width,
+ movement_regions[i].point.y + movement_regions[i].height,
+ 3,
+ blue_color,
+ &image_data,
+ out_buffer_copy);
+ }
+
+ printf("\n");
+
+ if (save_results_to_image)
+ save_image_from_buffer("/tmp/move_detect.jpg", out_buffer_copy, &image_data, 100);
+
+ if (movement_regions != NULL)
+ free(movement_regions);
+
+ if (out_buffer_copy != NULL)
+ free(out_buffer_copy);
+}