From: Tae-Young Chung Date: Wed, 2 Sep 2015 02:15:49 +0000 (+0900) Subject: Release 0.2.1 - including barcode,face,and image X-Git-Tag: accepted/tizen/mobile/20150904.104716^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F70%2F47370%2F1;p=platform%2Fcore%2Fapi%2Fmediavision.git Release 0.2.1 - including barcode,face,and image Change-Id: If6f9ed9a48376d9a179c5c1fa865b1630a701830 Signed-off-by: Tae-Young Chung --- diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..14ccbda --- /dev/null +++ b/AUTHORS @@ -0,0 +1,8 @@ +ByungWook Jang +Tae-Young Chung +Oleg Kopysov +Ievgen Vagin +Anton Artyukh +Yaroslav Zatsikha +Sergii Rudenko +SeokHoon Lee diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..16f4b13 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,170 @@ + +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +SET(fw_name "capi-media-vision") + +PROJECT(${fw_name}) + +SET(CMAKE_INSTALL_PREFIX /usr) +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) + +# Configure for porting layer: + +# Configure for porting layer: + +option(MEDIA_VISION_BARCODE_DETECTOR_LICENSE_PORT + "Turn on building of licensed port of the barcode detecting module (if OFF - open port will be built)." OFF) +option(MEDIA_VISION_BARCODE_GENERATOR_LICENSE_PORT + "Turn on building of licensed port of the barcode generating module (if OFF - open port will be built)." OFF) +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) + +set(MV_COMMON_LIB_NAME "mv_common") +set(MV_BARCODE_DETECTOR_LIB_NAME "mv_barcode_detector" CACHE STRING + "Name of the library will be built for barcode detecting module (without extension).") +set(MV_BARCODE_GENERATOR_LIB_NAME "mv_barcode_generator" CACHE STRING + "Name of the library will be built for barcode generating module (without extension).") +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(INC_DIR "${PROJECT_SOURCE_DIR}/include") +SET(INC_COMMON "${PROJECT_SOURCE_DIR}/mv_common/include") + +message(STATUS "In_dir ${INC_DIR}") + +if(MEDIA_VISION_BARCODE_DETECTOR_LICENSE_PORT) + add_definitions(-DMEDIA_VISION_BARCODE_DETECTOR_LICENSE_PORT) + SET(INC_BARCODE_DETECTOR "${PROJECT_SOURCE_DIR}/mv_barcode/barcode_detector_lic/include") +else() + SET(INC_BARCODE_DETECTOR "${PROJECT_SOURCE_DIR}/mv_barcode/barcode_detector/include") +endif() + +if(MEDIA_VISION_BARCODE_GENERATOR_LICENSE_PORT) + add_definitions(-DMEDIA_VISION_BARCODE_GENERATOR_LICENSE_PORT) + SET(INC_BARCODE_GENERATOR "${PROJECT_SOURCE_DIR}/mv_barcode/barcode_generator_lic/include") +else() + SET(INC_BARCODE_GENERATOR "${PROJECT_SOURCE_DIR}/mv_barcode/barcode_generator/include") +endif() + +if(MEDIA_VISION_IMAGE_LICENSE_PORT) + add_definitions(-DMEDIA_VISION_IMAGE_LICENSE_PORT) + SET(INC_IMAGE "${PROJECT_SOURCE_DIR}/mv_image/image_lic/include") +else() + SET(INC_IMAGE "${PROJECT_SOURCE_DIR}/mv_image/image/include") +endif() + +INCLUDE_DIRECTORIES(${INC_DIR} ${INC_COMMON} ${INC_BARCODE_DETECTOR} ${INC_BARCODE_GENERATOR} ${INC_IMAGE}) + +if(MEDIA_VISION_FACE_LICENSE_PORT) + add_definitions(-DMEDIA_VISION_FACE_LICENSE_PORT) + SET(INC_FACE "${PROJECT_SOURCE_DIR}/mv_face/face_lic/include") +else() + SET(INC_FACE "${PROJECT_SOURCE_DIR}/mv_face/face/include") +endif() + +INCLUDE_DIRECTORIES(${INC_DIR} ${INC_COMMON} ${INC_BARCODE_DETECTOR} ${INC_BARCODE_GENERATOR} ${INC_FACE}) + +SET(dependents "dlog capi-media-tool capi-system-info capi-appfw-application") +SET(pc_dependents "dlog") + +INCLUDE(FindPkgConfig) +pkg_check_modules(${fw_name} REQUIRED ${dependents}) +FOREACH(flag ${${fw_name}_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") + SET(EXTRA_CXXFLAGS "${EXTRA_CXXFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "-I./include -I./include/headers ${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall -w") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") + +SET(CMAKE_CXX_FLAGS "-I./include -I./include/headers ${CMAKE_CXX_FLAGS} ${EXTRA_CXXFLAGS} -fPIC") +SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g --w") + +IF("${ARCH}" STREQUAL "arm") + ADD_DEFINITIONS("-DTARGET") +ENDIF("${ARCH}" STREQUAL "arm") + +ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"") +ADD_DEFINITIONS("-DTIZEN_DEBUG") + +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=${LIB_INSTALL_DIR}") + +ADD_SUBDIRECTORY(mv_common) +ADD_SUBDIRECTORY(mv_barcode) +ADD_SUBDIRECTORY(mv_image) +ADD_SUBDIRECTORY(mv_face) + +aux_source_directory(src SOURCES) +ADD_LIBRARY(${fw_name} SHARED ${SOURCES}) + +TARGET_LINK_LIBRARIES(${fw_name} ${${fw_name}_LDFLAGS} + ${MV_COMMON_LIB_NAME} + ${MV_BARCODE_DETECTOR_LIB_NAME} + ${MV_BARCODE_GENERATOR_LIB_NAME} + ${MV_IMAGE_LIB_NAME} + ${MV_FACE_LIB_NAME}) + +SET_TARGET_PROPERTIES(${fw_name} + PROPERTIES + VERSION ${FULLVER} + SOVERSION ${MAJORVER} + CLEAN_DIRECT_OUTPUT 1 +) + +INSTALL(TARGETS ${fw_name} DESTINATION ${LIB_INSTALL_DIR}) +INSTALL( + DIRECTORY ${INC_DIR}/ DESTINATION include/media + FILES_MATCHING + PATTERN "*_private.h" EXCLUDE + PATTERN "*.h" + ) + +SET(PC_NAME ${fw_name}) +SET(PC_REQUIRED ${pc_dependents}) +SET(PC_LDFLAGS -l${fw_name}) +SET(PC_CFLAGS -I\${includedir}/media) + +CONFIGURE_FILE( + ${fw_name}.pc.in + ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc + @ONLY +) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) + +ADD_SUBDIRECTORY(test) + +IF(UNIX) + +ADD_CUSTOM_TARGET (distclean @echo cleaning for source distribution) +ADD_CUSTOM_COMMAND( + DEPENDS clean + COMMENT "distribution clean" + COMMAND find + ARGS . + -not -name config.cmake -and \( + -name tester.c -or + -name Testing -or + -name CMakeFiles -or + -name cmake.depends -or + -name cmake.check_depends -or + -name CMakeCache.txt -or + -name cmake.check_cache -or + -name *.cmake -or + -name Makefile -or + -name core -or + -name core.* -or + -name gmon.out -or + -name install_manifest.txt -or + -name *.pc -or + -name *~ \) + | grep -v TC | xargs rm -rf + TARGET distclean + VERBATIM +) + +ENDIF(UNIX) + diff --git a/LICENSE.APLv2 b/LICENSE.APLv2 new file mode 100644 index 0000000..54b213e --- /dev/null +++ b/LICENSE.APLv2 @@ -0,0 +1,204 @@ +Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..ccdad52 --- /dev/null +++ b/NOTICE @@ -0,0 +1,3 @@ +Copyright (c) Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, this software is licensed under Apache License, Version 2. +Please, see the LICENSE file for Apache License terms and conditions. diff --git a/README b/README new file mode 100644 index 0000000..415ddeb --- /dev/null +++ b/README @@ -0,0 +1,161 @@ +CONTENT + +1. GENERAL DESCRIPTION OF THE MEDIA VISION PACKAGE +2. USAGE OF PORTING LAYER FOR CHANGING MEDIA VISION ENGINE MODULES +3. OPEN PORT REQUIRED PACKAGES +4. TEST SUITE + + + + +1. GENERAL DESCRIPTION OF THE MEDIA VISION PACKAGE + +Media Vision package includes following modules: Common, Media Vision Barcode, +Media Vision Face and Media Vision Image. Common module provides two handles +(mv_source_h and mv_engine_config_h) and related fuctionality. It used by +barcode detector and generator submodules. mv_source_h is used for wrapping raw +image data buffers. mv_engine_config_h is optional. It can be used for fine +tuning of internal libraries which are used by API. mv_engine_config_h handle +usually can be used by barcode detector and/or generator modules (these modules +provide mv_barcode_detector and mv_barcode_generator internal libraries) in the +case when Native API doesn't cover all features supported by internal libraries. +Using NULL instead of real mv_engine_h handle as functions parameter has to be +taken into account. In most cases API user prefer to ignore detailed +configuration of the modules. + +Barcode detector submodule API provides tools to analyze the image buffers using +mv_barcode_detect() function. This analysis strives to detect barcodes at the +image, determine the type and extract the message. Results can be processed +using mv_barcode_detected_cb callback. + +Barcode generator submodule API provides tools to generate image buffer (or +image file) with barcode. Barcodes generation can be configured by type, +message, size, encoding mode, ECC (error correction level), version (three last +setting are allowed only for QR Codes). One of two functions can be used: +mv_barcode_generate_source() to generate the mv_source_h handle and +mv_barcode_generate_image() to generate the file with barcode image. + +Media Vision Face module aggregates functionality for detecting, recognition and +tracking the faces on images. More detailed description can be found in doxygen +documentation. + +Media Vision Image module aggregates functionality for recognition and +tracking the Flat Image objects. More detailed description can be found in +doxygen documentation. + + +2. USAGE OF PORTING LAYER FOR CHANGING MEDIA VISION ENGINE MODULES + +By default open source engine libraries are used to provide modules +functionality. But it is possible to substitute them by licensed or other custom +libraries. To enable building of custom library for the Media Vision package, +follow these steps: + +a. Find CMakeLists.txt in the root of the package directory and change + MEDIA_VISION_BARCODE_DETECTOR_LICENSE_PORT (for enabling build of a custom + barcode detector library) and/or + MEDIA_VISION_BARCODE_GENERATOR_LICENSE_PORT (for enabling build of a custom + barcode generator library) and/or + MEDIA_VISION_FACE_LICENSE_PORT (for enabling build of a custom Media Vision + Face library) and/or MEDIA_VISION_IMAGE_LICENSE_PORT (for enabling build of + a custom Media Vision Image library) options to ON. Example: + + # only barcode detector module will be customized + option(MEDIA_VISION_BARCODE_DETECTOR_LICENSE_PORT "..." ON) + # barcode generator module will be default + option(MEDIA_VISION_BARCODE_GENERATOR_LICENSE_PORT "..." OFF) + # face module will be default + option(MEDIA_VISION_FACE_LICENSE_PORT "..." OFF) + # image module will be default + option(MEDIA_VISION_IMAGE_LICENSE_PORT "..." OFF) + +b. Options change will cause CMake to build from different subdirectories of + mv_barcode/mv_face/mv_image directories. mv_barcode/barcode_detector, + mv_barcode/barcode_generator, mv_face/face, mv_image/image subdirectories are + used by default. mv_barcode/barcode_detector_lic, + mv_barcode/mv_barcode_generator_lic, mv_face/face_lic, mv_image/image_lic + subdirectories will be used during build if the corresponding option in ON. + *_lic subdirectories already include base structure of the porting layer + projects, and files will be used by main capi-media-vision library. Use this + files to call functions from custom libraries. For example, you can change + mv_barcode_detect_lic.c file in such a way: + + #include "mv_barcode_detect_lic.h" + #include "custom_library_header.h" + + int mv_barcode_detect_lic( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s roi, + mv_barcode_on_detected_cb detect_cb, + void *user_data) + { + mv_quadrangle_s *locations = NULL; + const char *messages = NULL; + mv_barcode_type_e *types = NULL; + + // Here the call of the custom barcode detection function from + // custom_library_header.h: + int barcodes_number = custom_library_function( + source, roi, &locations, &messages, &types); + + if (barcodes_number > 0) + { + detect_cb( + source, engine_cfg, locations, messages, types, barcodes_number, + user_data); + delete[] locations; + delete[] messages; + delete[] types; + } + + return TIZEN_ERROR_NONE; + } + +c. Change the packaging/capi-media-vision.spec to support any packages required + to be found into the system for success build of the custom libraries. + You also can remove requirements on open packages that are required by + disabled barcode generator/detector, face, image ports. See list of the + dependencies in the section 3 of this README file. + +d. Modify mv_barcode/_lic/CMakeLists.txt file for + linking required libraries and/or including additional headers. Don't modify + the project name or reset ${MV_BARCODE_DETECTOR_LIB_NAME}, + ${MV_BARCODE_GENERATOR_LIB_NAME}, ${MV_FACE_LIB_NAME}, ${MV_IMAGE_LIB_NAME} + variables, because porting layer use these ones during the build. If it is + required to change projects/libraries names, best solution is to change + MV_BARCODE_DETECTOR_LIB_NAME, MV_BARCODE_GENERATOR_LIB_NAME, + MV_FACE_LIB_NAME, MV_IMAGE_LIB_NAME options in the CMakeLists.txt file that + is located in the root of the package sources. + + + +3. OPEN PORT REQUIRED PACKAGES + +Building default barcode detector and generator libraries requires following +dependencies: + +Barcode detector: zbar +Barcode generator: zint +Media Vision Face: opencv_core, opencv_objdetect, opencv_contrib +Media Vision Image: opencv_core, opencv_highgui, opencv_imgproc, + opencv_objdetect, opencv_features2d, opencv_nonfree, + opencv_calib3d + +You can remove BuildRequires sections for these libraries from +packaging/capi-media-vision.spec file if corresponding module/modules is/are +disabled with options mentioned in 2.a. + + + +3. TEST SUITE + +capi-media-vision package includes test suites which allow to check API +functionality. The test suite applications provide console interface that allows +to select options for barcode generation and detection, face detection, +recognition and tracking, image recognition and tracking. Source codes of the +testsuites are located in corresponding subdirectories of the test directory in +the capi-media-vision project root: +test/testsuites/barcode +test/testsuites/face +test/testsuites/image diff --git a/capi-media-vision.manifest b/capi-media-vision.manifest new file mode 100644 index 0000000..86dbb26 --- /dev/null +++ b/capi-media-vision.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/capi-media-vision.pc.in b/capi-media-vision.pc.in new file mode 100644 index 0000000..cde0c80 --- /dev/null +++ b/capi-media-vision.pc.in @@ -0,0 +1,14 @@ + +# Package Information for pkg-config + +prefix=@PREFIX@ +exec_prefix=/usr +libdir=@LIB_INSTALL_DIR@ +includedir=/usr/include/media + +Name: @PC_NAME@ +Description: @PACKAGE_DESCRIPTION@ +Version: @VERSION@ +Requires: @PC_REQUIRED@ +Libs: -L${libdir} @PC_LDFLAGS@ +Cflags: -I${includedir} diff --git a/doc/mediavision_doc.h b/doc/mediavision_doc.h new file mode 100644 index 0000000..b7ab18d --- /dev/null +++ b/doc/mediavision_doc.h @@ -0,0 +1,252 @@ +/* + * 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_DOC_H__ +#define __TIZEN_MEDIAVISION_DOC_H__ + +/** + * @ingroup CAPI_MEDIA_FRAMEWORK + * @defgroup CAPI_MEDIA_VISION_MODULE Media Vision + * @brief Media Vision library providing following functionality:\n + * * Face detection, recognition, and tracking;\n + * * Barcode detection and generation;\n + * * Flat Image detection, recognition and tracking;\n + * * Flat Image features extraction. + * + * @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_BARCODE_MODULE submodules. + * @section CAPI_MEDIA_VISION_COMMON_MODULE_HEADER Required Header + * \#include + * + * @section CAPI_MEDIA_VISION_COMMON_MODULE_OVERVIEW Overview + * @ref CAPI_MEDIA_VISION_COMMON_MODULE provides a set of functions that + * are used in Media Vision API to correctly prepare and use included modules. + * @ref mv_source_h is the handler that has to be created to keep information + * on image or video frame data as row buffer. It can be created based on + * the media data stored in memory or using the @ref media_packet_h handler. + * @ref mv_source_h supported by the set of getters which allow to retrieve + * such image parameters as its size or colorspace (see @ref mv_colorspace_e + * enumeration). The handler is usually used as parameter for functions + * performing computer vision tasks on the image data.\n + * @ref mv_engine_config_h is the handler which provides dictionary + * functionality. It means that it is possible to set (key, value) pairs to + * the @ref mv_engine_config_h handlers and use them to transfer these values + * to the engine part underlying Media Vision API. Information on which + * attributes can be set is provided together with particular engines. + * + * @section CAPI_MEDIA_VISION_COMMON_MODULE_FEATURE Related Features + * This API is related with the following features:\n + * - http://tizen.org/feature/vision.barcode_detection\n + * - http://tizen.org/feature/vision.barcode_generation\n + * - http://tizen.org/feature/vision.face_recognition\n + * - http://tizen.org/feature/vision.image_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 + * + * Feature Element. + * + * + * @defgroup CAPI_MEDIA_VISION_FACE_MODULE Media Vision Face + * @ingroup CAPI_MEDIA_VISION_MODULE + * @brief Face detection, recognition, and tracking. + * @section CAPI_MEDIA_VISION_FACE_MODULE_HEADER Required Header + * \#include + * + * @section CAPI_MEDIA_VISION_FACE_MODULE_OVERVIEW Overview + * + * @section CAPI_MEDIA_VISION_FACE_MODULE_FEATURE Related Features + * This API is related with the following features:\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 + * + * Feature Element. + * + * + * @ref CAPI_MEDIA_VISION_FACE_MODULE contains @ref mv_face_detect() function + * to detect faces on @ref mv_source_h, and @ref mv_face_detected_cb callback + * to process detected faces. Also it contains @ref mv_face_recognize() function + * which performs face recognition on @ref mv_source_h for recognition model + * @ref mv_face_recognition_model_h handle. Results of the recognition will be + * passed to the @ref mv_face_recognized_cb. Results of the recognition consist + * of unique face label and confidence of the recognition model that face was + * recognized correctly. Unique face label is the integer identifier should be + * introduced to the model before starting recognition, when learning examples + * are added (see @ref mv_face_recognition_model_add() function + * documentation for details about unique face labels).\n + * Recognition model should be created with + * @ref mv_face_recognition_model_create() and destroyed with + * @ref mv_face_recognition_model_destroy(). Model can be cloned with + * @ref mv_face_recognition_model_clone(), saved to the file with + * @ref mv_face_recognition_model_save(), loaded with + * @ref mv_face_recognition_model_load(). Model learning can be provided with + * @ref mv_face_recognition_model_add(), and + * @ref mv_face_recognition_model_learn() functions. These two methods has to be + * called in the direct order: first, labeled face examples should be added to + * the model using @ref mv_face_recognition_model_add(). It is + * expected that images of the same face will be added specifying the same face + * label. When examples were added, model has to be learned based on the collected + * set of labeled face images. @ref mv_face_recognition_model_learn() function + * will perform learning. If it is required to get the list of unique face + * labels learned by the model, @ref mv_face_recognition_model_query_labels() + * function can be used.\n + * Module contains function + * @ref mv_face_track() which performs tracking on @ref mv_source_h for + * @ref mv_face_tracking_model_h and @ref mv_face_on_tracked_cb which process + * tracked face. Tracking model should be created with + * @ref mv_face_tracking_model_create() and destroyed with + * @ref mv_face_tracking_model_destroy(). Tracking model should be prepared + * with @ref mv_face_tracking_model_prepare() before each session of tracking. + * Model can be cloned with @ref mv_face_tracking_model_clone(), saved to the + * file with @ref mv_face_tracking_model_save(), loaded with + * @ref mv_face_tracking_model_load().\n + * Module provides function for detecting eye-blink status - + * @ref mv_face_eye_condition_recognize(), which provides detection on + * @ref mv_source_h and face location - @ref mv_rectangle_s. Callback + * @ref mv_face_eye_condition_recognized_cb handles result.\n + * Also module contains @ref mv_face_facial_expression_recognize() function which + * detects face expression on @ref mv_source_h, face location is determined by + * @ref mv_rectangle_s. Result is handled with + * @ref mv_face_facial_expression_recognized_cb. + * + * @defgroup CAPI_MEDIA_VISION_IMAGE_MODULE Media Vision Image + * @ingroup CAPI_MEDIA_VISION_MODULE + * @brief Flat Image recognition and tracking;\n + * Flat image features extraction. + * @section CCAPI_MEDIA_VISION_IMAGE_MODULE_HEADER Required Header + * \#include + * + * @section CAPI_MEDIA_VISION_IMAGE_MODULE_OVERVIEW Overview + * + * @section CAPI_MEDIA_VISION_IMAGE_MODULE_FEATURE Related Features + * This API is related with the following features:\n + * - http://tizen.org/feature/vision.image_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 + * + * Feature Element. + * + * + * @ref CAPI_MEDIA_VISION_IMAGE_MODULE contains @ref mv_image_recognize() + * function to recognize images on @ref mv_source_h, and @ref + * mv_image_recognized_cb callback to process recognition result. Module + * also contains @ref mv_image_track() which performs tracking of image on + * sequence of @ref mv_source_h handles (by using method for each @ref + * mv_source_h) and callback @ref mv_image_tracked_cb to process tracking result. + * In order to perform general functionality, module contains @ref + * mv_image_object_h and @ref mv_image_tracking_model_h handles. + * Image object should be created with @ref mv_image_object_create() and + * destroyed with @ref mv_image_object_destroy(). @ref mv_image_object_h can be + * constructed by calling @ref mv_image_object_fill() using image wrapped with + * @ref mv_source_h. Object can be cloned with @ref mv_image_object_clone(), + * saved to the file with @ref mv_image_object_save() and loaded from file with + * @ref mv_image_object_load(). Image object can be evaluated with + * @ref mv_image_object_get_recognition_rate(). + * Tracking model should be created with @ref mv_image_tracking_model_create() + * and destroyed with @ref mv_image_tracking_model_destroy(). Tracking model + * should be based on image object which will be tracked. Use + * @ref mv_image_tracking_model_set_target() to assign @ref mv_image_object_h + * to the corresponding @ref mv_image_tracking_model_h. It can be cloned with + * @ref mv_image_tracking_model_clone(), saved to the file with @ref + * mv_image_tracking_model_save() and loaded from file with @ref + * mv_image_tracking_model_load(). + * + * @defgroup CAPI_MEDIA_VISION_BARCODE_MODULE Media Vision BarCode + * @ingroup CAPI_MEDIA_VISION_MODULE + * @brief Barcode module consists of barcode detection and barcode generation + * submodules. + * @section CAPI_MEDIA_VISION_BARCODE_MODULE_HEADER Required Header + * \#include + * + * @section CAPI_MEDIA_VISION_BARCODE_MODULE_OVERVIEW Overview + * + * @section CAPI_MEDIA_VISION_BARCODE_MODULE_FEATURE Related Features + * This API is related with the following features:\n + * - http://tizen.org/feature/vision.barcode_detection\n + * - http://tizen.org/feature/vision.barcode_generation\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 + * + * Feature Element. + * + * + * @ref CAPI_MEDIA_VISION_BARCODE_MODULE contains two submodules:\n + * * Detection submodule, + * * Generation submodule.\n + * + * Detection submodule can be used for detecting barcodes on image sources, + * reading encoded messages, getting barcode types.\n + * This module contains + * @ref mv_barcode_detect() function and @ref mv_barcode_detected_cb + * callback. @ref mv_barcode_detect() function can be called for the image + * determined by @ref mv_source_h handler to detect barcodes. If barcodes + * were detected, then @ref mv_barcode_detected_cb callback is called. + * Each detected barcode type, message and location can be processed by + * this callback. @ref mv_barcode_detect() supports ROI (rectangular region of + * interest) specification to allow barcode detection only for the region on + * the image. + * + * Generation submodule can be used for generating the barcodes and QR codes. + * Different encoding types (see @ref mv_barcode_qr_mode_e), error correction + * codes (see @ref mv_barcode_qr_ecc_e) and code versions are supported for + * QRCodes.\n This submodule contains @ref mv_barcode_generate_source() function + * to generate handler to the buffer with row image of barcode, and + * @ref mv_barcode_generate_image() function to generate image file with + * barcode. Both functions support the set of parameters which allow API user to + * configure output barcode. QR codes as well as Barcodes are supported + * (see @ref mv_barcode_type_e enumeration for full list of supported barcodes). + * 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). + */ + +#endif /* __TIZEN_MEDIAVISION_DOC_H__ */ diff --git a/include/mv_barcode.h b/include/mv_barcode.h new file mode 100644 index 0000000..00ec447 --- /dev/null +++ b/include/mv_barcode.h @@ -0,0 +1,30 @@ +/** + * 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_BARCODE_H__ +#define __TIZEN_MEDIAVISION_BARCODE_H__ + +#include +#include +#include + +/** + * @file mv_barcode.h + * @brief Representative Media Vision Barcode API header file that includes + * Media Vision Barcode detection and generation functionalities. + */ + +#endif /* __TIZEN_MEDIAVISION_BARCODE_H__ */ diff --git a/include/mv_barcode_detect.h b/include/mv_barcode_detect.h new file mode 100644 index 0000000..77be222 --- /dev/null +++ b/include/mv_barcode_detect.h @@ -0,0 +1,148 @@ +/** + * 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_BARCODE_DETECT_H__ +#define __TIZEN_MEDIAVISION_BARCODE_DETECT_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file mv_barcode_detect.h + * @brief This file contains the Media Vision barcode detect API. + */ + +/** + * @addtogroup CAPI_MEDIA_VISION_BARCODE_MODULE + * @{ + */ + +/** + * @brief Define MV_BARCODE_DETECT_ATTR_MODE to set mode attribute of the engine + * configuration. + * + * @since_tizen 2.4 + * + * @see mv_barcode_detect_attr_mode_e + */ +#define MV_BARCODE_DETECT_ATTR_MODE "MV_BARCODE_DETECT_ATTR_MODE" /**< Mode: 0-image, 1-video*/ + +/** + * @brief Define MV_BARCODE_DETECT_ATTR_TARGET to set target attribute of the + * engine configuration. + * + * @since_tizen 2.4 + * + * @see mv_barcode_detect_attr_target_e + */ +#define MV_BARCODE_DETECT_ATTR_TARGET "MV_BARCODE_DETECT_ATTR_TARGET" /**< Target: 0-all, 1-1D, 2-2D*/ + +/** + * @brief Enumeration to mode attribute. + * + * @since_tizen 2.4 + */ +typedef enum +{ + MV_BARCODE_DETECT_ATTR_MODE_IMAGE, /**< Still image */ + MV_BARCODE_DETECT_ATTR_MODE_VIDEO /**< Continuous video */ +} mv_barcode_detect_attr_mode_e; + +/** + * @brief Enumeration to target attribute. + * + * @since_tizen 2.4 + */ +typedef enum +{ + MV_BARCODE_DETECT_ATTR_TARGET_ALL, /**< 1D and 2D */ + MV_BARCODE_DETECT_ATTR_TARGET_1D_BARCODE, /**< 1D barcode only */ + MV_BARCODE_DETECT_ATTR_TARGET_2D_BARCODE, /**< 2D barcode only */ +} mv_barcode_detect_attr_target_e; + +/** + * @brief Called when barcode detection is completed. + * @details If no barcode is detected then the method will be called, barcodes + * and states will be equal to NULL, and @a number_of_barcodes - 0. + * + * @since_tizen 2.4 + * @param [in] source The handle to the media source + * @param [in] engine_cfg The handle to the configuration of the engine + * @param [in] barcode_locations The quadrangle locations of detected barcodes + * @param [in] messages The decoded messages of barcodes + * @param [in] types The types of detected barcodes + * @param [in] number_of_barcodes The number of detected barcodes + * @param [in] user_data The user data passed from + * the mv_barcode_detect() function + * + * @pre mv_barcode_detect() invokes this callback + * + * @see mv_barcode_detect() + */ +typedef void (*mv_barcode_detected_cb)( + mv_source_h source, + mv_engine_config_h engine_cfg, + const mv_quadrangle_s *barcode_locations, + const char* messages[], + const mv_barcode_type_e *types, + int number_of_barcodes, + void *user_data); + +/** + * @brief Detects barcode(s) on source and reads message from it. + * + * @since_tizen 2.4 + * @param [in] source The media source handle + * @param [in] engine_cfg The handle to the configuration of the engine + * @param [in] roi Region of interest - rectangular area on the + * @a source which will be used for barcode detection + * Note that @a roi should be inside area on the + * @a source. + * @param [in] detect_cb The callback for result handling + * @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 + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Not supported format + * @retval #MEDIA_VISION_ERROR_INTERNAL Internal error + * + * @pre Create a source handle by calling @ref mv_create_source() + * @pre Create an engine configuration handle by calling + * @ref mv_create_engine_config(), otherwise use NULL + * + * @see mv_barcode_detected_cb() + */ +int mv_barcode_detect( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s roi, + mv_barcode_detected_cb detect_cb, + void *user_data); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIAVISION_BARCODE_DETECT_H__ */ diff --git a/include/mv_barcode_generate.h b/include/mv_barcode_generate.h new file mode 100644 index 0000000..6d82709 --- /dev/null +++ b/include/mv_barcode_generate.h @@ -0,0 +1,142 @@ +/** + * 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_BARCODE_GENERATE_H__ +#define __TIZEN_MEDIAVISION_BARCODE_GENERATE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file mv_barcode_generate.h + * @brief This file contains the Media Vision barcode generate API. + */ + +/** + * @addtogroup CAPI_MEDIA_VISION_BARCODE_MODULE + * @{ + */ + +/** + * @brief Generates @ref mv_source_h with barcode image. + * @details Pay attention that for EAN-8 and EAN-13 barcode types the barcode + * type may be selected automatically and this selection depends on the input + * message length. Also for QR codes the version may be selected as minimum + * required to generate QR code with the input message length. + * + * @since_tizen 2.4 + * @param [in] engine_cfg The handle to the configuration of the engine + * @param [in] message The message to be encoded in the barcode + * @param [in] type Type of the barcode to be generated + * @param [in] qr_enc_mode Encoding mode for the message (only for QR codes; + * for 1D barcodes set this parameter to + * @a MV_BARCODE_QR_MODE_UNAVAILABLE) + * @param [in] qr_ecc Error correction level (only for QR codes; for + * 1D barcodes set this parameter to + * @a MV_BARCODE_QR_ECC_UNAVAILABLE) + * @param [in] qr_version QR code version (for 1D barcodes set this + * parameter to 0) + * @param [in, out] image The media source handle which will be used to + * fill by the buffer with generated image + * @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_MSG_TOO_LONG Too long or short message + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * @retval #MEDIA_VISION_ERROR_INVALID_DATA Invalid data + * @retval #MEDIA_VISION_ERROR_INTERNAL Internal error + * + * @pre Create an engine configuration handle by calling + * @ref mv_create_engine_config(), otherwise use NULL + * + * @see mv_barcode_generate_image() + */ +int mv_barcode_generate_source( + mv_engine_config_h engine_cfg, + const char *message, + mv_barcode_type_e type, + mv_barcode_qr_mode_e qr_enc_mode, + mv_barcode_qr_ecc_e qr_ecc, + int qr_version, + mv_source_h image); + +/** + * @brief Generates image file with barcode. + * @details Pay attention that for EAN-8 and EAN-13 barcode types the barcode + * type may be selected automatically and this selection depends on the input + * message length. Also for QR codes the version may be selected as minimum + * required to generate QR code with the input message length. + * + * @since_tizen 2.4 + * @remarks The mediastorage privilege http://tizen.org/privilege/mediastorage is needed \n + if @a image_path is relevant to media storage.\n + The externalstorage privilege http://tizen.org/privilege/externalstorage is needed \n + if @a image_path is relevant to external storage. + * @param [in] engine_cfg The handle to the configuration of the engine + * @param [in] message The message to be encoded in the barcode + * @param [in] image_width The width of the generated image + * @param [in] image_height The height of the generated image + * @param [in] type Type of the barcode to be generated + * @param [in] qr_enc_mode Encoding mode for the message (only for QR codes; + * for 1D barcodes set this parameter to + * @a MV_BARCODE_QR_MODE_UNAVAILABLE) + * @param [in] qr_ecc Error correction level (only for QR codes; for + * 1D barcodes set this parameter to + * @a MV_BARCODE_QR_ECC_UNAVAILABLE) + * @param [in] qr_version QR code version (for 1D barcodes set this + * parameter to 0) + * @param [in] image_path The path to the file that has to be generated + * @param [in] image_format The format of the output image + * @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_MSG_TOO_LONG Too long or short message + * @retval #MEDIA_VISION_ERROR_PERMISSION_DENIED Permission denied + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * @retval #MEDIA_VISION_ERROR_INVALID_DATA Invalid data + * @retval #MEDIA_VISION_ERROR_INVALID_PATH Invalid path + * @retval #MEDIA_VISION_ERROR_INTERNAL Internal error + * + * @pre Create an engine configuration handle by calling + * @ref mv_create_engine_config(), otherwise use NULL + * + * @see mv_barcode_generate_source() + */ +int mv_barcode_generate_image( + mv_engine_config_h engine_cfg, + const char *message, + int image_width, + int image_height, + mv_barcode_type_e type, + mv_barcode_qr_mode_e qr_enc_mode, + mv_barcode_qr_ecc_e qr_ecc, + int qr_version, + const char *image_path, + mv_barcode_image_format_e image_format); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIAVISION_BARCODE_GENERATE_H__ */ diff --git a/include/mv_barcode_type.h b/include/mv_barcode_type.h new file mode 100644 index 0000000..d8b2e74 --- /dev/null +++ b/include/mv_barcode_type.h @@ -0,0 +1,105 @@ +/** + * 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_BARCODE_TYPE_H__ +#define __TIZEN_MEDIAVISION_BARCODE_TYPE_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file mv_barcode_type.h + * @brief This file contains enumerations required by barcode detect/generate API. + */ + +/** + * @addtogroup CAPI_MEDIA_VISION_BARCODE_MODULE + * @{ + */ + +/** + * @brief Enumeration for supported barcode types. + * @details QR codes (versions 1 to 40) and set of 1D barcodes are supported + * + * @since_tizen 2.4 + */ +typedef enum +{ + MV_BARCODE_QR, /**< 2D barcode - Quick Response code */ + MV_BARCODE_UPC_A, /**< 1D barcode - Universal Product Code with 12-digit */ + MV_BARCODE_UPC_E, /**< 1D barcode - Universal Product Code with 6-digit */ + MV_BARCODE_EAN_8, /**< 1D barcode - International Article Number with 8-digit */ + MV_BARCODE_EAN_13, /**< 1D barcode - International Article Number with 13-digit */ + MV_BARCODE_CODE128, /**< 1D barcode - Code 128 */ + MV_BARCODE_CODE39, /**< 1D barcode - Code 39 */ + MV_BARCODE_I2_5, /**< 1D barcode - Interleaved Two of Five */ + MV_BARCODE_UNDEFINED /**< Undefined */ +} mv_barcode_type_e; + +/** + * @brief Enumeration for supported QR code error correction level. + * + * @since_tizen 2.4 + * @remarks This is unavailable for 1D barcodes + */ +typedef enum +{ + MV_BARCODE_QR_ECC_LOW, /**< Recovery up to 7% losses */ + MV_BARCODE_QR_ECC_MEDIUM, /**< Recovery up to 15% losses */ + MV_BARCODE_QR_ECC_QUARTILE, /**< Recovery up to 25% losses */ + MV_BARCODE_QR_ECC_HIGH, /**< Recovery up to 30% losses */ + MV_BARCODE_QR_ECC_UNAVAILABLE /**< Unavailable */ +} mv_barcode_qr_ecc_e; + +/** + * @brief Enumeration for supported QR code encoding mode. + * + * @since_tizen 2.4 + * @remarks This is unavailable for 1D barcodes + */ +typedef enum +{ + MV_BARCODE_QR_MODE_NUMERIC, /**< Numeric digits */ + MV_BARCODE_QR_MODE_ALPHANUMERIC, /**< Alphanumeric characters */ + MV_BARCODE_QR_MODE_BYTE, /**< Raw 8-bit bytes */ + MV_BARCODE_QR_MODE_UTF8, /**< UTF-8 character encoding */ + MV_BARCODE_QR_MODE_UNAVAILABLE /**< Unavailable */ +} mv_barcode_qr_mode_e; + +/** + * @brief Enumeration for supported image formats for the barcode generating. + * + * @since_tizen 2.4 + */ +typedef enum +{ + MV_BARCODE_IMAGE_FORMAT_UNAVAILABLE = -1, /** Unavailable image format */ + MV_BARCODE_IMAGE_FORMAT_BMP, /**< BMP image format */ + MV_BARCODE_IMAGE_FORMAT_JPG, /**< JPEG image format */ + MV_BARCODE_IMAGE_FORMAT_PNG, /**< PNG image format */ + MV_BARCODE_IMAGE_FORMAT_NUM, /**< The number of supported image format */ +} mv_barcode_image_format_e; + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIAVISION_BARCODE_TYPE_H__ */ diff --git a/include/mv_common.h b/include/mv_common.h new file mode 100644 index 0000000..ff3a5e5 --- /dev/null +++ b/include/mv_common.h @@ -0,0 +1,684 @@ +/** + * 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_COMMON_H__ +#define __TIZEN_MEDIAVISION_COMMON_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file mv_common.h + * @brief This file contains the Media Vision Common API. + */ + +/** + * @addtogroup CAPI_MEDIA_VISION_COMMON_MODULE + * @{ + */ + +/** + * @brief Point in 2D space. + * + * @since_tizen 2.4 + */ +typedef struct +{ + int x; /**< X-axis coordinate of the point in 2D space */ + int y; /**< Y-axis coordinate of the point in 2D space */ +} mv_point_s; + +/** + * @brief Location of the object bounded by quadrangle defined by four 2D points. + * + * @since_tizen 2.4 + */ +typedef struct +{ + mv_point_s points[4]; /**< Four points that define object bounding + quadrangle */ +} mv_quadrangle_s; + +/** + * @brief Location of the object bounded by rectangle defined by + * coordinates of top left corner, width and height. + * + * @since_tizen 2.4 + */ +typedef struct +{ + mv_point_s point; /**< Top left corner of rectangle coordinates */ + int width; /**< Width of the bounding rectangle */ + int height; /**< Height of the bounding rectangle */ +} mv_rectangle_s; + +/** + * @brief Enumeration for Media Vision error. + * + * @since_tizen 2.4 + */ +typedef enum +{ + MEDIA_VISION_ERROR_NONE + = TIZEN_ERROR_NONE, /**< Successful */ + MEDIA_VISION_ERROR_NOT_SUPPORTED + = TIZEN_ERROR_NOT_SUPPORTED, /**< Not supported */ + MEDIA_VISION_ERROR_MSG_TOO_LONG + = TIZEN_ERROR_MSG_TOO_LONG, /**< Message too long */ + MEDIA_VISION_ERROR_NO_DATA + = TIZEN_ERROR_NO_DATA, /**< No data */ + MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE + = TIZEN_ERROR_KEY_NOT_AVAILABLE, /**< Key not available */ + MEDIA_VISION_ERROR_OUT_OF_MEMORY + = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */ + MEDIA_VISION_ERROR_INVALID_PARAMETER + = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */ + MEDIA_VISION_ERROR_INVALID_OPERATION + = TIZEN_ERROR_INVALID_OPERATION, /**< Invalid operation */ + MEDIA_VISION_ERROR_PERMISSION_DENIED + = TIZEN_ERROR_NOT_PERMITTED, /**< Not permitted */ + MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT + = TIZEN_ERROR_MEDIA_VISION | 0x01, /**< Not supported format */ + MEDIA_VISION_ERROR_INTERNAL + = TIZEN_ERROR_MEDIA_VISION | 0x02, /**< Internal error */ + MEDIA_VISION_ERROR_INVALID_DATA + = TIZEN_ERROR_MEDIA_VISION | 0x03, /**< Invalid data */ + MEDIA_VISION_ERROR_INVALID_PATH + = TIZEN_ERROR_MEDIA_VISION | 0x04, /**< Invalid path (Since 3.0) */ +} mv_error_e; + +/** + * @brief Enumeration for Media Vision @ref mv_engine_config_h handle attribute + * type. + * + * @since_tizen 2.4 + */ +typedef enum +{ + MV_ENGINE_CONFIG_ATTR_TYPE_DOUBLE, /**< Double attribute type */ + MV_ENGINE_CONFIG_ATTR_TYPE_INTEGER, /**< Integer attribute type */ + MV_ENGINE_CONFIG_ATTR_TYPE_BOOLEAN, /**< Boolean attribute type */ + MV_ENGINE_CONFIG_ATTR_TYPE_STRING /**< String attribute type */ +} mv_config_attribute_type_e; + +/** + * @brief Enumeration for Media Vision colorspace. + * + * @since_tizen 2.4 + */ +typedef enum +{ + MEDIA_VISION_COLORSPACE_INVALID, /**< The colorspace type is invalid */ + MEDIA_VISION_COLORSPACE_Y800, /**< The colorspace type is Y800 */ + MEDIA_VISION_COLORSPACE_I420, /**< The colorspace type is I420 */ + MEDIA_VISION_COLORSPACE_NV12, /**< The colorspace type is NV12 */ + MEDIA_VISION_COLORSPACE_YV12, /**< The colorspace type is YV12 */ + MEDIA_VISION_COLORSPACE_NV21, /**< The colorspace type is NV21 */ + MEDIA_VISION_COLORSPACE_YUYV, /**< The colorspace type is YUYV */ + MEDIA_VISION_COLORSPACE_UYVY, /**< The colorspace type is UYVY */ + MEDIA_VISION_COLORSPACE_422P, /**< The colorspace type is 422P */ + MEDIA_VISION_COLORSPACE_RGB565, /**< The colorspace type is RGB565 */ + MEDIA_VISION_COLORSPACE_RGB888, /**< The colorspace type is RGB888 */ + MEDIA_VISION_COLORSPACE_RGBA, /**< The colorspace type is RGBA */ +} mv_colorspace_e; + +/** + * @brief The handle to the Media Vision API engine algorithms configuration. + * @details Configuration is a dictionary consists of key and value pairs to + * collect engine-specific settings and allow Media Vision module to + * access them internally. Engine configuration provides developer by + * the possibility to make computer vision algorithms work better + * in particular conditions of API usage. To create engine + * configuration handle @ref mv_create_engine_config() function has to + * be used. When configuration is not needed any more, it is required to + * destroy it and release resources by @ref mv_destroy_engine_config() + * function. + * + * @since_tizen 2.4 + * + * @see mv_create_engine_config() + * @see mv_destroy_engine_config() + */ +typedef void *mv_engine_config_h; + +/** + * @brief The handle to the source. + * + * @since_tizen 2.4 + */ +typedef void *mv_source_h; + +/** + * @brief Creates a source handle. + * + * @since_tizen 2.4 + * @remarks You must release @a source by using @ref mv_destroy_source(). + * @param [out] source A new handle to the 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 + * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @see mv_destroy_source() + */ +int mv_create_source( + mv_source_h *source); + +/** + * @brief Destroys the source handle and releases all its resources. + * + * @since_tizen 2.4 + * @param [in] source The handle to the source 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_create_source() + */ +int mv_destroy_source( + mv_source_h source); + +/** + * @brief Fills the media source based on the media packet. + * + * @since_tizen 2.4 + * @param [in,out] source The handle to the source + * @param [in] media_packet The handle to the media packet from which + * will be filled the 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 + * @retval #MEDIA_VISION_ERROR_INVALID_OPERATION Invalid operation + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Not supported format + * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create a source handle by calling @ref mv_create_source() + * + * @see mv_create_source() + * @see mv_destroy_source() + */ +int mv_source_fill_by_media_packet( + mv_source_h source, + media_packet_h media_packet); + +/** + * @brief Fills the media source based on the buffer and metadata. + * + * @since_tizen 2.4 + * @param [in,out] source The handle to the source + * @param [in] data_buffer The buffer of image data + * @param [in] buffer_size The buffer size + * @param [in] image_width The width of image data + * @param [in] image_height The height of image data + * @param [in] image_colorspace The image colorspace + * @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 + * + * @pre Create a source handle by calling @ref mv_create_source() + * + * @see mv_source_clear() + */ +int mv_source_fill_by_buffer( + mv_source_h source, + unsigned char *data_buffer, + unsigned int buffer_size, + unsigned int image_width, + unsigned int image_height, + mv_colorspace_e image_colorspace); + +/** + * @brief Clears the buffer of the media source. + * + * @since_tizen 2.4 + * @param [in,out] source The handle to the 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 + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @see mv_source_fill_by_buffer() + */ +int mv_source_clear( + mv_source_h source); + +/** + * @brief Gets buffer of the media source. + * + * @since_tizen 2.4 + * @remarks Note that the retrieved buffer will be destroyed when + * @ref mv_destroy_source() or @ref mv_source_clear() function + * is called for the @a source. + * + * @param [in] source The handle to the source + * @param [out] data_buffer The buffer of the source + * @param [out] buffer_size The size of 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 + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @see mv_source_get_width() + * @see mv_source_get_height() + * @see mv_source_get_colorspace() + */ +int mv_source_get_buffer( + mv_source_h source, + unsigned char **data_buffer, + unsigned int *buffer_size); + +/** + * @brief Gets height of the media source. + * + * @since_tizen 2.4 + * @param [in] source The handle to the source + * @param [out] image_height The height of an image in the 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 + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @see mv_source_get_width() + * @see mv_source_get_colorspace() + * @see mv_source_get_buffer() + */ +int mv_source_get_height( + mv_source_h source, + unsigned int *image_height); + +/** + * @brief Gets width of the media source. + * + * @since_tizen 2.4 + * @param [in] source The handle to the source + * @param [out] image_width The width of an image in the 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 + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @see mv_source_get_height() + * @see mv_source_get_colorspace() + * @see mv_source_get_buffer() + */ +int mv_source_get_width( + mv_source_h source, + unsigned int *image_width); + +/** + * @brief Gets colorspace of the media source. + * + * @since_tizen 2.4 + * @param [in] source The handle to the source + * @param [out] image_colorspace The colorspace of an image in the 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 + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @see mv_source_get_width() + * @see mv_source_get_height() + * @see mv_source_get_buffer() + */ +int mv_source_get_colorspace( + mv_source_h source, + mv_colorspace_e *image_colorspace); + +/** + * @brief Creates the handle to the configuration of engine. + * + * @since_tizen 2.4 + * @remarks Available engine configuration attributes can be get by using + * @ref mv_engine_config_foreach_supported_attribute(). + * The attributes can be changed by @ref mv_engine_config_h + * related setters. Default values are used if the attributes + * are not changed. + * @param [out] engine_cfg The handle to the engine to be created + * @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_engine_config_h + * @see mv_destroy_engine_config() + * @see mv_engine_config_set_double_attribute() + * @see mv_engine_config_set_int_attribute() + * @see mv_engine_config_set_bool_attribute() + * @see mv_engine_config_set_string_attribute() + * @see mv_engine_config_get_double_attribute() + * @see mv_engine_config_get_int_attribute() + * @see mv_engine_config_get_bool_attribute() + * @see mv_engine_config_get_string_attribute() + */ +int mv_create_engine_config( + mv_engine_config_h *engine_cfg); + +/** + * @brief Destroys the engine configuration handle and releases all its + * resources. + * + * @since_tizen 2.4 + * @param [in] engine_cfg The handle to the engine configuration + * 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_engine_config_h + * @see mv_create_engine_config() + */ +int mv_destroy_engine_config( + mv_engine_config_h engine_cfg); + +/** + * @brief Sets the double attribute to the configuration. + * + * @since_tizen 2.4 + * @param [in] engine_cfg Engine configuration for which @a value has + * to be set + * @param [in] name String key of the attribute will be used for + * storing the @a value into configuration + * dictionary + * @param [in] value The double value of the attribute + * @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_KEY_NOT_AVAILABLE Attribute key isn't available + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @see mv_engine_config_get_double_attribute() + * @see mv_engine_config_set_int_attribute() + * @see mv_engine_config_set_bool_attribute() + * @see mv_engine_config_set_string_attribute() + */ +int mv_engine_config_set_double_attribute( + mv_engine_config_h engine_cfg, + const char *name, + double value); + +/** + * @brief Sets the integer attribute to the configuration. + * + * @since_tizen 2.4 + * @param [in] engine_cfg Engine configuration for which @a value has + * to be set + * @param [in] name String key of the attribute will be used for + * storing the @a value into configuration + * dictionary + * @param [in] value The integer value of the attribute + * @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_KEY_NOT_AVAILABLE Attribute key isn't available + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @see mv_engine_config_get_int_attribute() + * @see mv_engine_config_set_double_attribute() + * @see mv_engine_config_set_bool_attribute() + * @see mv_engine_config_set_string_attribute() + * @see mv_barcode_detect_attr_mode_e + * @see mv_barcode_detect_attr_target_e + */ +int mv_engine_config_set_int_attribute( + mv_engine_config_h engine_cfg, + const char *name, + int value); + +/** + * @brief Sets the boolean attribute to the configuration. + * + * @since_tizen 2.4 + * @param [in] engine_cfg Engine configuration for which @a value has + * to be set + * @param [in] name String key of the attribute will be used for + * storing the @a value into configuration + * dictionary + * @param [in] value The boolean value of the attribute + * @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_KEY_NOT_AVAILABLE Attribute key isn't available + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @see mv_engine_config_get_bool_attribute() + * @see mv_engine_config_set_double_attribute() + * @see mv_engine_config_set_int_attribute() + * @see mv_engine_config_set_string_attribute() + */ +int mv_engine_config_set_bool_attribute( + mv_engine_config_h engine_cfg, + const char *name, + bool value); + +/** + * @brief Sets the string attribute to the configuration. + * + * @since_tizen 2.4 + * @param [in] engine_cfg Engine configuration for which @a value has + * to be set + * @param [in] name String key of the attribute will be used for + * storing the @a value into configuration + * dictionary + * @param [in] value The string value of the attribute + * @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_KEY_NOT_AVAILABLE Attribute key isn't available + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @see mv_engine_config_get_string_attribute() + * @see mv_engine_config_set_double_attribute() + * @see mv_engine_config_set_int_attribute() + * @see mv_engine_config_set_bool_attribute() + */ +int mv_engine_config_set_string_attribute( + mv_engine_config_h engine_cfg, + const char *name, + const char *value); + +/** + * @brief Gets the double attribute from the configuration dictionary. + * + * @since_tizen 2.4 + * @param [in] engine_cfg Engine configuration from which @a value + * has to be gotten + * @param [in] name String key of the attribute will be used for + * getting the @a value from the + * configuration dictionary + * @param [out] value The attribute to be filled with double value + * from dictionary + * @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_KEY_NOT_AVAILABLE Attribute key isn't available + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @see mv_engine_config_set_double_attribute() + * @see mv_engine_config_get_int_attribute() + * @see mv_engine_config_get_bool_attribute() + * @see mv_engine_config_get_string_attribute() + */ +int mv_engine_config_get_double_attribute( + mv_engine_config_h engine_cfg, + const char *name, + double *value); + +/** + * @brief Gets the integer attribute from the configuration dictionary. + * + * @since_tizen 2.4 + * @param [in] engine_cfg Engine configuration from which @a value + * has to be gotten + * @param [in] name String key of the attribute will be used for + * getting the @a value from the + * configuration dictionary + * @param [out] value The attribute to be filled with integer value + * from dictionary + * @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_KEY_NOT_AVAILABLE Attribute key isn't available + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @see mv_engine_config_set_int_attribute() + * @see mv_engine_config_get_double_attribute() + * @see mv_engine_config_get_bool_attribute() + * @see mv_engine_config_get_string_attribute() + * @see mv_barcode_detect_attr_mode_e + * @see mv_barcode_detect_attr_target_e + */ +int mv_engine_config_get_int_attribute( + mv_engine_config_h engine_cfg, + const char *name, + int *value); + +/** + * @brief Gets the boolean attribute from the configuration dictionary. + * + * @since_tizen 2.4 + * @param [in] engine_cfg Engine configuration from which @a value + * has to be gotten + * @param [in] name String key of the attribute will be used for + * getting the @a value from the + * configuration dictionary + * @param [out] value The attribute to be filled with boolean value + * from dictionary + * @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_KEY_NOT_AVAILABLE Attribute key isn't available + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @see mv_engine_config_set_bool_attribute() + * @see mv_engine_config_get_double_attribute() + * @see mv_engine_config_get_int_attribute() + * @see mv_engine_config_get_string_attribute() + */ +int mv_engine_config_get_bool_attribute( + mv_engine_config_h engine_cfg, + const char *name, + bool *value); + +/** + * @brief Gets the string attribute from the configuration dictionary. + * + * @since_tizen 2.4 + * @remarks Function allocates memory required for output @a value, so + * it has to be removed by the user himself. + * @param [in] engine_cfg Engine configuration from which @a value + * has to be gotten + * @param [in] name String key of the attribute will be used for + * getting the @a value from the + * configuration dictionary + * @param [out] value The attribute to be filled with string value + * from dictionary + * @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_KEY_NOT_AVAILABLE Attribute key isn't available + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @see mv_engine_config_set_string_attribute() + * @see mv_engine_config_get_double_attribute() + * @see mv_engine_config_get_int_attribute() + * @see mv_engine_config_get_bool_attribute() + */ +int mv_engine_config_get_string_attribute( + mv_engine_config_h engine_cfg, + const char *name, + char **value); + +/** + * @brief Called to get information (type and name) once for each supported + * attribute. + * + * @since_tizen 2.4 + * @param [in] attribute_type The supported attribute type + * @param [in] attribute_name The supported attribute name + * @param [in] user_data The user data passed from the + * @ref mv_engine_config_foreach_supported_attribute() + * 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_engine_config_foreach_supported_attribute() will invoke this callback + * @see mv_engine_config_foreach_supported_attribute() + */ +typedef bool (*mv_supported_attribute_cb)( + mv_config_attribute_type_e attribute_type, + const char *attribute_name, + void *user_data); + +/** + * @brief Traverses the list of supported attribute names and types. + * @details Using this function names of supported attributes can be obtained. + * Names of the attributes can be used with @ref mv_engine_config_h + * related getters and setters to get/set appropriate attribute values. + * + * @since_tizen 2.4 + * @remarks If @a callback is called zero times after + * @ref mv_engine_config_foreach_supported_attribute() call, then + * engine configuration is not supported and setting of attributes will + * cause no effect. In this case for all Media Vision functions which + * require @ref mv_engine_config_h handle as in parameter this + * parameter can be set NULL. + * @remarks If @a callback is called at least once, then attribute names and + * types obtained in the @ref mv_supported_attribute_cb callback can be + * changed after mv_engine_config_h handle creation (with + * @ref mv_create_engine_config() function) by corresponding setters. + * Although, if attributes aren't changed by setters, then default + * values will be used.\n + * Changing of attribute values will affect internal functionality + * provided by concrete library underlying Media Vision API. + * @param [in] callback The iteration callback function + * @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_NO_DATA Can't determine list of supported attributes + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @see mv_engine_config_set_double_attribute() + * @see mv_engine_config_set_int_attribute() + * @see mv_engine_config_set_bool_attribute() + * @see mv_engine_config_set_string_attribute() + * @see mv_engine_config_get_double_attribute() + * @see mv_engine_config_get_int_attribute() + * @see mv_engine_config_get_bool_attribute() + * @see mv_engine_config_get_string_attribute() + */ +int mv_engine_config_foreach_supported_attribute( + mv_supported_attribute_cb callback, + void *user_data); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIAVISION_COMMON_H__ */ diff --git a/include/mv_face.h b/include/mv_face.h new file mode 100644 index 0000000..2b6d235 --- /dev/null +++ b/include/mv_face.h @@ -0,0 +1,1105 @@ +/** + * 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_FACE_H__ +#define __TIZEN_MEDIAVISION_FACE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file mv_face.h + * @brief This file contains the Media Vision Face API. + */ + +/** + * @addtogroup CAPI_MEDIA_VISION_FACE_MODULE + * @{ + */ + +/** + * @brief Defines MV_FACE_DETECTION_MODEL_FILE_PATH to set face detection + * haarcascade xml file attribute of the engine configuration. + * @details Face detection haarcascade model can be changed to specify the path to the file + * + * @since_tizen 3.0 + * @see mv_engine_config_set_string_attribute() + * @see mv_engine_config_get_string_attribute() + */ +#define MV_FACE_DETECTION_MODEL_FILE_PATH "MV_FACE_DETECTION_MODEL_FILE_PATH" + +/** + * @brief Defines MV_FACE_RECOGNITION_MODEL_TYPE to set the method used + * for face recognition model learning attribute of the engine + * configuration. + * @details Switches between three types of methods used for + * face recognition model learning. Possible values of the + * attribute are: + * 1 - Eigenfaces, + * 2 - Fisherfaces, + * 3 - Local Binary Patterns Histograms (LBPH) + * Default type is LBPH + * + * @since_tizen 3.0 + * @see mv_engine_config_set_int_attribute() + * @see mv_engine_config_get_int_attribute() + */ +#define MV_FACE_RECOGNITION_MODEL_TYPE "MV_FACE_RECOGNITION_MODEL_TYPE" + +/** + * @brief Define MV_FACE_DETECTION_ROI_X to set X coordinate of face detection + * roi as attribute of the engine configuration. + * @details Default value is -1 (the roi will be a full image) can be changed + * to specify the roi for face detection + * + * @since_tizen 3.0 + * @see mv_engine_config_set_int_attribute() + * @see mv_engine_config_get_int_attribute() + */ +#define MV_FACE_DETECTION_ROI_X "MV_FACE_DETECTION_ROI_X" + +/** + * @brief Define MV_FACE_DETECTION_ROI_Y to set Y coordinate of face detection + * roi as attribute of the engine configuration. + * @details Default value is -1 (the roi will be a full image) can be changed + * to specify the roi for face detection + * + * @since_tizen 3.0 + * @see mv_engine_config_set_int_attribute() + * @see mv_engine_config_get_int_attribute() + */ +#define MV_FACE_DETECTION_ROI_Y "MV_FACE_DETECTION_ROI_Y" + +/** + * @brief Define MV_FACE_DETECTION_ROI_WIDTH to set width of face detection + * roi as attribute of the engine configuration. + * @details Default value is -1 (the roi will be a full image) can be changed + * to specify the roi for face detection + * + * @since_tizen 3.0 + * @see mv_engine_config_set_int_attribute() + * @see mv_engine_config_get_int_attribute() + */ +#define MV_FACE_DETECTION_ROI_WIDTH "MV_FACE_DETECTION_ROI_WIDTH" + +/** + * @brief Define MV_FACE_DETECTION_ROI_HEIGHT to set height of face detection + * roi as attribute of the engine configuration. + * @details Default value is -1 (the roi will be a full image) can be changed + * to specify the roi for face detection + * + * @since_tizen 3.0 + * @see mv_engine_config_set_int_attribute() + * @see mv_engine_config_get_int_attribute() + */ +#define MV_FACE_DETECTION_ROI_HEIGHT "MV_FACE_DETECTION_ROI_HEIGHT" + +/** + * @brief Define MV_FACE_DETECTION_MIN_SIZE_WIDTH to set minimum width of face + * which will be detected as attribute of the engine configuration. + * @details Default value is -1 (all detected faces will be applied) can be + * changed to specify the minimum face width + * + * @since_tizen 3.0 + * @see mv_engine_config_set_int_attribute() + * @see mv_engine_config_get_int_attribute() + */ +#define MV_FACE_DETECTION_MIN_SIZE_WIDTH "MV_FACE_DETECTION_MIN_SIZE_WIDTH" + +/** + * @brief Define MV_FACE_DETECTION_MIN_SIZE_HEIGHT to set minimum height of face + * which will be detected as attribute of the engine configuration. + * @details Default value is -1 (all detected faces will be applied) can be changed + * to specify the minimum face height + * + * @since_tizen 3.0 + * @see mv_engine_config_set_int_attribute() + * @see mv_engine_config_get_int_attribute() + */ +#define MV_FACE_DETECTION_MIN_SIZE_HEIGHT "MV_FACE_DETECTION_MIN_SIZE_HEIGHT" + +/******************/ +/* Face detection */ +/******************/ + +/** + * @brief Called when faces are detected for the @a source. + * @details This type callback can be invoked each time when + * @ref mv_face_detect() is called to process the results of face + * detecting. + * + * @since_tizen 3.0 + * @remarks If no face is detected then the callback will be invoked, but + * @a faces_locations array will be NULL, and @a number_of_faces will + * be equal to 0. + * @param [in] source The handle to the source of the media where + * faces were detected + * @param [in] engine_cfg The handle to the configuration of engine was + * used for face detecting, or NULL if default + * settings were applied + * @param [in] faces_locations Rectangular locations of detected faces + * @param [in] number_of_faces Number of detected faces + * @param [in] user_data The user data passed from callback invoking code + * + * @pre Call @ref mv_face_detect() function to perform detection of the face for + * the face image and invoke this callback as a result + * + * @see mv_face_detect() + */ +typedef void (*mv_face_detected_cb)( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s *faces_locations, + int number_of_faces, + void *user_data); + +/** + * @brief Performs face detection on the @a source for the @a engine_conf. + * @details Use this function to launch face detection algorithm configured by + * @a engine_conf configuration. Each time when mv_face_detect is + * called, @a detected_cb will receive a set of the detected + * faces at the media source. + * + * @since_tizen 3.0 + * @param [in] source The handle to the source of the media where faces + * will be detected + * @param [in] engine_cfg The handle to the configuration of engine will be + * used for detecting. If NULL, then default settings + * will be used. + * @param [in] detected_cb The callback which will be called for all face + * locations detected on media source. This callback + * will receive detecting results + * @param [in] user_data The user data passed from the code where + * @ref mv_face_detect() is invoked. This data will + * be accessible from @a detected_cb callback. + * @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_INVALID_OPERATION Invalid operation + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Source colorspace + * isn't supported + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create a source handle by calling @ref mv_create_source() + * @post @a detected_cb will be called to process detection results + * + * @see mv_face_detected_cb + */ +int mv_face_detect( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_face_detected_cb detected_cb, + void *user_data); + + +/********************/ +/* Face recognition */ +/********************/ + +/** + * @brief Called each time when face is recognized by @ref mv_face_recognize() + * function. + * + * @since_tizen 3.0 + * @param [in] source The handle to the image source for which + * face has been recognized/not recognized + * @param [in] recognition_model The handle to the recognition model has been + * used for recognition + * @param [in] engine_cfg The handle to the configuration of engine was + * used for recognition, or NULL if default + * settings were applied + * @param [in] face_location The pointer to the location of the face + * recognized on @a source. If face wasn't + * recognized, then pointer is NULL + * @param [in] face_label The label that identifies face which was + * recognized in the @a source. NULL if + * recognition was performed, but no faces + * were 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). No faces were + * recognized if @a confidence was 0.0. + * When model has been learned on large amount + * of examples, threshold for this value + * can be high (0.85-0.95). If model + * was learned for small amount of examples, + * then threshold can be reduced (0.5-0.85) + * @param [in] user_data The user data passed from callback invoking + * code + * + * @pre Call @ref mv_face_recognize() function to perform recognition of the + * face for the face image and invoke this callback as a result + * + * @see mv_face_recognize() + */ +typedef void (*mv_face_recognized_cb)( + 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); + +/** + * @brief Performs face recognition on the @a source image. + * @details Use this function to launch face recognition algorithm configured by + * @a engine_conf configuration using @a recognition_model recognition + * model. Each time when @ref mv_face_recognize() is called, + * @a recognized_cb will receive recognition results:\n + * - Location in the @a source of the face has been recognized; + * - Label of the face has been recognized; + * - Confidence of the @a recognition_model that face has been + * recognized correctly (value from 0.0 to 1.0). + * + * @since_tizen 3.0 + * @remarks Using of untrained or weakly trained recognition models will cause + * not accurate results even if resulting confidence will be high. + * Use @ref mv_face_recognition_model_learn() function before + * @ref mv_face_recognize() call. Best results can be achieved when big + * set of face image examples were added by + * @ref mv_face_recognition_model_add() before + * @ref mv_face_recognition_model_learn() call. + * @param [in] source The handle to the source of the media to + * recognize face(s) for + * @param [in] recognition_model The handle to the model will be used for + * recognition + * @param [in] engine_cfg The handle to the configuration of engine + * will be used for recognition. If NULL, then + * default settings will be used + * @param [in] face_location Rectangular box bounding face image on the + * @a source. If NULL, then full source will be + * analyzed + * @param [in] recognized_cb The callback which will be called for the + * face recognition results on the @a source. + * @param [in] user_data The user data passed from the code where + * @ref mv_face_recognize() is invoked. This + * data will be accessible from @a recognized_cb + * callback + * @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_INVALID_OPERATION Invalid operation + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Source colorspace + * isn't supported + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create a source handle by calling @ref mv_create_source() + * @pre Create a face recognition model handle by calling + * @ref mv_face_recognition_model_create() + * @post @a recognized_cb will be called to process recognition results + * + * @see mv_face_recognized_cb + */ +int mv_face_recognize( + mv_source_h source, + mv_face_recognition_model_h recognition_model, + mv_engine_config_h engine_cfg, + mv_rectangle_s *face_location, + mv_face_recognized_cb recognized_cb, + void *user_data); + + +/*****************/ +/* Face tracking */ +/*****************/ + +/** + * @brief Called when face determined by @a tracking_model is tracked. + * @details This type callback can be invoked each time when + * @ref mv_face_track() is called to process the results of face + * tracking. + * + * @since_tizen 3.0 + * @param [in] source The handle to the video frame or image from + * sequence for which face was tracked + * @param [in] tracking_model The handle to the model that was used for + * tracking + * @param [in] engine_cfg The handle to the configuration of engine was + * used for tracking, or NULL if default settings + * were applied. + * @param [in] location The pointer to the quadrangle-shaped location + * which determines new position of the tracked + * face on the @a source. If NULL, then face was + * lost by tracking algorithm during last iteration + * @param [in] confidence The confidence of the @a tracking_model + * that new location of the face was determined + * correctly (value from 0.0 to 1.0). + * If no location was determined during last track + * iteration, then value is 0.0 + * @param [in] user_data The user data passed from callback invoking code + * + * @pre Call @ref mv_face_track() function to perform track iteration for + * the video frame or the image from sequence and invoke this callback as + * a result + * + * @see mv_face_track() + */ +typedef void (*mv_face_tracked_cb)( + mv_source_h source, + mv_face_tracking_model_h tracking_model, + mv_engine_config_h engine_cfg, + mv_quadrangle_s *location, + double confidence, + void *user_data); + +/** + * @brief Performs face tracking on the @a source for the @a tracking_model. + * @details Use this function to launch face tracking algorithm configured by + * @a engine_conf configuration using @a tracking_model tracking + * model. Each time when this function is called, @a tracked_cb + * will receive updated @a tracking_model, new location determined for + * the tracked face and model confidence that location is determined + * correctly. + * + * @since_tizen 3.0 + * @remarks To allow correct tracking @a tracking_model has to be already used + * in previous tracking process(es) or prepared with + * @ref mv_face_tracking_model_prepare(). Preparation requires + * specifying the face location for the @a source on which tracking was + * started. I.e. @ref mv_face_tracking_model_prepare() function has to + * be called at least once before this method call. + * @param [in] source The handle to the source of the media to + * recognize face for + * @param [in] tracking_model The handle to the model will be used for + * tracking + * @param [in] engine_cfg The handle to the configuration of engine will + * be used for tracking. If NULL, the default + * configuration will be used. + * @param [in] tracked_cb The callback which will be called for tracking + * event on the @a source where face would be + * tracked. This callback will receive tracking + * results + * @param [in] do_learn The model learning flag. If it is set @c true + * then model will try to learn (if it supports + * learning feature), otherwise model will be not + * learned during the invoking tracking iteration. + * Learning process improves tracking correctness, + * but can decrease tracking performance + * @param [in] user_data The user data passed from the code where + * @ref mv_face_track() is invoked. This data will + * be accessible from @a tracked_cb callback + * @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_INVALID_OPERATION Invalid operation + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Source colorspace + * isn't supported + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create a source handle by calling @ref mv_create_source() + * @pre Create a face tracking model handle by calling + * @ref mv_face_tracking_model_create() + * @post @a tracked_cb will be called to process tracking results + * + * @see mv_face_tracked_cb + */ +int mv_face_track( + mv_source_h source, + mv_face_tracking_model_h tracking_model, + mv_engine_config_h engine_cfg, + mv_face_tracked_cb tracked_cb, + bool do_learn, + void *user_data); + + +/********************************/ +/* Recognition of eye condition */ +/********************************/ + +/** + * @brief Called when eye blink condition is recognized. + * @details This type callback can be invoked each time when + * mv_face_eye_condition_recognize() is called for @a face_location to + * recognize eye-blink condition for the face at the @a source.\n + * Usage example for this callback can be found in + * mv_face_eye_condition_recognize() documentation. + * + * @since_tizen 3.0 + * @param [in] source The handle to the source of the media for which + * eye-blink condition was recognized + * @param [in] engine_cfg The handle to the configuration of engine was + * used for eye-blink condition recognition, or + * NULL if default settings were applied. + * @param [in] face_location The location bounding the face at the @a source + * @param [in] eye_condition The type of eye-blink condition recognized for + * face bounded by @a face_location + * @param [in] user_data The user data passed from callback invoking code + * + * + * @pre Call @ref mv_face_eye_condition_recognize() function to perform + * eye-blink condition recognition and invoke this callback as a result + * + * @see mv_face_eye_condition_recognize() + */ +typedef void (*mv_face_eye_condition_recognized_cb)( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s face_location, + mv_face_eye_condition_e eye_condition, + void *user_data); + +/** + * @brief Determines eye-blink condition for @a face_location on media @a source. + * @details Use this function to recognize eye-blink condition for the face + * bounded by @a face_location at @a source. + * + * @since_tizen 3.0 + * @param [in] source The handle to the source of the media to + * recognize eye-blink condition for + * @param [in] engine_cfg The handle to the configuration of engine + * will be used for eye-blink condition + * recognition. If NULL, the default configuration + * will be used. + * @param [in] face_location The location bounding the face at the @a source + * @param [in] eye_condition_recognized_cb The callback for processing result + * of eye-blink condition recognition + * @param [in] user_data The user data passed from the code where + * mv_face_eye_condition_recognize() is invoked. + * This data will be accessible from + * @a eye_condition_recognized_cb callback. + * @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_FORMAT Source colorspace + * isn't supported + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create a source handle by calling mv_create_source() + * + * @see mv_face_eye_condition_recognized_cb + */ +int mv_face_eye_condition_recognize( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s face_location, + mv_face_eye_condition_recognized_cb eye_condition_recognized_cb, + void *user_data); + + +/************************************/ +/* Recognition of facial expression */ +/************************************/ + +/** + * @brief Called when facial expression is recognized + * @details This type callback can be invoked each time when + * mv_face_facial_expression_recognize() is called for @a face_location to + * recognize facial expression for the face at the @a source.\n + * Usage example for this callback can be found in + * mv_face_facial_expression_recognize() documentation. + * + * @since_tizen 3.0 + * @param [in] source The handle to the source of the media for + * which facial expression was recognized + * @param [in] engine_cfg The handle to the configuration of engine was + * used for expression recognition + * @param [in] face_location The location bounding the face at the @a source + * @param [in] facial_expression The type of facial expression recognized + * for face bounded by @a face_location + * @param [in] user_data The user data passed from callback invoking code + * + * @pre Create a source handle by calling mv_create_source() + * @pre Create a face engine configuration handle by calling mv_create_engine_config() + * + * @see mv_face_facial_expression_recognize() + */ +typedef void (*mv_face_facial_expression_recognized_cb)( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s face_location, + mv_face_facial_expression_e facial_expression, + void *user_data); + +/** + * @brief Determines facial expression for @a face_location on media @a source. + * @details Use this function to determine facial expression for the face + * bounded by @a face_location at @a source. + * + * @since_tizen 3.0 + * @param [in] source The handle to the source of the media + * to recognize facial expression for + * @param [in] engine_cfg The handle to the configuration of + * engine will be used for expression recognition + * @param [in] face_location The location bounding the face at the @a source + * @param [in] expression_recognized_cb The callback for processing result + * of facial expression determining + * @param [in] user_data The user data passed from the code where + * mv_face_facial_expression_recognize() is invoked. + * This data will be accessible from + * @a expression_recognized_cb callback. + * @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_FORMAT Source colorspace + * isn't supported + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create a source handle by calling mv_create_source() + * @pre Create a face engine configuration handle by calling @ref mv_create_engine_config() + * + * @see mv_face_facial_expression_recognized_cb + */ +int mv_face_facial_expression_recognize( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s face_location, + mv_face_facial_expression_recognized_cb expression_recognized_cb, + void *user_data); + +/*******************************/ +/* Recognition model behavior */ +/*******************************/ + +/** + * @brief Creates a face recognition model handle. + * @details Use this function to create default face recognition model. Creating + * process is defined by concrete face engine library. After creation + * recognition model has to be learned with + * @ref mv_face_recognition_model_learn() function to provide + * appropriate results of face recognition functionality. Or learned + * earlier model can be loaded by @ref mv_face_recognition_model_load() + * function. + * + * @since_tizen 3.0 + * @remarks It can cause incompatibility issues when saved models (see + * @ref mv_face_recognition_model_save(), + * @ref mv_face_recognition_model_load() + * functions documentation) are used in applications for different + * platforms which use different computer vision libraries underlying + * this API. + * @remarks You must release @a recognition_model by using + * @ref mv_face_recognition_model_destroy() function. + * @param [out] recognition_model The handle to the recognition model to be + * created + * + * @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 + * + * @post Model can be loaded from the file after creation. Use + * @ref mv_face_recognition_model_load() function to load it from file + * @post Release @a recognition_model by using + * @ref mv_face_recognition_model_destroy() function when it is not needed + * anymore + * + * @see mv_face_recognition_model_destroy() + */ +int mv_face_recognition_model_create( + mv_face_recognition_model_h *recognition_model); + +/** + * @brief Destroys the face recognition model handle and releases all its + * resources. + * + * @since_tizen 3.0 + * @param [in] recognition_model The handle to the face recognition model 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 + * + * @pre Create recognition model by using @ref mv_face_recognition_model_create() + * + * @see mv_face_recognition_model_create() + */ +int mv_face_recognition_model_destroy( + mv_face_recognition_model_h recognition_model); + +/** + * @brief Creates a copy of existed recognition model handle and clones all its + * resources. + * + * @since_tizen 3.0 + * @remarks Cloning perform not only handle copy, but also copies all internal + * resources of the model. @a dst must be released using + * @ref mv_face_recognition_model_destroy(). + * @param [in] src The handle to the recognition model to be copied + * @param [out] dst The handle to the copy of existed recognition model + * specified as @a src + * @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 + * + * @pre Create face recognition handles by calling + * @ref mv_face_recognition_model_create() + * + * @see mv_face_recognition_model_create() + */ +int mv_face_recognition_model_clone( + mv_face_recognition_model_h src, + mv_face_recognition_model_h *dst); + +/** + * @brief Saves recognition model to the file. + * + * @since_tizen 3.0 + * @remarks This function doesn't save face image examples (image itself) added by + * @ref mv_face_recognition_model_add() function. + * This examples can be removed by + * @ref mv_face_recognition_model_reset() function if + * it is needed to clear the memory. + * @remarks @a recognition_model is saved to the application's data directory. + * After model is saved to the file, it can be loaded from this file + * by @ref mv_face_recognition_model_load() function. + * @param [in] file_name Name of the file to save the model + * @param [in] recognition_model The handle to the recognition model to be + * saved to the file + * @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_INVALID_OPERATION Invalid operation + * @retval #MEDIA_VISION_ERROR_INVALID_PATH Invalid path + * @retval #MEDIA_VISION_ERROR_PERMISSION_DENIED Not permitted + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Not supported model format + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create a face recognition handle by calling + * @ref mv_face_recognition_model_create() function + * @post Saved model can be loaded later by calling + * @ref mv_face_recognition_model_load() function + * + * @see mv_face_recognition_model_load() + * @see mv_face_recognition_model_create() + */ +int mv_face_recognition_model_save( + const char *file_name, + mv_face_recognition_model_h recognition_model); + +/** + * @brief Loads recognition model from file. + * + * @since_tizen 3.0 + * @remarks This function doesn't modify the set of face image examples added + * with @ref mv_face_recognition_model_add() function. + * Model will be loaded from file without loss of collected examples. + * If you want to free memory from examples, use + * @ref mv_face_recognition_model_reset() function. It + * is recommended to clear the memory if learning algorithm doesn't + * support reinforcement learning. + * @remarks @a recognition_model is loaded from the application's data directory. + * @a recognition_model must be destroyed using + * @ref mv_face_recognition_model_destroy(). + * @param [in] file_name Name of file to load the model + * @param [out] recognition_model The handle to the recognition model + * to be loaded from the file + * @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_INVALID_PATH Invalid path + * @retval #MEDIA_VISION_ERROR_PERMISSION_DENIED Not permitted + * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Not supported model format + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Recognition model can be preliminary saved with + * @ref mv_face_recognition_model_save() function + * + * @see mv_face_recognition_model_save() + * @see mv_face_recognition_model_destroy() + */ +int mv_face_recognition_model_load( + const char *file_name, + mv_face_recognition_model_h *recognition_model); + +/** + * @brief Adds face image example to be used for face recognition model learning + * with @ref mv_face_recognition_model_learn(). + * + * @since_tizen 3.0 + * @remarks It is possible to destroy @a source after calling this method. + * Source isn't used for learning directly. + * @remarks Face image @a example_location location can be determined using + * @ref mv_face_detect function. + * @param [in] source The handle to @a source that contains face + * image + * @param [in] recognition_model The handle to the recognition model which + * could be learned based on example + * @param [in] example_location The pointer to the rectangular location of + * the face image at the source image. If NULL, + * then full image will be analyzed as the face + * image + * @param [in] face_label The label that identifies face for which + * example is adding. Specify the same labels + * for the face images of a single person when + * calling this method. Has to be unique for + * each face + * @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_FORMAT Source colorspace + * isn't supported + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create a face recognition handle by calling + * @ref mv_face_recognition_model_create() function + * @post When appropriate amount of face image examples is added to the + * @a recognition_model, this model has to be learned by + * @ref mv_face_recognition_model_learn() function call. Only after + * learning of the model it can be used for face recognition with + * @ref mv_face_recognize() function + * + * @see mv_face_recognition_model_reset() + * @see mv_face_recognition_model_learn() + */ +int mv_face_recognition_model_add( + const mv_source_h source, + mv_face_recognition_model_h recognition_model, + const mv_rectangle_s *example_location, + int face_label); + +/** + * @brief Removes from @a recognition_model all collected with + * @ref mv_face_recognition_model_add() function + * face examples labeled with @a face_label. + * + * @since_tizen 3.0 + * @remarks Be aware that if this function is called before + * @ref mv_face_recognition_model_learn() function call, all or part of + * the required for learning data will be lost. It means that face + * image examples determined by the @a face_label label will be removed + * from the model and not taken into account when + * @ref mv_face_recognition_model_learn() will be called next time. + * @remarks Call of this function will free all the memory has been allocated + * during previous @ref mv_face_recognition_model_add() + * calls for the corresponding @a face_label label. + * @param [in] recognition_model The handle to the recognition model for + * which face image examples will be reset. + * @param [in] face_label The label that identifies face for which + * examples will be removed from the + * @a recognition_model. If NULL, then all + * known by @a recognition_model face image + * examples will be removed + * @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_KEY_NOT_AVAILABLE Key not available + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @see mv_face_recognition_model_add() + * @see mv_face_recognition_model_learn() + */ +int mv_face_recognition_model_reset( + mv_face_recognition_model_h recognition_model, + int *face_label); + +/** + * @brief Learns face recognition model. + * @details Before you start learning process, face recognition models has to be + * filled with training data - face image examples. These examples has + * to be provided by + * @ref mv_face_recognition_model_add() function. + * Usually, recognition accuracy is increased when number of not + * identical examples is large. But it depends on the used learning + * algorithm. + * + * @since_tizen 3.0 + * @remarks Common flow is to collect face examples as much as possible, add + * them to the recognition model with + * @ref mv_face_recognition_model_add(), then call + * @ref mv_face_recognition_model_learn() for this recognition model to + * learn it (or update the model if updating is supported by the used + * algorithm). + * @remarks Selection of the learning algorithm can be performed by setting + * corresponding attributes for the @a engine_cfg. You can check + * supported by @a engine_cfg attributes using + * @ref mv_engine_config_foreach_supported_attribute() function call. + * By default, Local Binary Patterns Histograms (LBPH) based + * recognition algorithm will be used. + * @param [in] engine_cfg The handle to the configuration of + * engine will be used for learning of the + * recognition models. If NULL, then + * default settings will be used + * @param [in,out] recognition_model The model which will be learned. After + * learning process these model may be + * changed, so @ref mv_face_recognize() + * results may differ before and after + * method call respectively to the face + * examples collected for the + * @a recognition_model + * @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_NO_DATA No data + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create a face engine configuration handle by calling + * @ref mv_create_engine_config() and set supported parameters if + * needed. Or just set @a engine_cfg as NULL to learn with default settings + * @pre Create a face recognition model handles by calling + * @ref mv_face_recognition_model_create() function + * @pre Add face image examples to the @a recognition_model by calling + * @ref mv_face_recognition_model_add() function + * @post If it is not planned to learn the model again, clear memory by + * @ref mv_face_recognition_model_reset() function + * @post When model has been learned, it can be used for face recognition with + * @ref mv_face_recognize() function + * + * @see mv_face_recognition_model_add() + * @see mv_face_recognition_model_reset() + * @see mv_face_recognize() + */ +int mv_face_recognition_model_learn( + mv_engine_config_h engine_cfg, + mv_face_recognition_model_h recognition_model); + +/** + * @brief Queries labels list and number of labels had been learned by the model. + * + * @since_tizen 3.0 + * @remarks @a labels array has to be released using free(). + * @param [in] recognition_model The handle to the recognition model for + * which set of the learned labels will be + * queried + * @param [out] labels The array which will be filled with labels + * had been learned by the model + * @param [out] number_of_labels The number of labels in @a labels array + * @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 Add face image examples with labels to the @a recognition_model by + * calling the @ref mv_face_recognition_model_add() function + * @pre Learn the @a recognition_model by labeled examples using + * @ref mv_face_recognition_model_learn() function + * @post @a labels array has to be freed in the function invoking code + * + * @see mv_face_recognition_model_add() + * @see mv_face_recognition_model_reset() + * @see mv_face_recognition_model_learn() + */ +int mv_face_recognition_model_query_labels( + mv_face_recognition_model_h recognition_model, + int **labels, + unsigned int *number_of_labels); + +/***************************/ +/* Tracking model behavior */ +/***************************/ + +/** + * @brief Calls this function to create a face tracking model handle. + * @details Use this function to create default face tracking model handle. + * After creation this handle has to be initialized with + * @ref mv_face_tracking_model_prepare() function to provide + * appropriate results of face tracking functionality. When handle is + * prepared, it is possible to use it for tracking on continuous + * sequence of the sources. Call @ref mv_face_tracking_model_prepare() + * function each time before starting tracking on the new sequence. + * The exception is situation when the new sequence is continuation + * of the previous sequence for which model has been tracked. + * + * @since_tizen 3.0 + * @param [out] tracking_model The pointer to the handle to the tracking + * model that will be created + * @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 + * + * @post Model can be loaded from the file after creation. Use + * @ref mv_face_tracking_model_load() function to load it from file + * @post Use @ref mv_face_tracking_model_prepare() function before tracking on + * the new video or continuous images sequence + * @post Release @a tracking_model by using + * @ref mv_face_tracking_model_destroy() function when it is not needed + * anymore + * + * @see mv_face_tracking_model_destroy() + * @see mv_face_tracking_model_prepare() + * @see mv_face_tracking_model_load() + */ +int mv_face_tracking_model_create( + mv_face_tracking_model_h *tracking_model); + +/** + * @brief Calls this function to destroy the face tracking model handle and + * release all its resources. + * + * @since_tizen 3.0 + * @param [in] tracking_model The handle to the face tracking model that + * will 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 + * + * @pre Create tracking model by using @ref mv_face_tracking_model_create() + * + * @see mv_face_tracking_model_create() + */ +int mv_face_tracking_model_destroy( + mv_face_tracking_model_h tracking_model); + +/** + * @brief Calls this function to initialize tracking model by the location of the + * face to be tracked. + * @details This function is usually called once after tracking model is created + * and each time before tracking is started for the new sequence of + * sources which is not the direct continuation of the sequence for + * which tracking has been performed before. But it is allowed to call + * it between tracking sessions to allow Media Vision start to track + * more accurately. + * + * @since_tizen 3.0 + * @param [in] tracking_model The handle to the tracking model that will be + * prepared for tracking on new video or image + * sequence + * @param [in] engine_cfg The handle to the configuration of engine + * will be used for model preparing. If NULL, then + * default settings will be used. + * @param [in] source The handle to the source where face @a location + * is specified. Usually it is the first frame of + * the video or the first image in the continuous + * image sequence planned to be used for tracking + * @param [in] location The quadrangle-shaped location (actually, + * rectangle can be used) determining position + * of the face to be tracked on the @a source. If + * @c NULL, then tracking model will try to find + * previously tracked face by itself. Don't set + * NULL when called first time for the tracking + * model. + * @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 Create a face tracking model handle by calling + * @ref mv_face_tracking_model_create() function + * @pre Create a source handle by calling @ref mv_create_source() function + * @post When model is prepared, @ref mv_face_track() function can be used to + * track on the video or continuous image sequence + * + * @see mv_face_tracking_model_create() + * @see mv_face_track() + */ +int mv_face_tracking_model_prepare( + mv_face_tracking_model_h tracking_model, + mv_engine_config_h engine_cfg, + mv_source_h source, + mv_quadrangle_s *location); + +/** + * @brief Calls this function to make a copy of existed tracking model handle and + * clone all its resources to the copy. + * + * @since_tizen 3.0 + * @remarks Cloning performs not only handle copy, but also copies all internal + * resources of the model. @a dst must be released using + * mv_face_tracking_model_destroy(). + * @param [in] src The handle to the tracking model to be copied + * @param [out] dst The handle to the copy of existed tracking model + * specified as @a src + * @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 + * + * @pre Create face tracking @a src handle by calling + * @ref mv_face_tracking_model_create() + * + * @see mv_face_tracking_model_create() + */ +int mv_face_tracking_model_clone( + mv_face_tracking_model_h src, + mv_face_tracking_model_h *dst); + +/** + * @brief Calls this method to save tracking model to the file. + * + * @since_tizen 3.0 + * @remarks @ tracking_model is saved to the application's data directory. + * After model is saved to the file, it can be loaded from this file + * with @ref mv_face_tracking_model_load() function. + * @param [in] file_name Name of the file to save the model + * @param [in] tracking_model The handle to the tracking model to be + * saved to the file + * @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_INVALID_OPERATION Invalid operation + * @retval #MEDIA_VISION_ERROR_INVALID_PATH Invalid path + * @retval #MEDIA_VISION_ERROR_PERMISSION_DENIED Not permitted + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Not supported model format + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create a face tracking handle by calling + * @ref mv_face_tracking_model_create() + * @post Saved model can be loaded from file using + * @ref mv_face_tracking_model_load() function + * + * @see mv_face_tracking_model_load() + * @see mv_face_tracking_model_create() + */ +int mv_face_tracking_model_save( + const char *file_name, + mv_face_tracking_model_h tracking_model); + +/** + * @brief Calls this method to load a tracking model from file. + * + * @since_tizen 3.0 + * @remarks @a tracking_model is loaded from the application's data directory. + * @a tracking_model must be destroyed using + * @ref mv_face_tracking_model_destroy. + * @param [in] file_name Name of file to load the model + * @param [out] tracking_model The handle to the tracking model to be + * loaded from file + * @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_INVALID_OPERATION Invalid operation + * @retval #MEDIA_VISION_ERROR_INVALID_PATH Invalid path + * @retval #MEDIA_VISION_ERROR_PERMISSION_DENIED Not permitted + * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Not supported model format + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Models has been saved by @ref mv_face_tracking_model_save() function + * can be loaded with this function + * @post After model has been loaded and if further tracking will be performed + * on the video which is not continuation of the last tracking performed + * for the model, it is recommended to call + * @ref mv_face_tracking_model_prepare() function + * + * @see mv_face_tracking_model_save() + * @see mv_face_tracking_model_destroy() + */ +int mv_face_tracking_model_load( + const char *file_name, + mv_face_tracking_model_h *tracking_model); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIAVISION_FACE_H__ */ diff --git a/include/mv_face_type.h b/include/mv_face_type.h new file mode 100644 index 0000000..2164e94 --- /dev/null +++ b/include/mv_face_type.h @@ -0,0 +1,117 @@ +/** + * 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_FACE_TYPE_H__ +#define __TIZEN_MEDIAVISION_FACE_TYPE_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file mv_face_type.h + * @brief This file contains enumerations and handles definition required by + * face detect/recognize/track API. + */ + +/** + * @addtogroup CAPI_MEDIA_VISION_FACE_MODULE + * @{ + */ + +/** + * @brief Enumeration for eyes state type. + * + * @since_tizen 3.0 + * + * @see mv_face_eye_condition_recognize() + */ +typedef enum +{ + MV_FACE_EYES_OPEN, /**< Eyes are open */ + MV_FACE_EYES_CLOSED, /**< Eyes are closed */ + MV_FACE_EYES_NOT_FOUND /**< The eyes condition wasn't determined */ +} mv_face_eye_condition_e; + +/** + * @brief Enumeration for expression types can be determined for faces. + * + * @since_tizen 3.0 + * + * @see mv_face_facial_expression_recognize() + */ +typedef enum +{ + MV_FACE_UNKNOWN, /**< Unknown face expression */ + MV_FACE_NEUTRAL, /**< Face expression is neutral */ + MV_FACE_SMILE, /**< Face expression is smiling */ + MV_FACE_SADNESS, /**< Face expression is sadness */ + MV_FACE_SURPRISE, /**< Face expression is surprise */ + MV_FACE_ANGER, /**< Face expression is anger */ + MV_FACE_FEAR, /**< Face expression is fear */ + MV_FACE_DISGUST, /**< Face expression is disgust */ +} mv_face_facial_expression_e; + +/** + * @brief The handle to the model aggregating recognition face features. + * @details This handle can be used for faces recognizing with + * @ref mv_face_recognize() function. Handle has to be created by + * @ref mv_face_recognition_model_create() and destroyed by + * @ref mv_face_recognition_model_destroy() functions. To use + * recognition models effectively learning process has to be performed + * before recognition. In other words, appropriate set of the face + * image examples has to be collected with + * @ref mv_face_recognition_model_add() function before + * @ref mv_face_recognition_model_learn() function call, then + * recognition can be performed with @ref mv_face_recognize(). + * + * @since_tizen 3.0 + * + * @see mv_face_recognition_model_create() + * @see mv_face_recognition_model_destroy() + * @see mv_face_recognition_model_learn() + */ +typedef void *mv_face_recognition_model_h; + +/** + * @brief The handle to the model aggregating tracking face features. + * @details This model can be used for face tracking with @ref mv_face_track() + * function. Handle has to be created by + * @ref mv_face_tracking_model_create() and destroyed by + * @ref mv_face_tracking_model_destroy() function. Tracking model can + * be improved during tracking task and allows to track face more + * accurately. So, you can create several tracking models independently + * by default, then apply tracking task for each of them. After some + * tracking these models will be different and each of them will be + * more efficient for tracking of face for which was created. + * + * @since_tizen 3.0 + * @remarks Create each tracking model for single face. + * + * @see mv_face_tracking_model_create() + * @see mv_face_tracking_model_destroy() + */ +typedef void *mv_face_tracking_model_h; + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIAVISION_FACE_TYPE_H__ */ diff --git a/include/mv_image.h b/include/mv_image.h new file mode 100644 index 0000000..5fa9cf6 --- /dev/null +++ b/include/mv_image.h @@ -0,0 +1,857 @@ +/** + * 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_IMAGE_H__ +#define __TIZEN_MEDIAVISION_IMAGE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file mv_image.h + * @brief This file contains the Media Vision Image API. + * Working with images (like planar objects): recognition and tracking. + */ + +/** + * @addtogroup CAPI_MEDIA_VISION_IMAGE_MODULE + * @{ + */ + +/** + * @brief Defines MV_IMAGE_RECOGNITION_OBJECT_SCALE_FACTOR to set the image to + * be recognized scale factor attribute of the engine configuration. + * @details The value of the factor will be used for resizing of + * the images (objects) for recognition. Scale factor is the double value + * and the defalut is 1.2 + * + * @since_tizen 3.0 + * @see mv_engine_config_set_double_attribute() + * @see mv_engine_config_get_double_attribute() + */ +#define MV_IMAGE_RECOGNITION_OBJECT_SCALE_FACTOR "MV_IMAGE_RECOGNITION_OBJECT_SCALE_FACTOR" + +/** + * @brief Defines MV_IMAGE_RECOGNITION_OBJECT_MAX_KEYPOINTS_NUM to set the maximum + * keypoints should be detected on the image attribute of the + * engine configuration. + * @details The maximal number of keypoints can be selected on the image + * object to calculate descriptors. This keypoints will be used + * for image (object) recognition and has to be specified as integer number + * and the defalut is 1000 + * @since_tizen 3.0 + * @see mv_engine_config_set_int_attribute() + * @see mv_engine_config_get_int_attribute() + */ +#define MV_IMAGE_RECOGNITION_OBJECT_MAX_KEYPOINTS_NUM "MV_IMAGE_RECOGNITION_OBJECT_MAX_KEYPOINTS_NUM" + +/** + * @brief Defines MV_IMAGE_RECOGNITION_SCENE_SCALE_FACTOR to set the scene scale + * factor attribute of the engine configuration. + * @details The value of the factor will be used for resizing of + * the scene including the images (objects) for recognition. + * Scale factor is the double value and the defalut is 1.2 + * + * @since_tizen 3.0 + * @see mv_engine_config_set_double_attribute() + * @see mv_engine_config_get_double_attribute() + */ +#define MV_IMAGE_RECOGNITION_SCENE_SCALE_FACTOR "MV_IMAGE_RECOGNITION_SCENE_SCALE_FACTOR" + +/** + * @brief Defines MV_IMAGE_RECOGNITION_SCENE_MAX_KEYPOINTS_NUM to set the maximum + * keypoints should be detected on the scene attribute of the engine + * configuration. + * @details The maximal number of keypoints can be selected on the scene including + * the images (objects) to calculate descriptors. + * This keypoints will be used for image recognition and has to be specified + * as unsigned integer and the defalut is 5000 + * + * @since_tizen 3.0 + * @see mv_engine_config_set_double_attribute() + * @see mv_engine_config_get_double_attribute() + */ +#define MV_IMAGE_RECOGNITION_SCENE_MAX_KEYPOINTS_NUM "MV_IMAGE_RECOGNITION_SCENE_MAX_KEYPOINTS_NUM" + +/** + * @brief Defines MV_IMAGE_RECOGNITION_MIN_MATCH_NUM to set the minimum number + * of keypoints matches required for recognition attribute of the engine + * configuration. + * @details The minimal number of keypoints should be matched between an image and a scene. + * It will be taken into account for image objects recognition. + * Value is unsigned integer and the defalut is 30 + * + * @since_tizen 3.0 + * @see mv_engine_config_set_int_attribute() + * @see mv_engine_config_get_int_attribute() + */ +#define MV_IMAGE_RECOGNITION_MIN_MATCH_NUM "MV_IMAGE_RECOGNITION_MIN_MATCH_NUM" + +/** + * @brief Defines MV_IMAGE_RECOGNITION_REQ_MATCH_PART to set the required + * matching part for the image recognition attribute of the engine + * configuration. + * @details To recognize occluded or hidden an image by other images, + * required relative part of the matches in respect to the total + * amount of matching keypoints required for image recognition. + * Too low value will result in unsustainable behavior, but + * effect of object overlapping will be reduced. Value can be from 0 to 1 + * and the defalut is 0.05 + * + * @since_tizen 3.0 + * @see mv_engine_config_set_double_attribute() + * @see mv_engine_config_get_double_attribute() + */ +#define MV_IMAGE_RECOGNITION_REQ_MATCH_PART "MV_IMAGE_RECOGNITION_REQ_MATCH_PART" + +/** + * @brief Defines MV_IMAGE_RECOGNITION_TOLERANT_MATCH_PART_ERR to set the part + * matching error for the image recognition attribute of the engine + * configuration. + * @details Allowable error of matches number. Value can be from 0 to 1 + * and the defalut is 0.1 + * + * @since_tizen 3.0 + * @see mv_engine_config_set_double_attribute() + * @see mv_engine_config_get_double_attribute() + */ +#define MV_IMAGE_RECOGNITION_TOLERANT_MATCH_PART_ERR "MV_IMAGE_RECOGNITION_TOLERANT_MATCH_PART_ERR" + +/** + * @brief Defines MV_IMAGE_TRACKING_HISTORY_AMOUNT to set the number of + * recognition results in the tracking history attribute of the engine + * configuration. + * @details Number of previous recognition results, which will influence + * the stabilization. Value is unsigned integer and the defalut is 3 + * + * @since_tizen 3.0 + * @see mv_engine_config_set_int_attribute() + * @see mv_engine_config_get_int_attribute() + */ +#define MV_IMAGE_TRACKING_HISTORY_AMOUNT "MV_IMAGE_TRACKING_HISTORY_AMOUNT" + +/** + * @brief Defines MV_IMAGE_TRACKING_EXPECTED_OFFSET to set the expected tracking + * offset attribute of the engine configuration. + * @detials Relative offset value, for which the object offset is + * expected (relative to the object size in the current frame). + * Value is a double and the defalut is 0 + * + * @since_tizen 3.0 + * @see mv_engine_config_set_double_attribute() + * @see mv_engine_config_get_double_attribute() + */ +#define MV_IMAGE_TRACKING_EXPECTED_OFFSET "MV_IMAGE_TRACKING_EXPECTED_OFFSET" + +/** + * @brief Defines MV_IMAGE_TRACKING_USE_STABLIZATION to enable the contour + * stabilization during tracking process. + * + * @since_tizen 3.0 + * @see mv_engine_config_set_bool_attribute() + * @see mv_engine_config_get_bool_attribute() + */ +#define MV_IMAGE_TRACKING_USE_STABLIZATION "MV_IMAGE_TRACKING_USE_STABLIZATION" + +/** + * @brief Defines MV_IMAGE_TRACKING_STABLIZATION_TOLERANT_SHIFT to set the + * tolerant shift for the tracking stabilization attribute of the engine + * configuration. + * @details Relative value of maximum shift per one frame which will be ignored by + * stabilization (relative to the object size in the current frame). + * Value is a double and the defalut is 0.006 + * + * @since_tizen 3.0 + * @see mv_engine_config_set_double_attribute() + * @see mv_engine_config_get_double_attribute() + */ +#define MV_IMAGE_TRACKING_STABLIZATION_TOLERANT_SHIFT "MV_IMAGE_TRACKING_STABLIZATION_TOLERANT_SHIFT" + +/** + * @brief Defines MV_IMAGE_TRACKING_STABLIZATION_SPEED to set the + * speed of the tracking stabilization attribute of the engine + * configuration. + * @details Start speed will be used for image stabilization. Value is a double + * and the defalut is 2 + * @since_tizen 3.0 + * @see mv_engine_config_set_double_attribute() + * @see mv_engine_config_get_double_attribute() + */ +#define MV_IMAGE_TRACKING_STABLIZATION_SPEED "MV_IMAGE_TRACKING_STABLIZATION_SPEED" + +/** + * @brief Defines MV_IMAGE_TRACKING_STABLIZATION_ACCELERATION to set the + * acceleration of the tracking stabilization attribute of the engine + * configuration. + * @details Acceleration will be used for image stabilization (relative to + * the distance from current location to stabilized location). + * Value is double from 0 to 1 and the defalut is 0.001 + * + * @since_tizen 3.0 + * @see mv_engine_config_set_double_attribute() + * @see mv_engine_config_get_double_attribute() + */ +#define MV_IMAGE_TRACKING_STABLIZATION_ACCELERATION "MV_IMAGE_TRACKING_STABLIZATION_ACCELERATION" + +/****************************/ +/* Image object recognition */ +/****************************/ + +/** + * @brief Called when image recognition results are received from @ref mv_image_recognize() + * @details This type of callback will be called after @ref mv_image_recognize() + * in order to process recognition result. + * + * @since_tizen 3.0 + * @remarks Values @a source, @a engine_cfg, @a image_objects, and @a number_of_objects + * are the same as values of input parameters of @ref mv_image_recognize(). + * @remarks @locations are valid only inside callback. + * @param [in] source The handle to the source image on which the + * recognition was carried out + * @param [in] engine_cfg The handle to the configuration of engine + * that was used for image recognition, or NULL + * if default settings were applied + * @param [in] image_objects The set of handles to the image objects which + * have been processed as targets of recognition + * @param [in] locations The locations of image objects on the source + * image. This array corresponding to an array + * of image objects and each element contains a + * location of corresponding object on the + * @a source image or NULL if object is not + * recognized + * @param [in] number_of_objects The number of image objects and corresponding + * locations + * @param [in] user_data The user data passed from the + * @ref mv_image_recognize() function + * + * @pre Call @ref mv_image_recognize() function to perform recognition of the + * image objects on the source image and invoke this callback as a result + * + * @see mv_image_recognize() + * @see mv_source_h + * @see mv_image_object_h + * @see mv_engine_config_h + * @see mv_quadrangle_s + */ +typedef void (*mv_image_recognized_cb)( + mv_source_h source, + mv_engine_config_h engine_cfg, + const mv_image_object_h *image_objects, + mv_quadrangle_s **locations, + unsigned int number_of_objects, + void *user_data); + +/** + * @brief Recognizes the given image objects on the source image. + * @details Use this function to launch image recognition algorithm configured + * by @a engine_conf configuration. + * + * @since_tizen 3.0 + * @param [in] source The handle to the source image on which image + * objects will be recognized + * @param [in] image_objects The set of handles to the image objects which + * will be processed as targets of recognition + * @param [in] number_of_objects The number of image objects + * @param [in] engine_cfg The handle to the configuration of engine + * which will be used for recognition. If NULL, + * then default settings will be used. + * @param [in] recognized_cb The callback which will be called in order to + * process recognition result + * @param [in] user_data The user data to be passed to the + * @a recognized_cb + * @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_FORMAT Source colorspace + * isn't supported + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create a set of image objects using @ref mv_image_object_create() for + * each of them and construct (fill / load / clone) them on images that + * will be recognized + * @pre Create a source handle by calling @ref mv_create_source() and fill + * by the image for which recognition will be performed + * @post @a mv_image_recognized_cb will be called to process recognition result + * @post Release source image by using @ref mv_destroy_source() + * @post Release image objects by using @ref mv_image_object_destroy() for each + * handle from @a image_objects set + * + * @see mv_image_recognized_cb + * @see mv_source_h + * @see mv_create_source() + * @see mv_destroy_source() + * @see mv_image_object_h + * @see mv_image_object_create() + * @see mv_image_object_destroy() + * @see mv_engine_config_h + */ +int mv_image_recognize( + mv_source_h source, + const mv_image_object_h *image_objects, + int number_of_objects, + mv_engine_config_h engine_cfg, + mv_image_recognized_cb recognized_cb, + void *user_data); + +/*************************/ +/* Image object tracking */ +/*************************/ + +/** + * @brief Called when image tracking result received from @ref mv_image_track() + * @details Image tracking on a sequence of frames assumes calling + * @ref mv_image_track() function for each frame in the correct order. + * This type of callback will be called after each @ref mv_image_track() + * call for processing result data. + * + * @since_tizen 3.0 + * @remarks If image object is not tracked then the callback will be invoked, + * but @a location will be NULL. + * @remarks Handles @a image_tracking_model, @a source and @a engine_cfg the + * same as input parameters of @ref mv_image_track(). + * @remarks @location pointer is valid only inside callback + * @param [in] source The handle to the source image on which + * the tracking was carried out + * @param [in] image_tracking_model The handle to the image tracking model + * which processed as target of tracking + * @param [in] engine_cfg The handle to the configuration of engine + * that was used to image tracking, or + * NULL if default settings were applied + * @param [in] location The image object location on the source + * image or NULL if objects is not tracked + * @param [in] user_data The user data passed from the + * @ref mv_image_track() function + * + * @pre Call @ref mv_image_track() function to perform tracking of the image + * object on the current image from the sequence and invoke this callback + * as a result + * + * @see mv_image_track() + * @see mv_source_h + * @see image_tracking_model_h + * @see mv_engine_config_h + * @see mv_quadrangle_s + */ +typedef void (*mv_image_tracked_cb)( + mv_source_h source, + mv_image_tracking_model_h image_tracking_model, + mv_engine_config_h engine_cfg, + mv_quadrangle_s *location, + void *user_data); + +/** + * @brief Tracks the given image tracking model on the current frame + * @details Image tracking on a sequence of frames assumes calling this + * function for each frame in the correct order. + * @a tracked_cb will be called for result processing. + * + * @since_tizen 3.0 + * @remarks Tracking algorithm is usually using for recognition of image object + * on the sequence of images that are organized by time. For example, + * it may be the sequence of frames from a video stream. + * @remarks If object is lost during the tracking, system tries to find it + * further for the following frames. Therefore, tracking will be + * recovered when object appears again. + * @remarks Previous calls of @ref mv_image_track() for this + * @a image_tracking_model will affect on current call + * @param [in] source The handle to the current image of + * sequence where image tracking model + * will be tracked + * @param [in,out] image_tracking_model The handle to the image tracking model + * which processed as target of tracking + * @param [in] engine_cfg The handle to the configuration of + * engine which will be used for tracking. + * If NULL, then default settings will be + * used. + * @param [in] tracked_cb The callback which will receive + * tracking results + * @param [in] user_data The user data to be passed to the + * @a tracked_cb + * @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_FORMAT Source colorspace + * isn't supported + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create image tracking model by calling + * @ref mv_image_tracking_model_create() and set target by calling + * @ref mv_image_tracking_model_set_target() + * @pre Create a source images by calling @ref mv_create_source() for each of + * them and construct them based on sequence of images for which will be + * held image tracking + * @post @a tracked_cb will be called to process tracking result + * @post Release image tracking model by using + * @ref mv_image_tracking_model_destroy() + * + * @see mv_image_tracked_cb + * @see mv_source_h + * @see image_tracking_model_h + * @see mv_image_tracking_model_create() + * @see mv_image_tracking_model_set_target() + * @see mv_image_tracking_model_destroy() + */ +int mv_image_track( + mv_source_h source, + mv_image_tracking_model_h image_tracking_model, + mv_engine_config_h engine_cfg, + mv_image_tracked_cb tracked_cb, + void *user_data); + +/**************************/ +/* Image object behaviour */ +/**************************/ + +/** + * @brief Creates an image object. + * + * @since_tizen 3.0 + * @param [out] image_object A new handle to the image object + * @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 + * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory + * + * @post Release image object by using @ref mv_image_object_destroy() + * + * @see mv_image_object_destroy() + * @see mv_image_object_h + */ +int mv_image_object_create( + mv_image_object_h *image_object); + +/** + * @brief Destroys the image object. + * + * @since_tizen 3.0 + * @param [in] image_object The handle to the image object 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 + * + * @pre Create image object by using @ref mv_image_object_create() + * + * @see mv_image_object_create() + * @see mv_image_object_h + */ +int mv_image_object_destroy( + mv_image_object_h image_object); + +/** + * @brief Fills the image object. + * @details Extracts data from @a source image which will be needed for + * recognition of depicted object in @a location. + * + * @since_tizen 3.0 + * @remarks After filling the image object it can be evaluated by + * @ref mv_image_object_get_recognition_rate(). If recognition rate + * is too low, try to use another image of object or change + * configuration parameters (see @ref mv_engine_config_h) and construct + * the image object again. + * @param [in,out] image_object The handle to the image object which will be + * filled and can be recognized in future + * @param [in] engine_cfg The handle to the configuration of engine + * which will be used for extract recognition + * data from @a source. If NULL, then default + * settings will be used. + * @param [in] source The source image where image object is depicted + * @param [in] location The pointer to location of the image object + * on the source image, or NULL if the object is + * shown in full + * @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_FORMAT Source colorspace + * isn't supported + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create image object by using @ref mv_image_object_create() + * @post Release image object by using @ref mv_image_object_destroy() + * + * @see mv_image_object_h + * @see mv_image_object_create() + * @see mv_image_object_get_recognition_rate() + * @see mv_image_recognize() + * @see mv_image_object_destroy() + * @see mv_engine_config_h + */ +int mv_image_object_fill( + mv_image_object_h image_object, + mv_engine_config_h engine_cfg, + mv_source_h source, + mv_rectangle_s *location); + +/** + * @brief Gets a value that determines how well an image object can be recognized. + * @details Recognition rate determines how well an image object can be + * recognized. This value can be from 0 to 1. If the recognition rate + * is 0 object can not be recognized and the bigger it is the more + * likely to recognize the object. + * + * @since_tizen 3.0 + * @remarks If recognition rate is too low, try to use another image of object + * or change some configuration parameters (see @ref mv_engine_config_h) + * and fill the image object again (see @ref mv_image_object_fill()). + * @param [in] image_object The handle to the image object which will be + * evaluated by this function + * @param [out] recognition_rate A value that determines how well an image + * object can be recognized, if 0 then object + * can not be recognized + * @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 Create image object by using @ref mv_image_object_create() + * @post Release image object by using @ref mv_image_object_destroy() + * + * @see mv_image_object_h + * @see mv_image_object_create() + * @see mv_image_object_fill() + * @see mv_image_object_destroy() + * @see mv_engine_config_h + */ +int mv_image_object_get_recognition_rate( + mv_image_object_h image_object, + double *recognition_rate); + +/** + * @brief Sets a label for the image object. + * + * @since_tizen 3.0 + * @param [in] image_object The handle to the image object for which the label + * will be assigned + * @param [in] label The label which will be assigned to the image + * object + * @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 Create image object by using @ref mv_image_object_create() + * @post Label could be received by using @ref mv_image_object_get_label() + * @post Release image object by using @ref mv_image_object_destroy() + * + * @see mv_image_object_get_label() + * @see mv_image_object_h + * @see mv_image_object_create() + * @see mv_image_object_destroy() + */ +int mv_image_object_set_label( + mv_image_object_h image_object, + int label); + +/** + * @brief Gets a label of image object. + * + * @since_tizen 3.0 + * @remarks If @a image_object have not a label, this function return + * MEDIA_VISION_ERROR_NO_DATA value. + * @param [in] image_object The handle to the image object from which a + * label will be received + * @param [out] label The label of image object + * @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_NO_DATA Image object hasn't label + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create image object by using @ref mv_image_object_create() + * @pre Set label for the image object by using @ref mv_image_object_set_label() + * @post Release image object by using @ref mv_image_object_destroy() + * + * @see mv_image_object_set_label() + * @see mv_image_object_h + * @see mv_image_object_create() + * @see mv_image_object_destroy() + */ +int mv_image_object_get_label( + mv_image_object_h image_object, + int *label); + +/** + * @brief Clones the image object. + * + * @since_tizen 3.0 + * @remarks @a dst must be released using mv_image_object_destroy(). + * @param [in] src The handle to the source image object + * @param [out] dst The handle to the destination image object + * @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 + * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory + * + * @pre Create image object handles by calling mv_image_object_create() + * + * @see mv_image_object_create() + * @see mv_image_object_destroy() + */ +int mv_image_object_clone( + mv_image_object_h src, + mv_image_object_h *dst); + +/** + * @brief Saves the image object. + * + * @since_tizen 3.0 + * @remarks @a image_object is saved to the application's data directory. + * @param [in] file_name Name of the file to save the image object + * @param [in] image_object The handle to the image object which will be saved + * @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_INVALID_PATH Invalid path + * @retval #MEDIA_VISION_ERROR_PERMISSION_DENIED Not permitted + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create image object handle by calling mv_image_object_create() + * @post Saved model can be loaded later by calling + * mv_image_object_load() function + * + * @see mv_image_object_create() + * @see mv_image_object_load() + * @see mv_image_object_destroy() + */ +int mv_image_object_save( + const char *file_name, mv_image_object_h image_object); + +/** + * @brief Loads an image object from the file. + * + * @since_tizen 3.0 + * @remarks @a image_object is loaded from the application's data directory. + * @a image_object must be destroyed using + * @ref mv_image_object_destroy(). + * @param [in] file_name Name of file to load the image object + * @param [out] image_object The handle to the image object which will be + * filled + * @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_INVALID_PATH Invalid path + * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory + * @retval #MEDIA_VISION_ERROR_PERMISSION_DENIED Not permitted + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Image object can be preliminary saved with mv_image_object_save() + * function + * + * @see mv_image_object_save() + * @see mv_image_object_destroy() + */ +int mv_image_object_load( + const char *file_name, mv_image_object_h *image_object); + +/**********************************/ +/* Image tracking model behaviour */ +/**********************************/ + +/** + * @brief Creates an image tracking model. + * + * @since_tizen 3.0 + * @param [out] image_tracking_model A new handle to the image tracking model + * @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 Release image tracking model by using mv_image_tracking_model_destroy() + * + * @see mv_image_tracking_model_destroy() + */ +int mv_image_tracking_model_create( + mv_image_tracking_model_h *image_tracking_model); + +/** + * @brief Sets target of image tracking model. + * @details Sets image object which will be tracked by using tracking + * functionality with @a image_tracking_model. + * + * @since_tizen 3.0 + * @param [in] image_object Image object which will be set + * as target for tracking + * @param [in] image_tracking_model Handle to the image tracking model + * for which will be set a new target + * @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 Create image tracking model by calling + * @ref mv_image_tracking_model_create() + * @pre Create an image object using @ref mv_image_object_create() and construct + * (fill / load / clone) it on image that will be tracking + * @post Release image object by using @ref mv_image_object_destroy() + * @post Release image tracking model by using + * @ref mv_image_tracking_model_destroy() + * + * @see mv_image_object_h + * @see mv_image_tracking_model_h + * @see mv_image_object_create() + * @see mv_image_object_destroy() + * @see mv_image_tracking_model_create() + * @see mv_image_track() + * @see mv_image_tracking_model_destroy() + */ +int mv_image_tracking_model_set_target( + mv_image_object_h image_object, + mv_image_tracking_model_h image_tracking_model); + +/** + * @brief Destroys the image tracking model. + * + * @since_tizen 3.0 + * @param [in] image_tracking_model The handle to the image tracking model + * 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 + * + * @pre Create image tracking model by using mv_image_tracking_model_create() + * + * @see mv_image_tracking_model_create() + */ +int mv_image_tracking_model_destroy( + mv_image_tracking_model_h image_tracking_model); + +/** + * @brief Refreshes the state of image tracking model. + * @details Clears moving history and change state to undetected. This function + * is usually called each time before tracking is started for the new + * sequence of sources which is not the direct continuation of the + * sequence for which tracking has been performed before. Tracking + * algorithm will try to find image by itself. + * + * @since_tizen 3.0 + * @param [in] image_tracking_model The handle to the image tracking model + * which will be refreshed + * @param [in] engine_cfg The handle to the configuration of + * engine which will be used. If NULL, + * then default settings will be used. + * @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 Create image tracking model by calling + * @ref mv_image_tracking_model_create() + * @post Release image tracking model by using + * @ref mv_image_tracking_model_destroy() + * + * @see mv_image_tracking_model_h + * @see mv_image_tracking_model_create() + * @see mv_image_track() + * @see mv_image_tracking_model_destroy() + */ +int mv_image_tracking_model_refresh( + mv_image_tracking_model_h image_tracking_model, + mv_engine_config_h engine_cfg); + +/** + * @brief Clones the image tracking model. + * + * @since_tizen 3.0 + * @remarks @a dst must be released using mv_image_tracking_model_destroy(). + * @param [in] src The handle to the source image tracking model + * @param [out] dst The handle to the destination image tracking model + * @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 + * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory + * + * @pre Create image tracking model handles by calling + * mv_image_tracking_model_create() + * + * @see mv_image_tracking_model_create() + * @see mv_image_tracking_model_destroy() + */ +int mv_image_tracking_model_clone( + mv_image_tracking_model_h src, + mv_image_tracking_model_h *dst); + +/** + * @brief Saves the image tracking model. + * + * @since_tizen 3.0 + * @remarks @a image_tracking_model is saved to the application's data directory. + * @param [in] file_name Name of file to save the model + * @param [in] image_tracking_model The handle to the image tracking model + * to be saved + * @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_INVALID_PATH Invalid path + * @retval #MEDIA_VISION_ERROR_PERMISSION_DENIED Not permitted + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create image tracking model handle by calling + * mv_image_tracking_model_create() + * @post Saved model can be loaded later by calling + * mv_image_tracking_model_load() function + * + * @see mv_image_tracking_model_create() + * @see mv_image_tracking_model_load() + * @see mv_image_tracking_model_destroy() + */ +int mv_image_tracking_model_save( + const char *file_name, mv_image_tracking_model_h image_tracking_model); + +/** + * @brief Loads an image tracking model from the file. + * + * @since_tizen 3.0 + * @remarks @a image_tracking_model is loaded from the application's data directory. + * @a image_tracking_model must be destroyed using + * @ref mv_image_tracking_model_destroy. + * @param [in] file_name Name of file to load model + * @param [out] image_tracking_model The handle to the image tracking + * model to be filled + * @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_INVALID_PATH Invalid path + * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory + * @retval #MEDIA_VISION_ERROR_PERMISSION_DENIED Not permitted + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Image tracking model handle can be preliminary saved with + * mv_image_tracking_model_save() function + * + * @see mv_image_tracking_model_save() + * @see mv_image_tracking_model_destroy() + */ +int mv_image_tracking_model_load( + const char *file_name, mv_image_tracking_model_h *image_tracking_model); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIAVISION_IMAGE_H__ */ diff --git a/include/mv_image_type.h b/include/mv_image_type.h new file mode 100644 index 0000000..9875685 --- /dev/null +++ b/include/mv_image_type.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 __TIZEN_MEDIAVISION_IMAGE_TYPE_H__ +#define __TIZEN_MEDIAVISION_IMAGE_TYPE_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file mv_image_type.h + * @brief This file contains enumerations and handles definition required by + * image recognize/track API. + */ + +/** + * @addtogroup CAPI_MEDIA_VISION_IMAGE_MODULE + * @{ + */ + +/* Provided data types */ + +/** + * @brief The image object's type handle. + * + * @since_tizen 3.0 + */ +typedef void *mv_image_object_h; + +/** + * @brief The image tracking model's type handle. + * + * @since_tizen 3.0 + */ +typedef void *mv_image_tracking_model_h; + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIAVISION_IMAGE_TYPE_H__ */ diff --git a/include/mv_private.h b/include/mv_private.h new file mode 100644 index 0000000..7877a2b --- /dev/null +++ b/include/mv_private.h @@ -0,0 +1,86 @@ +/** + * 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_MEDIA_VISION_PRIVATE_H__ +#define __TIZEN_MEDIA_VISION_PRIVATE_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include + +#ifdef LOG_TAG +#undef LOG_TAG +#endif + +#define LOG_TAG "TIZEN_MEDIA_VISION" + +#define MEDIA_VISION_FUNCTION_ENTER() \ + LOGI("[%s] ", __FUNCTION__) + +#define MEDIA_VISION_FUNCTION_LEAVE() \ + LOGI("[%s] ", __FUNCTION__) + +#define MEDIA_VISION_ASSERT(function, msg) \ + do \ + { \ + int error_code = function; \ + if(error_code != MEDIA_VISION_ERROR_NONE) \ + { \ + LOGE("%s(0x%08x)", msg, error_code); \ + return error_code; \ + } \ + } \ + while(0) + +#define MEDIA_VISION_CHECK_CONDITION(condition,error,msg) \ + do \ + { \ + if(!(condition)) \ + { \ + LOGE("[%s] %s(0x%08x)", __FUNCTION__, msg, error); \ + return error; \ + } \ + } \ + while(0) + +#define MEDIA_VISION_INSTANCE_CHECK(arg) \ + MEDIA_VISION_CHECK_CONDITION(arg != NULL, \ + MEDIA_VISION_ERROR_INVALID_PARAMETER, \ + "MEDIA_VISION_ERROR_INVALID_PARAMETER") + +#define MEDIA_VISION_NULL_ARG_CHECK(arg) \ + MEDIA_VISION_CHECK_CONDITION(arg != NULL, \ + MEDIA_VISION_ERROR_INVALID_PARAMETER, \ + "MEDIA_VISION_ERROR_INVALID_PARAMETER") + +#define MEDIA_VISION_SUPPORT_CHECK(arg) \ + MEDIA_VISION_CHECK_CONDITION(arg != false, MEDIA_VISION_ERROR_NOT_SUPPORTED, \ + "MEDIA_VISION_ERROR_NOT_SUPPORTED") + +bool __mv_check_system_info_feature_supported(); +bool __mv_barcode_detect_check_system_info_feature_supported(); +bool __mv_barcode_generate_check_system_info_feature_supported(); +bool __mv_face_check_system_info_feature_supported(); +bool __mv_image_check_system_info_feature_supported(); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIA_VISION_PRIVATE_H__ */ diff --git a/media-vision-config-example.json b/media-vision-config-example.json new file mode 100644 index 0000000..2de8fed --- /dev/null +++ b/media-vision-config-example.json @@ -0,0 +1,21 @@ +{ + "attributes": + [ + { "name" : "sample_double_attribute", + "type" : "double", + "value" : 0.82, + }, + { "name" : "sample_integer_attribute", + "type" : "integer", + "value" : 50, + }, + { "name" : "sample_boolean_attribute", + "type" : "boolean", + "value" : true, + }, + { "name" : "sample_string attribute", + "type" : "string", + "value" : "test string", + }, + ] +} diff --git a/media-vision-config.json b/media-vision-config.json new file mode 100644 index 0000000..902567e --- /dev/null +++ b/media-vision-config.json @@ -0,0 +1,120 @@ +{ + "attributes": + [ + { + "name" : "MV_FACE_DETECTION_MODEL_FILE_PATH", + "type" : "string", + "value" : "/usr/share/OpenCV/haarcascades/haarcascade_frontalface_alt2.xml", + }, + { + "name" : "MV_FACE_DETECTION_ROI_X", + "type" : "integer", + "value" : -1, + }, + { + "name" : "MV_FACE_DETECTION_ROI_Y", + "type" : "integer", + "value" : -1, + }, + { + "name" : "MV_FACE_DETECTION_ROI_WIDTH", + "type" : "integer", + "value" : -1, + }, + { + "name" : "MV_FACE_DETECTION_ROI_HEIGHT", + "type" : "integer", + "value" : -1, + }, + { + "name" : "MV_FACE_DETECTION_MIN_SIZE_WIDTH", + "type" : "integer", + "value" : -1, + }, + { + "name" : "MV_FACE_DETECTION_MIN_SIZE_HEIGHT", + "type" : "integer", + "value" : -1, + }, + { + "name" : "MV_BARCODE_DETECT_ATTR_MODE", + "type" : "integer", + "value" : 1, + }, + { + "name" : "MV_BARCODE_DETECT_ATTR_TARGET", + "type" : "integer", + "value" : 0, + }, + { + "name" : "MV_IMAGE_RECOGNITION_OBJECT_SCALE_FACTOR", + "type" : "double", + "value" : 1.2, + }, + { + "name" : "MV_IMAGE_RECOGNITION_OBJECT_MAX_KEYPOINTS_NUM", + "type" : "integer", + "value" : 1000, + }, + { + "name" : "MV_IMAGE_RECOGNITION_SCENE_SCALE_FACTOR", + "type" : "double", + "value" : 1.2, + }, + { + "name" : "MV_IMAGE_RECOGNITION_SCENE_MAX_KEYPOINTS_NUM", + "type" : "integer", + "value" : 5000, + }, + { + "name" : "MV_IMAGE_RECOGNITION_MIN_MATCH_NUM", + "type" : "integer", + "value" : 30, + }, + { + "name" : "MV_IMAGE_RECOGNITION_REQ_MATCH_PART", + "type" : "double", + "value" : 0.05, + }, + { + "name" : "MV_IMAGE_RECOGNITION_TOLERANT_MATCH_PART_ERR", + "type" : "double", + "value" : 0.1, + }, + { + "name" : "MV_IMAGE_TRACKING_HISTORY_AMOUNT", + "type" : "integer", + "value" : 3, + }, + { + "name" : "MV_IMAGE_TRACKING_EXPECTED_OFFSET", + "type" : "double", + "value" : 0, + }, + { + "name" : "MV_IMAGE_TRACKING_USE_STABLIZATION", + "type" : "boolean", + "value" : false, + }, + { + "name" : "MV_IMAGE_TRACKING_STABLIZATION_TOLERANT_SHIFT", + "type" : "double", + "value" : 0.006, + }, + { + "name" : "MV_IMAGE_TRACKING_STABLIZATION_SPEED", + "type" : "double", + "value" : 2, + }, + { + "name" : "MV_IMAGE_TRACKING_STABLIZATION_ACCELERATION", + "type" : "double", + "value" : 0.001, + }, + { + "name" : "MV_FACE_RECOGNITION_MODEL_TYPE", + "type" : "integer", + "value" : 3, + } + ] +} diff --git a/mv_barcode/CMakeLists.txt b/mv_barcode/CMakeLists.txt new file mode 100644 index 0000000..88da8a9 --- /dev/null +++ b/mv_barcode/CMakeLists.txt @@ -0,0 +1,14 @@ +project(mv_barcode) +cmake_minimum_required(VERSION 2.6) + +if(MEDIA_VISION_BARCODE_DETECTOR_LICENSE_PORT) + add_subdirectory(${PROJECT_SOURCE_DIR}/barcode_detector_lic) # Licensed port +else() + add_subdirectory(${PROJECT_SOURCE_DIR}/barcode_detector) # Open port +endif() + +if(MEDIA_VISION_BARCODE_GENERATOR_LICENSE_PORT) + add_subdirectory(${PROJECT_SOURCE_DIR}/barcode_generator_lic) # Licened port +else() + add_subdirectory(${PROJECT_SOURCE_DIR}/barcode_generator) # Open port +endif() diff --git a/mv_barcode/barcode_detector/CMakeLists.txt b/mv_barcode/barcode_detector/CMakeLists.txt new file mode 100644 index 0000000..4a85be3 --- /dev/null +++ b/mv_barcode/barcode_detector/CMakeLists.txt @@ -0,0 +1,29 @@ +project(${MV_BARCODE_DETECTOR_LIB_NAME}) +cmake_minimum_required(VERSION 2.6) + +set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG _DEBUG) + +if(NOT SKIP_WARNINGS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_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("${INC_DIR}") +include_directories("${PROJECT_SOURCE_DIR}/include") +include_directories("${PROJECT_SOURCE_DIR}/src") + +file(GLOB MV_BARCODE_DET_INC_LIST "${PROJECT_SOURCE_DIR}/include/*.h") +file(GLOB MV_BARCODE_DET_SRC_LIST "${PROJECT_SOURCE_DIR}/src/*.cpp") + +if(FORCED_STATIC_BUILD) + add_library(${PROJECT_NAME} STATIC ${MV_BARCODE_DET_INC_LIST} ${MV_BARCODE_DET_SRC_LIST}) +else() + add_library(${PROJECT_NAME} SHARED ${MV_BARCODE_DET_INC_LIST} ${MV_BARCODE_DET_SRC_LIST}) +endif() + +target_link_libraries(${PROJECT_NAME} ${MV_COMMON_LIB_NAME} zbar dlog) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}) diff --git a/mv_barcode/barcode_detector/include/Barcode.h b/mv_barcode/barcode_detector/include/Barcode.h new file mode 100644 index 0000000..6003fb1 --- /dev/null +++ b/mv_barcode/barcode_detector/include/Barcode.h @@ -0,0 +1,88 @@ +/** + * 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 __BARCODE_H__ +#define __BARCODE_H__ + +#include "mv_barcode.h" + +#include +#include + +namespace MediaVision +{ +namespace Barcode +{ + +/** + * @class Barcode + * @brief Handle to barcode object. + */ +class Barcode +{ +public: + /** + * @brief Barcode constructor. + * + * @since_tizen 2.4 + * @remarks create copy of bar_obj + * @param [in] barObj zbar barcode handle + * + */ + Barcode(const zbar::Symbol& barObj); + + /** + * @brief Barcode destructor. + * + * @since_tizen 2.4 + */ + ~Barcode(); + + /** + * @brief Gets encoded message from barcode object. + * + * @since_tizen 2.4 + * @return Encoded message + */ + std::string getMessage(void) const; + + /** + * @brief Gets the type of the barcode. + * + * @since_tizen 2.4 + * @return Enumeration value corresponding to the barcode type + */ + mv_barcode_type_e getType(void) const; + + /** + * @brief Calculates location of barcode handle from zbar. + * location polygon. + * + * @since_tizen 2.4 + * @param [out] location Quadrangle that contains barcode on image + * @return @c MEDIA_VISION_ERROR_NONE on success, + * otherwise a negative error value + */ + int calculateLocation(mv_quadrangle_s& location) const; + +private: + const zbar::Symbol *m_pBarcodeObj; ///< Pointer to zbar barcode handle +}; + +} /* Barcode */ +} /* MediaVision */ + +#endif /* __BARCODE_H__ */ diff --git a/mv_barcode/barcode_detector/include/BarcodeUtils.h b/mv_barcode/barcode_detector/include/BarcodeUtils.h new file mode 100644 index 0000000..4dea365 --- /dev/null +++ b/mv_barcode/barcode_detector/include/BarcodeUtils.h @@ -0,0 +1,46 @@ +/** + * 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_BARCODE_UTILS_H__ +#define __TIZEN_MEDIAVISION_BARCODE_UTILS_H__ + +#include "mv_common.h" + +namespace zbar +{ + class Image; +} + +namespace MediaVision +{ +namespace Barcode +{ + +/** + * @brief This function converts media vision image handle to zbar image handle. + * + * @since_tizen 2.4 + * @param [in] mvSource Media vision image handle + * @param [out] zbarSource Zbar image handle + * @return @c MEDIA_VISION_ERROR_NONE on success, + otherwise a negative error value + */ +int convertSourceMV2Zbar(mv_source_h mvSource, zbar::Image& zbarSource); + +} /* Barcode */ +} /* MediaVision */ + +#endif /* __TIZEN_MEDIAVISION_BARCODE_UTILS_H__ */ diff --git a/mv_barcode/barcode_detector/include/mv_barcode_detect_open.h b/mv_barcode/barcode_detector/include/mv_barcode_detect_open.h new file mode 100644 index 0000000..e13d8e7 --- /dev/null +++ b/mv_barcode/barcode_detector/include/mv_barcode_detect_open.h @@ -0,0 +1,67 @@ +/** + * 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_BARCODE_DETECT_OPEN_H__ +#define __TIZEN_MEDIAVISION_BARCODE_DETECT_OPEN_H__ + +#include "mv_barcode_detect.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file mv_barcode_detect_open.h + * @brief This file contains the Media Vision barcode detect module API for the + * open module. + */ + +/** + * @brief Detects barcode(s) on source and reads message from it. + * + * @since_tizen 2.4 + * @param [in] source The media source handle + * @param [in] engine_cfg The handle to the configuration of the engine + * @param [in] roi Region of interest - rectangular area on the + * @a source which will be used for barcode detection + * Note that @a roi should be inside area on the + * @a source. + * @param [in] detect_cb The callback for result handling + * @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_FORMAT Not supported format + * @retval #MEDIA_VISION_ERROR_INTERNAL Internal error + * @pre Create a source handle by calling @ref mv_create_source() + * @pre Create an engine configuration handle by calling + * @ref mv_create_engine_config() if necessary, otherwise use NULL + * + * @see mv_barcode_detected_cb() + */ +int mv_barcode_detect_open( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s roi, + mv_barcode_detected_cb detect_cb, + void *user_data); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIAVISION_BARCODE_DETECT_OPEN_H__ */ diff --git a/mv_barcode/barcode_detector/src/Barcode.cpp b/mv_barcode/barcode_detector/src/Barcode.cpp new file mode 100644 index 0000000..a35f8bd --- /dev/null +++ b/mv_barcode/barcode_detector/src/Barcode.cpp @@ -0,0 +1,148 @@ +/** + * 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 "Barcode.h" + +#include + +namespace MediaVision +{ +namespace Barcode +{ + +Barcode::Barcode(const zbar::Symbol& barObj): + m_pBarcodeObj(new zbar::Symbol(barObj)) +{ + ; /* NULL */ +} + +Barcode::~Barcode() +{ + LOGI("Delete ZBar object"); + delete m_pBarcodeObj; +} + +std::string Barcode::getMessage(void) const +{ + LOGI("Retrieve message data from ZBar object"); + return m_pBarcodeObj->get_data(); +} + +mv_barcode_type_e Barcode::getType(void) const +{ + zbar::zbar_symbol_type_t barcodeType = m_pBarcodeObj->get_type(); + + switch (barcodeType) + { + case zbar::ZBAR_QRCODE: + return MV_BARCODE_QR; + + case zbar::ZBAR_UPCA: + return MV_BARCODE_UPC_A; + + case zbar::ZBAR_UPCE: + return MV_BARCODE_UPC_E; + + case zbar::ZBAR_EAN8: + return MV_BARCODE_EAN_8; + + case zbar::ZBAR_EAN13: + return MV_BARCODE_EAN_13; + + case zbar::ZBAR_CODE128: + return MV_BARCODE_CODE128; + + case zbar::ZBAR_CODE39: + return MV_BARCODE_CODE39; + + case zbar::ZBAR_I25: + return MV_BARCODE_I2_5; + + default: + LOGE("ZBar symbol colorspace is not supported by media vision"); + return MV_BARCODE_UNDEFINED; + } +} + +int Barcode::calculateLocation(mv_quadrangle_s& location) const +{ + const int numberOfVertexes = 4; + + const int locationPolygonSize = m_pBarcodeObj->get_location_size(); + + //polygon location should contain at least 4 points + if (locationPolygonSize < numberOfVertexes) + { + LOGW("Can't compute location of the barcode by %i points (less then %i).", locationPolygonSize, numberOfVertexes); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + if (locationPolygonSize == numberOfVertexes) + { + for (int i = 0; i < numberOfVertexes; ++i) + { + location.points[i].x = m_pBarcodeObj->get_location_x(i); + location.points[i].y = m_pBarcodeObj->get_location_y(i); + } + + return MEDIA_VISION_ERROR_NONE; + } + + //bounding quadrangle is computing by 4 marginal points + mv_point_s first = {m_pBarcodeObj->get_location_x(0), m_pBarcodeObj->get_location_y(0)}; + + int minX = first.x; + int maxX = first.x; + int minY = first.y; + int maxY = first.y; + + for (int i = 0; i < locationPolygonSize; ++i) + { + mv_point_s current = {m_pBarcodeObj->get_location_x(i), m_pBarcodeObj->get_location_y(i)}; + if (current.x < minX) + { + minX = current.x; + } + else if (current.x > maxX) + { + maxX = current.x; + } + + if (current.y < minY) + { + minY = current.y; + } + else if (current.y > maxY) + { + maxY = current.y; + } + } + + mv_point_s bottomLeft = {minX, maxY}; + mv_point_s bottomRight = {maxX, maxY}; + mv_point_s topRight = {maxX, minY}; + mv_point_s topLeft = {minX, minY}; + + location.points[0] = topLeft; + location.points[1] = topRight; + location.points[2] = bottomRight; + location.points[3] = bottomLeft; + + return MEDIA_VISION_ERROR_NONE; +} + +} /* Barcode */ +} /* MediaVision */ diff --git a/mv_barcode/barcode_detector/src/BarcodeUtils.cpp b/mv_barcode/barcode_detector/src/BarcodeUtils.cpp new file mode 100644 index 0000000..57219eb --- /dev/null +++ b/mv_barcode/barcode_detector/src/BarcodeUtils.cpp @@ -0,0 +1,113 @@ +/** + * 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 "BarcodeUtils.h" +#include "mv_common_c.h" + +#include + +#include + +namespace MediaVision +{ +namespace Barcode +{ + +int convertSourceMV2Zbar(mv_source_h mvSource, zbar::Image& zbarSource) +{ + int err = MEDIA_VISION_ERROR_NONE; + unsigned char *buffer = NULL; + unsigned int height = 0; + unsigned int width = 0; + unsigned int size = 0; + mv_colorspace_e colorspace = MEDIA_VISION_COLORSPACE_INVALID; + + err = mv_source_get_colorspace_c(mvSource, &colorspace); + if (err != MEDIA_VISION_ERROR_NONE) + { + LOGW("Can't determine mv_source_h colorspace to convert to ZBar colorspace. Conversion failed"); + return err; + } + + switch(colorspace) + { + case MEDIA_VISION_COLORSPACE_Y800: + zbarSource.set_format("Y800"); + break; + case MEDIA_VISION_COLORSPACE_I420: + zbarSource.set_format("I420"); + break; + case MEDIA_VISION_COLORSPACE_NV12: + zbarSource.set_format("NV12"); + break; + case MEDIA_VISION_COLORSPACE_YV12: + zbarSource.set_format("YV12"); + break; + case MEDIA_VISION_COLORSPACE_NV21: + zbarSource.set_format("NV21"); + break; + case MEDIA_VISION_COLORSPACE_YUYV: + zbarSource.set_format("YUYV"); + break; + case MEDIA_VISION_COLORSPACE_UYVY: + zbarSource.set_format("UYVY"); + break; + case MEDIA_VISION_COLORSPACE_422P: + zbarSource.set_format("422P"); + break; + case MEDIA_VISION_COLORSPACE_RGB565: + zbarSource.set_format("RGBP"); + break; + case MEDIA_VISION_COLORSPACE_RGB888: + zbarSource.set_format("RGB3"); + break; + case MEDIA_VISION_COLORSPACE_RGBA: + zbarSource.set_format("RGB4"); + break; + default: + LOGE("Media vision colorspace is not supported by ZBar symbol"); + return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT; + } + + err = mv_source_get_buffer_c(mvSource, &buffer, &size); + if (err != MEDIA_VISION_ERROR_NONE) + { + LOGW("Can't get mv_source_h buffer to convert to ZBar image. Conversion failed"); + return err; + } + + err = mv_source_get_height_c(mvSource, &height); + if (err != MEDIA_VISION_ERROR_NONE) + { + LOGW("Can't get mv_source_h height for conversion. Conversion failed"); + return err; + } + + err = mv_source_get_width_c(mvSource, &width); + if (err != MEDIA_VISION_ERROR_NONE) + { + LOGW("Can't get mv_source_h width for conversion. Conversion failed"); + return err; + } + + zbarSource.set_size(width, height); + zbarSource.set_data(buffer, size); + + return err; +} + +} /* Barcode */ +} /* MediaVision */ diff --git a/mv_barcode/barcode_detector/src/mv_barcode_detect_open.cpp b/mv_barcode/barcode_detector/src/mv_barcode_detect_open.cpp new file mode 100644 index 0000000..dd5e557 --- /dev/null +++ b/mv_barcode/barcode_detector/src/mv_barcode_detect_open.cpp @@ -0,0 +1,153 @@ +/** + * 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_barcode_detect_open.h" + +#include "Barcode.h" +#include "BarcodeUtils.h" + +#include + +#include + +using namespace MediaVision::Barcode; + +int mv_barcode_detect_open( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s roi, + mv_barcode_detected_cb detect_cb, + void *user_data) +{ + if (!source || !detect_cb) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + zbar::Image image; + int err = convertSourceMV2Zbar(source, image); + if (err != MEDIA_VISION_ERROR_NONE) + { + LOGW("convertSourceMV2Zbar failed"); + return err; + } + + zbar::Image greyImage = image.convert("Y800"); + greyImage.set_crop(roi.point.x, roi.point.y, roi.width, roi.height); + zbar::ImageScanner scanner; + + int target_val; + err = mv_engine_config_get_int_attribute(engine_cfg, "MV_BARCODE_DETECT_ATTR_TARGET", &target_val); + if (err != MEDIA_VISION_ERROR_NONE) + { + LOGW("mv_engine_config_get_int_attribute failed"); + return err; + } + + /** + * 0 - linear barcodes and QR codes + * 1 - only linear barcodes + * 2 - only QR codes + */ + switch (target_val) + { + case 0: + scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1); + break; + case 1: + scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 0); + scanner.set_config(zbar::ZBAR_UPCA, zbar::ZBAR_CFG_ENABLE, 1); + scanner.set_config(zbar::ZBAR_UPCE, zbar::ZBAR_CFG_ENABLE, 1); + scanner.set_config(zbar::ZBAR_EAN8, zbar::ZBAR_CFG_ENABLE, 1); + scanner.set_config(zbar::ZBAR_EAN13, zbar::ZBAR_CFG_ENABLE, 1); + scanner.set_config(zbar::ZBAR_CODE128, zbar::ZBAR_CFG_ENABLE, 1); + scanner.set_config(zbar::ZBAR_CODE39, zbar::ZBAR_CFG_ENABLE, 1); + scanner.set_config(zbar::ZBAR_I25, zbar::ZBAR_CFG_ENABLE, 1); + break; + case 2: + scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 0); + scanner.set_config(zbar::ZBAR_QRCODE, zbar::ZBAR_CFG_ENABLE, 1); + break; + default: + LOGW("Unavailabe target value %d", target_val); + } + + int numberOfBarcodes = scanner.scan(greyImage); + LOGI("ZBar scanner has found %i barcodes on the mv_source_h", numberOfBarcodes); + mv_quadrangle_s *barcodeLocations = NULL; + mv_barcode_type_e *types = NULL; + + if (numberOfBarcodes == 0) + { + LOGI("Call the detect callback for 0 detected barcodes"); + detect_cb(source, engine_cfg, barcodeLocations, NULL, types, numberOfBarcodes, user_data); + return MEDIA_VISION_ERROR_NONE; + } + else if (numberOfBarcodes < 0) + { + LOGW("Incorrect number of barcodes (%i), detection is terminated", numberOfBarcodes); + return MEDIA_VISION_ERROR_INTERNAL; + } + + const char **messagesArray = new const char*[numberOfBarcodes]; + barcodeLocations = new mv_quadrangle_s[numberOfBarcodes]; + types = new mv_barcode_type_e[numberOfBarcodes]; + + int i = 0; + //extract results and prepare them for callback passing + for (zbar::SymbolIterator symbol = greyImage.symbol_begin(); + symbol != greyImage.symbol_end(); + ++symbol, ++i) + { + Barcode curBarcode(*symbol); + + size_t messageLength = curBarcode.getMessage().size(); + char *curMessage = new char[messageLength + 1]; + curBarcode.getMessage().copy(curMessage, messageLength); + curMessage[messageLength] = '\0'; + messagesArray[i] = curMessage; + + types[i] = curBarcode.getType(); + + int err = curBarcode.calculateLocation(barcodeLocations[i]); + if (err != MEDIA_VISION_ERROR_NONE) + { + LOGW("Can't determine location for barcode, detection is terminated"); + for (int j = 0; j <= i; ++j) + { + delete[] messagesArray[j]; + } + delete[] messagesArray; + delete[] barcodeLocations; + delete[] types; + return err; + } + } + + LOGI("Call the detect callback for %i detected barcodes", numberOfBarcodes); + detect_cb(source, engine_cfg, barcodeLocations, messagesArray, types, numberOfBarcodes, user_data); + + LOGI("Clean the memory from barcodes messages, locations and types"); + for (int j = 0; j < numberOfBarcodes; ++j) + { + delete[] messagesArray[j]; + } + delete[] messagesArray; + delete[] barcodeLocations; + delete[] types; + + return MEDIA_VISION_ERROR_NONE; +} diff --git a/mv_barcode/barcode_detector_lic/CMakeLists.txt b/mv_barcode/barcode_detector_lic/CMakeLists.txt new file mode 100644 index 0000000..c4e6af0 --- /dev/null +++ b/mv_barcode/barcode_detector_lic/CMakeLists.txt @@ -0,0 +1,25 @@ +project(${MV_BARCODE_DETECTOR_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_BARCODE_DET_INC_LIST "${PROJECT_SOURCE_DIR}/include/*.h") +file(GLOB MV_BARCODE_DET_SRC_LIST "${PROJECT_SOURCE_DIR}/src/*.c") + +if(FORCED_STATIC_BUILD) + add_library(${PROJECT_NAME} STATIC ${MV_BARCODE_DET_INC_LIST} ${MV_BARCODE_DET_SRC_LIST}) +else() + add_library(${PROJECT_NAME} SHARED ${MV_BARCODE_DET_INC_LIST} ${MV_BARCODE_DET_SRC_LIST}) +endif() + +target_link_libraries(${PROJECT_NAME} ${MV_COMMON_LIB_NAME}) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}) diff --git a/mv_barcode/barcode_detector_lic/include/mv_barcode_detect_lic.h b/mv_barcode/barcode_detector_lic/include/mv_barcode_detect_lic.h new file mode 100644 index 0000000..b119723 --- /dev/null +++ b/mv_barcode/barcode_detector_lic/include/mv_barcode_detect_lic.h @@ -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. + */ + +#ifndef __TIZEN_MEDIAVISION_BARCODE_DETECT_LIC_H__ +#define __TIZEN_MEDIAVISION_BARCODE_DETECT_LIC_H__ + +#include "mv_barcode_detect.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file mv_barcode_detect_lic.h + * @brief This file contains the Media Vision barcode detect module API for the + * licensed module. + */ + +/** + * @brief Detects barcode(s) on source and reads message from it. + * + * @since_tizen 2.4 + * @param [in] source The media source handle + * @param [in] engine_cfg The handle to the configuration of the engine + * @param [in] roi Region of interest - rectangular area on the + * @a source which will be used for barcode detection + * @param [in] detect_cb The callback for result handling + * @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 + * + * @pre Create a source handle by calling @ref mv_create_source() + * @pre Create an engine configuration handle by calling + * @ref mv_create_engine_config() if necessary, otherwise use NULL + * + * @see mv_barcode_detected_cb() + */ +int mv_barcode_detect_lic( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s roi, + mv_barcode_detected_cb detect_cb, + void *user_data); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIAVISION_BARCODE_DETECT_LIC_H__ */ diff --git a/mv_barcode/barcode_detector_lic/src/mv_barcode_detect_lic.c b/mv_barcode/barcode_detector_lic/src/mv_barcode_detect_lic.c new file mode 100644 index 0000000..5dc9fc0 --- /dev/null +++ b/mv_barcode/barcode_detector_lic/src/mv_barcode_detect_lic.c @@ -0,0 +1,27 @@ +/** + * 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_barcode_detect_lic.h" + +int mv_barcode_detect_lic( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s roi, + mv_barcode_detected_cb detect_cb, + void *user_data) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} diff --git a/mv_barcode/barcode_generator/CMakeLists.txt b/mv_barcode/barcode_generator/CMakeLists.txt new file mode 100644 index 0000000..f3b16b9 --- /dev/null +++ b/mv_barcode/barcode_generator/CMakeLists.txt @@ -0,0 +1,32 @@ +project(${MV_BARCODE_GENERATOR_LIB_NAME}) +cmake_minimum_required(VERSION 2.6) + +set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG _DEBUG) + +if(NOT SKIP_WARNINGS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_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("${INC_DIR}") +include_directories("${PROJECT_SOURCE_DIR}/include") +include_directories("${PROJECT_SOURCE_DIR}/src") + +file(GLOB MV_BARCODE_GEN_INC_LIST "${PROJECT_SOURCE_DIR}/include/*.h") +file(GLOB MV_BARCODE_GEN_SRC_LIST "${PROJECT_SOURCE_DIR}/src/*.cpp") + +find_package(OpenCV REQUIRED) +include_directories(${OpenCV_INCLUDE_DIRS}) + +if(FORCED_STATIC_BUILD) + add_library(${PROJECT_NAME} STATIC ${MV_BARCODE_GEN_INC_LIST} ${MV_BARCODE_GEN_SRC_LIST}) +else() + add_library(${PROJECT_NAME} SHARED ${MV_BARCODE_GEN_INC_LIST} ${MV_BARCODE_GEN_SRC_LIST}) +endif() + +target_link_libraries(${PROJECT_NAME} zint ${MV_COMMON_LIB_NAME} ${OpenCV_LIBS} dlog) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}) diff --git a/mv_barcode/barcode_generator/include/BarcodeGenerator.h b/mv_barcode/barcode_generator/include/BarcodeGenerator.h new file mode 100644 index 0000000..8640683 --- /dev/null +++ b/mv_barcode/barcode_generator/include/BarcodeGenerator.h @@ -0,0 +1,103 @@ +/** + * 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 __BARCODEGENERATOR_H__ +#define __BARCODEGENERATOR_H__ + +#include "BarcodeOptions.h" + +#include + +/** + * @file BarcodeGenerator.h + * @brief This file contains the BarcodeGenerator class. + */ + +namespace MediaVision +{ +namespace Barcode +{ + +/** + * @brief This class implements barcode generation. + * @details 1D Barcodes and 2D QR codes are supported. + * + * @since_tizen 2.4 + */ +class BarcodeGenerator +{ +public: + + /** + * @brief This method generates Barcodes image according to options. + * + * @since_tizen 2.4 + * @param [in] imageFileName Image file name which will be generated + * @param [in] imageFormat Image file format which will be generated + * @param [in] imageWidth Image file width which will be generated + * @param [in] imageHeight Image file height which will be generated + * @param [in] message Input message to be encoded + * @param [in] type Barcode type (1D barcode or 2D QR code) + * @param [in] encodingMode Encoding mode (for QR codes only) + * @param [in] correctionLevel Error correction level (for QR codes only) + * @param [in] qrVersion QR code version (1 ~ 40, 0 for 1D barcodes) + * @return BARCODE_ERROR_NONE from BarcodeError which is 0 if success, + * BarcodeError value otherwise + */ + static int generateBarcodeToImage( + const std::string& imageFileName, + BarcodeImageFormat imageFormat, + const int imageWidth, + const int imageHeight, + const std::string& message, + BarcodeType type, + BarcodeQREncodingMode encodingMode = BARCODE_QR_MODE_UNAVAILABLE, + BarcodeQRErrorCorrectionLevel correctionLevel = BARCODE_QR_ECC_UNAVAILABLE, + int qrVersion = 0); + + /** + * @brief This method generates Barcodes image buffer according to options. + * + * @since_tizen 2.4 + * @param [out] imageBuffer Image buffer with image to be generated + * @param [out] imageWidth Image buffer width which will be generated + * @param [out] imageHeight Image buffer height which will be generated + * @param [out] imageChannels Image buffer channels number which will be generated + * @param [in] message Input message to be encoded + * @param [in] type Barcode type (1D barcode or 2D QR code) + * @param [in] encodingMode Encoding mode (for QR codes only) + * @param [in] correctionLevel Error correction level (for QR codes only) + * @param [in] qrVersion QR code version (1 ~ 40, 0 for 1D barcodes) + * @return BARCODE_ERROR_NONE from BarcodeError which is 0 if success, + * BarcodeError value otherwise + */ + static int generateBarcodeToBuffer( + unsigned char **imageBuffer, + unsigned int *imageWidth, + unsigned int *imageHeight, + unsigned int *imageChannels, + const std::string& message, + BarcodeType type, + BarcodeQREncodingMode encodingMode = BARCODE_QR_MODE_UNAVAILABLE, + BarcodeQRErrorCorrectionLevel correctionLevel = BARCODE_QR_ECC_UNAVAILABLE, + int qrVersion = 0); +}; + +} /* Barcode */ +} /* MediaVision */ + +#endif /* __BARCODEGENERATOR_H__ */ + diff --git a/mv_barcode/barcode_generator/include/BarcodeOptions.h b/mv_barcode/barcode_generator/include/BarcodeOptions.h new file mode 100644 index 0000000..4da3b90 --- /dev/null +++ b/mv_barcode/barcode_generator/include/BarcodeOptions.h @@ -0,0 +1,114 @@ +/** + * 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 __BARCODEOPTIONS_H__ +#define __BARCODEOPTIONS_H__ + +/** + * @file BarcodeOptions.h + * @brief This file contains the Barcode options. + */ + +namespace MediaVision +{ +namespace Barcode +{ + +/** + * @brief The Barcode type enumeration. + * + * @since_tizen 2.4 + */ +enum BarcodeType +{ + BARCODE_QR = 58, + BARCODE_UPCA = 34, + BARCODE_UPCE = 37, + BARCODE_EAN8 = 13, + BARCODE_EAN13 = BARCODE_EAN8, + BARCODE_CODE39 = 8, + BARCODE_CODE128 = 20, + BARCODE_INTERLEAVE_2_5 = 3 +}; + +/** + * @brief The Barcode error correction level enumeration. + * + * @since_tizen 2.4 + * @remarks This is unavailable for 1D barcodes. + */ +enum BarcodeQRErrorCorrectionLevel +{ + BARCODE_QR_ECC_UNAVAILABLE = 0, + BARCODE_QR_ECC_LOW = 1, + BARCODE_QR_ECC_MEDIUM = 2, + BARCODE_QR_ECC_QUARTILE = 3, + BARCODE_QR_ECC_HIGH = 4 +}; + + +/** + * @brief The Barcode encoding mode enumeration. + * + * @since_tizen 2.4 + * @remarks This is unavailable for 1D barcodes. + */ +enum BarcodeQREncodingMode +{ + BARCODE_QR_MODE_NUMERIC = 1, + BARCODE_QR_MODE_ALPHANUMERIC = 1, + BARCODE_QR_MODE_BYTE = 0, + BARCODE_QR_MODE_UTF8 = 1, + BARCODE_QR_MODE_KANJI = 3, + BARCODE_QR_MODE_UNAVAILABLE +}; + +/** + * @brief The Barcode image format enumeration. + * + * @since_tizen 2.4 + */ +enum BarcodeImageFormat +{ + BARCODE_IMAGE_JPG, + BARCODE_IMAGE_PNG, + BARCODE_IMAGE_BMP +}; + +/** + * @brief The Barcode error enumeration. + * + * @since_tizen 2.4 + */ +enum BarcodeError +{ + BARCODE_ERROR_NONE = 0, + BARCODE_WARNING_INVALID_OPTION = 2, + BARCODE_ERROR_TOO_LONG = 5, + BARCODE_ERROR_INVALID_DATA = 6, + BARCODE_ERROR_INVALID_CHECK = 7, + BARCODE_ERROR_INVALID_OPTION = 8, + BARCODE_ERROR_ENCODING_PROBLEM = 9, + BARCODE_ERROR_FILE_ACCESS = 10, + BARCODE_ERROR_MEMORY = 11, + BARCODE_ERROR_INVALID_PATH =12, +}; + +} /* Barcode */ +} /* MediaVision */ + +#endif /* __BARCODEOPTIONS_H__ */ + diff --git a/mv_barcode/barcode_generator/include/mv_barcode_generate_open.h b/mv_barcode/barcode_generator/include/mv_barcode_generate_open.h new file mode 100644 index 0000000..d3134ac --- /dev/null +++ b/mv_barcode/barcode_generator/include/mv_barcode_generate_open.h @@ -0,0 +1,109 @@ +/** + * 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_BARCODE_GENERATE_OPEN_H__ +#define __TIZEN_MEDIAVISION_BARCODE_GENERATE_OPEN_H__ + +#include "mv_barcode_generate.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file mv_barcode_generate_open.h + * @brief This file contains the Media Vision barcode generate module API for + * the open module. + */ + +/** + * @brief Generates @ref mv_source_h with barcode image. + * + * @since_tizen 2.4 + * @param [in] engine_cfg The handle to the configuration of the engine + * @param [in] message The message to be encoded in the barcode + * @param [in] type Type of the barcode to be generated + * @param [in] qr_enc_mode Encoding mode for the message (only for QR codes; + * for 1D barcodes set this parameter to + * @ref MV_BARCODE_QR_MODE_UNAVAILABLE) + * @param [in] qr_ecc Error correction level (only for QR codes; for + * 1D barcodes set this parameter to + * @ref MV_BARCODE_QR_ECC_UNAVAILABLE) + * @param [in] qr_version QR code version (for 1D barcodes set this + * parameter to 0) + * @param [in, out] image The media source handle which will be used to + * fill by the buffer with generated image + * @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_MSG_TOO_LONG Too long or short message + * @retval #MEDIA_VISION_ERROR_PERMISSION_DENIED Permission denied + * + * @see mv_barcode_generate_image_open() + */ +int mv_barcode_generate_source_open(mv_engine_config_h engine_cfg, + const char *message, + mv_barcode_type_e type, + mv_barcode_qr_mode_e qr_enc_mode, + mv_barcode_qr_ecc_e qr_ecc, + int qr_version, + mv_source_h image); + +/** + * @brief Generates image file with barcode. + * + * @since_tizen 2.4 + * @param [in] engine_cfg The handle to the configuration of the engine + * @param [in] message The message to be encoded in the barcode + * @param [in] image_width The width of the generated image + * @param [in] image_height The height of the generated image + * @param [in] type Type of the barcode to be generated + * @param [in] qr_enc_mode Encoding mode for the message (only for QR codes; + * for 1D barcodes set this parameter to + * @ref MV_BARCODE_QR_MODE_UNAVAILABLE) + * @param [in] qr_ecc Error correction level (only for QR codes; for + * 1D barcodes set this parameter to + * @ref MV_BARCODE_QR_ECC_UNAVAILABLE) + * @param [in] qr_version QR code version (for 1D barcodes set this + * parameter to 0) + * @param [in] image_path The path to the file that has to be generated + * @param [in] image_format The format of the output image + * @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_MSG_TOO_LONG Too long or short message + * @retval #MEDIA_VISION_ERROR_PERMISSION_DENIED Permission denied + * @retval #MEDIA_VISION_ERROR_INVALID_PATH Invalid path + * + * @see mv_barcode_generate_source_open() + */ +int mv_barcode_generate_image_open( + mv_engine_config_h engine_cfg, + const char *message, + int image_width, + int image_height, + mv_barcode_type_e type, + mv_barcode_qr_mode_e qr_enc_mode, + mv_barcode_qr_ecc_e qr_ecc, + int qr_version, + const char *image_path, + mv_barcode_image_format_e image_format); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIAVISION_BARCODE_GENERATE_OPEN_H__ */ diff --git a/mv_barcode/barcode_generator/src/BarcodeGenerator.cpp b/mv_barcode/barcode_generator/src/BarcodeGenerator.cpp new file mode 100644 index 0000000..8e1d85d --- /dev/null +++ b/mv_barcode/barcode_generator/src/BarcodeGenerator.cpp @@ -0,0 +1,280 @@ +/** + * 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 "BarcodeGenerator.h" + +#include + +#include + +#include +#include +#include + +#include +#include +#include + +namespace MediaVision +{ +namespace Barcode +{ + +namespace +{ + +int getFormatEncodingInfo( + BarcodeImageFormat imageFormat, + std::vector& extensions, + std::vector& compressionParams) +{ + static const int PNGCompressionLevel = 3; + + compressionParams.clear(); + extensions.clear(); + + switch (imageFormat) + { + case BARCODE_IMAGE_PNG: + compressionParams.push_back(CV_IMWRITE_PNG_COMPRESSION); + compressionParams.push_back(PNGCompressionLevel); + extensions.push_back(".png"); + break; + case BARCODE_IMAGE_JPG: + extensions.push_back(".jpg"); + extensions.push_back(".jpeg"); + extensions.push_back(".jpe"); + break; + case BARCODE_IMAGE_BMP: + extensions.push_back(".bmp"); + extensions.push_back(".dib"); + break; + default: + return BARCODE_ERROR_INVALID_OPTION; + } + return BARCODE_ERROR_NONE; +} + +int createBarcode( + const std::string& message, + BarcodeType type, + BarcodeQREncodingMode encodingMode, + BarcodeQRErrorCorrectionLevel correctionLevel, + int qrVersion, + zint_symbol *symbol) +{ + // set input values + symbol->symbology = type; + symbol->input_mode = encodingMode; + symbol->option_1 = correctionLevel; + symbol->option_2 = qrVersion; + symbol->scale = 1; + + // set default values + std::strcpy(symbol->fgcolour, "000000"); + std::strcpy(symbol->bgcolour, "ffffff"); + symbol->border_width = 1; + symbol->whitespace_width = 0; + symbol->height = 50; + + // create barcode + const int rotationAngle = 0; + int error = ZBarcode_Encode_and_Buffer( + symbol, + (unsigned char*)(message.c_str()), + message.length(), + rotationAngle); + + return error; +} + +int writeBufferToImageFile( + zint_symbol *symbol, + const std::string& imageFileName, + BarcodeImageFormat imageFormat, + const int imageWidth, + const int imageHeight) +{ + if (imageWidth <= 0 || imageHeight <= 0) + { + LOGE("Barcode image size is invalid: %i x %i. Terminate write to " + "the image operation", imageWidth, imageHeight); + return BARCODE_ERROR_INVALID_DATA; + } + + /* find directory */ + std::string prefix_imageFileName = imageFileName.substr(0, imageFileName.find_last_of('/')); + LOGD("prefix_path: %s", prefix_imageFileName.c_str()); + + /* check the directory is available */ + if (access(prefix_imageFileName.c_str(),F_OK)) + { + LOGE("Can't save barcode image to the path. The path[%s] doesn't existed.", prefix_imageFileName.c_str()); + return BARCODE_ERROR_INVALID_PATH; + } + + // check current extension + std::vector expectedExtensions; + std::vector compressionParams; + + int error = getFormatEncodingInfo(imageFormat, + expectedExtensions, compressionParams); + + if (BARCODE_ERROR_NONE != error || expectedExtensions.empty()) + { + LOGE("Image format is incorrectly specified or not supported"); + return error; + } + + bool rightExtensionFlag = false; + + std::string resultFilePath(imageFileName); + + for (size_t extNum = 0; extNum < expectedExtensions.size(); ++extNum) + { + if (resultFilePath.size() >= expectedExtensions[extNum].size()) + { + std::string givenExtension = resultFilePath.substr( + resultFilePath.length() - expectedExtensions[extNum].size(), + expectedExtensions[extNum].size()); + + std::transform( + givenExtension.begin(), givenExtension.end(), + givenExtension.begin(), ::tolower); + + if (givenExtension == expectedExtensions[extNum]) + { + rightExtensionFlag = true; + break; + } + } + } + + if (!rightExtensionFlag) + { + resultFilePath += expectedExtensions[0]; + } + + cv::Mat image(symbol->bitmap_height, symbol->bitmap_width, CV_8UC3, symbol->bitmap); + cv::resize(image, image, cv::Size(imageWidth, imageHeight), 0, 0, cv::INTER_AREA); + + error = cv::imwrite(resultFilePath, image, compressionParams) ? + BARCODE_ERROR_NONE : BARCODE_ERROR_INVALID_DATA; + + if (BARCODE_ERROR_NONE != error) + { + LOGE("Write barcode image to file %s operation failed.", + resultFilePath.c_str()); + return error; + } + + return error; +} + +} /* anonymous namespace */ + +int BarcodeGenerator::generateBarcodeToImage( + const std::string& imageFileName, + BarcodeImageFormat imageFormat, + const int imageWidth, + const int imageHeight, + const std::string& message, + BarcodeType type, + BarcodeQREncodingMode encodingMode, + BarcodeQRErrorCorrectionLevel correctionLevel, + int qrVersion) +{ + zint_symbol *symbol = ZBarcode_Create(); + + int error = createBarcode( + message, + type, + encodingMode, + correctionLevel, + qrVersion, + symbol); + + if (error != BARCODE_ERROR_NONE) + { + LOGE("Barcode creation failed, clean memory"); + ZBarcode_Delete(symbol); + return error; + } + + error = writeBufferToImageFile( + symbol, + imageFileName, + imageFormat, + imageWidth, + imageHeight); + if (error != BARCODE_ERROR_NONE) + { + LOGE("Barcode [%s] file write fail, clean memory", imageFileName.c_str()); + } + else + { + LOGI("Barcode image [%s] is successfully generated, clean memory", imageFileName.c_str()); + } + + ZBarcode_Delete(symbol); + + return error; +} + +int BarcodeGenerator::generateBarcodeToBuffer( + unsigned char **imageBuffer, + unsigned int *imageWidth, + unsigned int *imageHeight, + unsigned int *imageChannels, + const std::string& message, + BarcodeType type, + BarcodeQREncodingMode encodingMode, + BarcodeQRErrorCorrectionLevel correctionLevel, + int qrVersion) +{ + zint_symbol *symbol = ZBarcode_Create(); + + int error = createBarcode( + message, + type, + encodingMode, + correctionLevel, + qrVersion, + symbol); + + if (error != BARCODE_ERROR_NONE) + { + LOGE("Barcode creation failed, clean memory"); + ZBarcode_Delete(symbol); + return error; + } + + // fill output buffer + *imageWidth = symbol->bitmap_width; + *imageHeight = symbol->bitmap_height; + *imageChannels = 3; + const unsigned int imageBufferSize = (*imageWidth) * (*imageHeight) * (*imageChannels); + *imageBuffer = new unsigned char [imageBufferSize]; + memmove(*imageBuffer, symbol->bitmap, imageBufferSize); + + LOGI("Barcode buffer has been successfully generated, clean memory"); + ZBarcode_Delete(symbol); + + return BARCODE_ERROR_NONE; +} + +} /* Barcode */ +} /* MediaVision */ diff --git a/mv_barcode/barcode_generator/src/mv_barcode_generate_open.cpp b/mv_barcode/barcode_generator/src/mv_barcode_generate_open.cpp new file mode 100644 index 0000000..1aa3034 --- /dev/null +++ b/mv_barcode/barcode_generator/src/mv_barcode_generate_open.cpp @@ -0,0 +1,348 @@ +/** + * 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_barcode_generate_open.h" + +#include "mv_common_c.h" +#include "BarcodeGenerator.h" + +#include + +#include +#include + +using namespace MediaVision::Barcode; + +namespace +{ + +int alphanumToUpper(std::string& strToTransform) +{ + std::string tempString = strToTransform; + std::transform(tempString.begin(), tempString.end(), + tempString.begin(), ::toupper); + + if (std::string::npos != tempString.find_first_not_of("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:")) + { + LOGE("Barcode message can't be converted according to support " + "alphanumeric (0..9, A..Z, space, $, %, *, +, -, ., /, :) " + "mode: %s", strToTransform.c_str()); + return BARCODE_ERROR_INVALID_DATA; + } + + LOGI("Barcode message was converted according to support alphanumeric " + "mode: %s -> %s", strToTransform.c_str(), tempString.c_str()); + strToTransform = tempString; + return BARCODE_ERROR_NONE; +} + +BarcodeType convertBarcodeType(mv_barcode_type_e type) +{ + BarcodeType barcodeType = BARCODE_QR; + switch (type) + { + case MV_BARCODE_UPC_A: + barcodeType = BARCODE_UPCA; + break; + case MV_BARCODE_UPC_E: + barcodeType = BARCODE_UPCE; + break; + case MV_BARCODE_EAN_8: + barcodeType = BARCODE_EAN8; + break; + case MV_BARCODE_EAN_13: + barcodeType = BARCODE_EAN13; + break; + case MV_BARCODE_CODE128: + barcodeType = BARCODE_CODE128; + break; + case MV_BARCODE_CODE39: + barcodeType = BARCODE_CODE39; + break; + case MV_BARCODE_I2_5: + barcodeType = BARCODE_INTERLEAVE_2_5; + break; + default: + break; + } + + LOGI("Media vision barcode type has been converted to ZInt barcode type " + "(%i -> %i)", type, barcodeType); + return barcodeType; +} + +BarcodeQREncodingMode convertEncodingMode(mv_barcode_qr_mode_e mode) +{ + BarcodeQREncodingMode encodingMode = BARCODE_QR_MODE_ALPHANUMERIC; + + switch (mode) + { + case MV_BARCODE_QR_MODE_NUMERIC: + encodingMode = BARCODE_QR_MODE_NUMERIC; + break; + case MV_BARCODE_QR_MODE_BYTE: + encodingMode = BARCODE_QR_MODE_BYTE; + break; + case MV_BARCODE_QR_MODE_UTF8: + encodingMode = BARCODE_QR_MODE_UTF8; + break; + default: + break; + } + + LOGI("Media vision QRCode encoding mode has been converted to " + "ZInt encoding mode (%i -> %i)", mode, encodingMode); + return encodingMode; +} + +BarcodeQRErrorCorrectionLevel convertECC(mv_barcode_qr_ecc_e ecc) +{ + BarcodeQRErrorCorrectionLevel ecclevel = BARCODE_QR_ECC_LOW; + + switch (ecc) + { + case MV_BARCODE_QR_ECC_MEDIUM: + ecclevel = BARCODE_QR_ECC_MEDIUM; + break; + case MV_BARCODE_QR_ECC_QUARTILE: + ecclevel = BARCODE_QR_ECC_QUARTILE; + break; + case MV_BARCODE_QR_ECC_HIGH: + ecclevel = BARCODE_QR_ECC_HIGH; + break; + default: + break; + } + + LOGI("Media vision ECC level has been converted to " + "ZInt ECC level (%i -> %i)", ecc, ecclevel); + return ecclevel; +} + +int convertBarcodeError(int barcodeError) +{ + int mvError = MEDIA_VISION_ERROR_NONE; + + switch (barcodeError) + { + case BARCODE_WARNING_INVALID_OPTION: + mvError = MEDIA_VISION_ERROR_INVALID_PARAMETER; + break; + case BARCODE_ERROR_TOO_LONG: + mvError = MEDIA_VISION_ERROR_MSG_TOO_LONG; + break; + case BARCODE_ERROR_INVALID_DATA: + mvError = MEDIA_VISION_ERROR_INVALID_DATA; + break; + case BARCODE_ERROR_INVALID_CHECK: + mvError = MEDIA_VISION_ERROR_INVALID_PARAMETER; + break; + case BARCODE_ERROR_INVALID_OPTION: + mvError = MEDIA_VISION_ERROR_INVALID_PARAMETER; + break; + case BARCODE_ERROR_ENCODING_PROBLEM: + mvError = MEDIA_VISION_ERROR_INTERNAL; + break; + case BARCODE_ERROR_FILE_ACCESS: + mvError = MEDIA_VISION_ERROR_PERMISSION_DENIED; + break; + case BARCODE_ERROR_MEMORY: + mvError = MEDIA_VISION_ERROR_OUT_OF_MEMORY; + break; + case BARCODE_ERROR_INVALID_PATH: + mvError = MEDIA_VISION_ERROR_INVALID_PATH; + default: + break; + } + + LOGI("ZInt error code has been converted to the media vision error code " + "(%i -> (0x%08x))", barcodeError, mvError); + return mvError; +} + +BarcodeImageFormat convertImageFormat(mv_barcode_image_format_e format) +{ + BarcodeImageFormat imageFormat = BARCODE_IMAGE_PNG; + + switch (format) + { + case MV_BARCODE_IMAGE_FORMAT_JPG: + imageFormat = BARCODE_IMAGE_JPG; + break; + case MV_BARCODE_IMAGE_FORMAT_BMP: + imageFormat = BARCODE_IMAGE_BMP; + break; + default: + break; + } + + LOGI("Media vision image format has been converted to " + "internal image format (%i -> %i)", format, imageFormat); + return imageFormat; +} + +} /* anonymous namespace */ + +int mv_barcode_generate_source_open( + mv_engine_config_h /*engine_cfg*/, + const char *message, + mv_barcode_type_e type, + mv_barcode_qr_mode_e qr_enc_mode, + mv_barcode_qr_ecc_e qr_ecc, + int qr_version, + mv_source_h image) +{ + std::string messageStr = std::string(message); + + if (qr_enc_mode == MV_BARCODE_QR_MODE_NUMERIC && + messageStr.find_first_not_of("0123456789") != std::string::npos) + { + LOGE("Barcode message can't be used according to support " + "numeric (0..9) mode: %s", messageStr.c_str()); + return MEDIA_VISION_ERROR_INVALID_DATA; + } + + int error = BARCODE_ERROR_NONE; + if (MV_BARCODE_QR == type && + MV_BARCODE_QR_MODE_ALPHANUMERIC == qr_enc_mode) + { + error = alphanumToUpper(messageStr); + if (BARCODE_ERROR_NONE != error) + { + return convertBarcodeError(error); + } + } + + unsigned char *imageBuffer = NULL; + unsigned int imageWidth = 0u; + unsigned int imageHeight = 0u; + unsigned int imageChannels = 0u; + + error = BarcodeGenerator::generateBarcodeToBuffer( + &imageBuffer, + &imageWidth, + &imageHeight, + &imageChannels, + messageStr, + convertBarcodeType(type), + convertEncodingMode(qr_enc_mode), + convertECC(qr_ecc), + qr_version); + + if (error != BARCODE_ERROR_NONE) + { + LOGE("Barcode generation to the buffer failed"); + if (NULL != imageBuffer) + { + LOGI("Delete temporal buffer"); + delete[] imageBuffer; + } + return convertBarcodeError(error); + } + + const unsigned int imageBufferSize = imageWidth * imageHeight * imageChannels; + + LOGI("Barcode has been generated to the buffer: " + "Buffer size = %ui x %ui; Channels = %ui; Message = %s", + imageWidth, imageHeight, imageChannels, messageStr.c_str()); + + error = mv_source_fill_by_buffer_c( + image, + imageBuffer, + imageBufferSize, + imageWidth, + imageHeight, + MEDIA_VISION_COLORSPACE_RGB888); + + if (error != MEDIA_VISION_ERROR_NONE) + { + LOGE("Meidiavision source fill by generated buffer failed"); + } + + if (NULL != imageBuffer) + { + LOGI("Delete temporal buffer"); + delete[] imageBuffer; + } + + return error; +} + + +int mv_barcode_generate_image_open( + mv_engine_config_h /*engine_cfg*/, + const char *message, + int image_width, + int image_height, + mv_barcode_type_e type, + mv_barcode_qr_mode_e qr_enc_mode, + mv_barcode_qr_ecc_e qr_ecc, + int qr_version, + const char *image_path, + mv_barcode_image_format_e image_format) +{ + std::string messageStr = std::string(message); + + if (qr_enc_mode == MV_BARCODE_QR_MODE_NUMERIC && + messageStr.find_first_not_of("0123456789") != std::string::npos) + { + LOGE("Barcode message can't be used according to support " + "numeric (0..9) mode: %s", messageStr.c_str()); + return MEDIA_VISION_ERROR_INVALID_DATA; + } + + if (NULL == image_path) + { + LOGE("Can't save barcode image to the path[%p]. The path has to be specified", image_path); + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + int error = BARCODE_ERROR_NONE; + if (MV_BARCODE_QR == type && + MV_BARCODE_QR_MODE_ALPHANUMERIC == qr_enc_mode) + { + error = alphanumToUpper(messageStr); + if (BARCODE_ERROR_NONE != error) + { + return convertBarcodeError(error); + } + } + + error = BarcodeGenerator::generateBarcodeToImage( + std::string(image_path), + convertImageFormat(image_format), + image_width, + image_height, + messageStr, + convertBarcodeType(type), + convertEncodingMode(qr_enc_mode), + convertECC(qr_ecc), + qr_version); + + if (error != BARCODE_ERROR_NONE) + { + LOGE("Barcode generation to the image file failed"); + } + else + { + LOGI("Barcode has been generated to the image: " + "Image size = %ui x %ui; Message = %s", + image_width, image_height, messageStr.c_str()); + } + + return convertBarcodeError(error); +} + diff --git a/mv_barcode/barcode_generator_lic/CMakeLists.txt b/mv_barcode/barcode_generator_lic/CMakeLists.txt new file mode 100644 index 0000000..f037975 --- /dev/null +++ b/mv_barcode/barcode_generator_lic/CMakeLists.txt @@ -0,0 +1,25 @@ +project(${MV_BARCODE_GENERATOR_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_BARCODE_GEN_INCLUDE_LIST "${PROJECT_SOURCE_DIR}/include/*.h") +file(GLOB MV_BARCODE_GEN_SRC_LIST "${PROJECT_SOURCE_DIR}/src/*.c") + +if(FORCED_STATIC_BUILD) + add_library(${PROJECT_NAME} STATIC ${MV_BARCODE_GEN_INCLUDE_LIST} ${MV_BARCODE_GEN_SRC_LIST}) +else() + add_library(${PROJECT_NAME} SHARED ${MV_BARCODE_GEN_INCLUDE_LIST} ${MV_BARCODE_GEN_SRC_LIST}) +endif() + +target_link_libraries(${PROJECT_NAME} ${MV_COMMON_LIB_NAME}) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}) diff --git a/mv_barcode/barcode_generator_lic/include/mv_barcode_generate_lic.h b/mv_barcode/barcode_generator_lic/include/mv_barcode_generate_lic.h new file mode 100644 index 0000000..2076b0c --- /dev/null +++ b/mv_barcode/barcode_generator_lic/include/mv_barcode_generate_lic.h @@ -0,0 +1,107 @@ +/** + * 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_BARCODE_GENERATE_LIC_H__ +#define __TIZEN_MEDIAVISION_BARCODE_GENERATE_LIC_H__ + +#include "mv_barcode_generate.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file mv_barcode_generate_lic.h + * @brief This file contains the Media Vision barcode generate module API for + * the licensed module. + */ + +/** + * @brief Generates @ref mv_source_h with barcode image. + * + * @since_tizen 2.4 + * @param [in] engine_cfg The handle to the configuration of the engine + * @param [in] message The message to be encoded in the barcode + * @param [in] image_width The width of the generated image + * @param [in] image_height The height of the generated image + * @param [in] type Type of the barcode to be generated + * @param [in] qr_enc_mode Encoding mode for the message (only for QR codes; + * for 1D barcodes set this parameter to + * @ref MV_BARCODE_QR_MODE_UNAVAILABLE) + * @param [in] qr_ecc Error correction level (only for QR codes; for + * 1D barcodes set this parameter to + * @ref MV_BARCODE_QR_ECC_UNAVAILABLE) + * @param [in] qr_version QR code version (for 1D barcodes set this + * parameter to 0) + * @param [in] image The media source handle which will be used to + * fill by the buffer with generated image + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIA_VISION_ERROR_NONE Successful + * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter + * + * @see mv_barcode_generate_image_lic() + */ +int mv_barcode_generate_source_lic( + mv_engine_config_h engine_cfg, + const char *message, + mv_barcode_type_e type, + mv_barcode_qr_mode_e qr_enc_mode, + mv_barcode_qr_ecc_e qr_ecc, + int qr_version, + mv_source_h image); + +/** + * @brief Generates image file with barcode. + * + * @since_tizen 2.4 + * @param [in] engine_cfg The handle to the configuration of the engine + * @param [in] message The message to be encoded in the barcode + * @param [in] image_width The width of the generated image + * @param [in] image_height The height of the generated image + * @param [in] type Type of the barcode to be generated + * @param [in] qr_enc_mode Encoding mode for the message (only for QR codes; + * for 1D barcodes set this parameter to + * @ref MV_BARCODE_QR_MODE_UNAVAILABLE) + * @param [in] qr_ecc Error correction level (only for QR codes; for + * 1D barcodes set this parameter to + * @ref MV_BARCODE_QR_ECC_UNAVAILABLE) + * @param [in] qr_version QR code version (for 1D barcodes set this + * parameter to 0) + * @param [in] image_path The path to the file that has to be generated + * @param [in] image_format The format of the output image + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIA_VISION_ERROR_NONE Successful + * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter + * + * @see mv_barcode_generate_source_lic() + */ +int mv_barcode_generate_image_lic( + mv_engine_config_h engine_cfg, + const char *message, + int image_width, + int image_height, + mv_barcode_type_e type, + mv_barcode_qr_mode_e qr_enc_mode, + mv_barcode_qr_ecc_e qr_ecc, + int qr_version, + const char *image_path, + mv_barcode_image_format_e image_format); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIAVISION_BARCODE_GENERATE_LIC_H__ */ diff --git a/mv_barcode/barcode_generator_lic/src/mv_barcode_generate_lic.c b/mv_barcode/barcode_generator_lic/src/mv_barcode_generate_lic.c new file mode 100644 index 0000000..d57621f --- /dev/null +++ b/mv_barcode/barcode_generator_lic/src/mv_barcode_generate_lic.c @@ -0,0 +1,45 @@ +/** + * 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_barcode_generate_lic.h" + +int mv_barcode_generate_source_lic( + mv_engine_config_h engine_cfg, + const char *message, + mv_barcode_type_e type, + mv_barcode_qr_mode_e qr_enc_mode, + mv_barcode_qr_ecc_e qr_ecc, + int qr_version, + mv_source_h image) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED;; +} + +int mv_barcode_generate_image_lic( + mv_engine_config_h engine_cfg, + const char *message, + int image_width, + int image_height, + mv_barcode_type_e type, + mv_barcode_qr_mode_e qr_enc_mode, + mv_barcode_qr_ecc_e qr_ecc, + int qr_version, + const char *image_path, + mv_barcode_image_format_e image_format) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + diff --git a/mv_common/CMakeLists.txt b/mv_common/CMakeLists.txt new file mode 100644 index 0000000..64fa19a --- /dev/null +++ b/mv_common/CMakeLists.txt @@ -0,0 +1,36 @@ +project(${MV_COMMON_LIB_NAME}) +cmake_minimum_required(VERSION 2.6) + +set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG _DEBUG) + +if(NOT SKIP_WARNINGS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_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") + +file(GLOB MV_COMMON_INCLUDE_LIST "${PROJECT_SOURCE_DIR}/include/*.h") +file(GLOB MV_COMMON_SRC_LIST "${PROJECT_SOURCE_DIR}/src/*.cpp") + +find_package(OpenCV REQUIRED core highgui imgproc) + +if(NOT OpenCV_FOUND) + message(SEND_ERROR "Failed to find OpenCV") + return() +else() + include_directories(${OpenCV_INCLUDE_DIRS}) +endif() + +if(FORCED_STATIC_BUILD) + add_library(${PROJECT_NAME} STATIC ${MV_COMMON_INCLUDE_LIST} ${MV_COMMON_SRC_LIST}) +else() + add_library(${PROJECT_NAME} SHARED ${MV_COMMON_INCLUDE_LIST} ${MV_COMMON_SRC_LIST}) +endif() + +TARGET_LINK_LIBRARIES(${MV_COMMON_LIB_NAME} jpeg ${OpenCV_LIBS} capi-media-tool tbm json-c) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}) diff --git a/mv_common/include/EngineConfig.h b/mv_common/include/EngineConfig.h new file mode 100644 index 0000000..ac580c9 --- /dev/null +++ b/mv_common/include/EngineConfig.h @@ -0,0 +1,183 @@ +/** + * 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 __ENGINECONFIG_H__ +#define __ENGINECONFIG_H__ + +#include +#include + +#include "mv_common.h" + +/** + * @file EngineConfig.h + * @brief Engine Configuration class definition. + */ + +namespace MediaVision +{ +namespace Common +{ + +typedef std::map::const_iterator DictDblConstIter; +typedef std::map::const_iterator DictIntConstIter; +typedef std::map::const_iterator DictBoolConstIter; +typedef std::map::const_iterator DictStrConstIter; + +class EngineConfig +{ +public: + /** + * @brief Engine configuration constructor. + * @details Create new engine configuration dictionary and set default + * attributes values. + * + * @since_tizen 2.4 + */ + EngineConfig(); + + /** + * @brief Engine configuration destructor. + */ + virtual ~EngineConfig(); + + /** + * @brief Sets attribute with double value. + * + * @since_tizen 2.4 + * @param [in] key The string name of the attribute + * @param [in] value The double attribute value to be set + * @return @c MEDIA_VISION_ERROR_NONE on success,\n + * otherwise a negative error value + */ + int setAttribute(const std::string& key, const double value); + + /** + * @brief Sets attribute with integer value. + * + * @since_tizen 2.4 + * @param [in] key The string name of the attribute + * @param [in] value The integer attribute value to be set + * @return @c MEDIA_VISION_ERROR_NONE on success,\n + * otherwise a negative error value + */ + int setAttribute(const std::string& key, const int value); + + /** + * @brief Sets attribute with boolean value. + * + * @since_tizen 2.4 + * @param [in] key The string name of the attribute + * @param [in] value The boolean attribute value to be set + * @return @c MEDIA_VISION_ERROR_NONE on success,\n + * otherwise a negative error value + */ + int setAttribute(const std::string& key, const bool value); + + /** + * @brief Sets attribute with string value. + * + * @since_tizen 2.4 + * @param [in] key The string name of the attribute + * @param [in] value The string attribute value to be set + * @return @c MEDIA_VISION_ERROR_NONE on success,\n + * otherwise a negative error value + */ + int setAttribute(const std::string& key, const std::string& value); + + /** + * @brief Gets double attribute value by attribute name. + * + * @since_tizen 2.4 + * @param [in] key The string name of the attribute + * @param [out] value r The double attribute value to be obtained + * @return @c MEDIA_VISION_ERROR_NONE on success,\n + * otherwise a negative error value + * @retval #MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE If attribute with name @a key + * doesn't exist in the engine configuration dictionary + */ + int getDoubleAttribute(const std::string& key, double *value) const; + + /** + * @brief Gets integer attribute value by attribute name. + * + * @since_tizen 2.4 + * @param [in] key The string name of the attribute + * @param [out] value The integer attribute value to be obtained + * @return @c MEDIA_VISION_ERROR_NONE on success,\n + * otherwise a negative error value + * @retval #MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE If attribute with name @a key + * doesn't exist in the engine configuration dictionary + */ + int getIntegerAttribute(const std::string& key, int *value) const; + + /** + * @brief Gets boolean attribute value by attribute name. + * + * @since_tizen 2.4 + * @param [in] key The string name of the attribute + * @param [out] value The boolean attribute value to be obtained + * @return @c MEDIA_VISION_ERROR_NONE on success,\n + * otherwise a negative error value + * @retval #MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE If attribute with name @a key + * doesn't exist in the engine configuration dictionary + */ + int getBooleanAttribute(const std::string& key, bool *value) const; + + /** + * @brief Gets string attribute value by attribute name. + * + * @since_tizen 2.4 + * @param [in] key The string name of the attribute + * @param [out] value The string attribute value to be obtained + * @return @c MEDIA_VISION_ERROR_NONE on success,\n + * otherwise a negative error value + * @retval #MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE If attribute with name @a key + * doesn't exist in the engine configuration dictionary + */ + int getStringAttribute(const std::string& key, std::string *value) const; + +public: + static bool setDefaultConfigFilePath(const std::string& confFilePath); + + static const std::map& getDefaultDblDict(); + static const std::map& getDefaultIntDict(); + static const std::map& getDefaultBoolDict(); + static const std::map& getDefaultStrDict(); + static int cacheDictionaries( + bool isLazyCache = true, + std::string configFilePath = DefConfigFilePath); + +private: + std::map m_dblDict; + std::map m_intDict; + std::map m_boolDict; + std::map m_strDict; + +private: + static std::string DefConfigFilePath; + + static std::map DefDblDict; + static std::map DefIntDict; + static std::map DefBoolDict; + static std::map DefStrDict; + +}; + +} /* Common */ +} /* MediaVision */ + +#endif /* __ENGINECONFIG_H__ */ diff --git a/mv_common/include/MediaSource.h b/mv_common/include/MediaSource.h new file mode 100644 index 0000000..454f69f --- /dev/null +++ b/mv_common/include/MediaSource.h @@ -0,0 +1,148 @@ +/** + * 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 __MEDIASOURCE_H__ +#define __MEDIASOURCE_H__ + +// Need for a colorspace +#include + +/** + * @file MediaSource.h + * @brief This file contains the MediaSource class. + */ + +namespace MediaVision +{ +namespace Common +{ + +/** + * @class MediaSource + * @brief The Media Source container + * @details It is class which contains Media Source information. This class + * will be use in the Media Vision as simple image. + */ +class MediaSource +{ +public: + + /** + * @brief Creates a MediaSource. + * @details Default parameters values of the MediaSource will be: zero for + * width, height and buffer size; NULL for buffer; + * MEDIA_VISION_COLORSPACE_INVALID for colorspace. + * + * @since_tizen 2.4 + * + * @see MediaSource::~MediaSource() + */ + MediaSource(); + + /** + * @brief Destroys the MediaSource and releases all its resources. + * + * @since_tizen 2.4 + * + * @see MediaSource::MediaSource() + */ + virtual ~MediaSource(); + + /** + * @brief Clears the MediaSource. + * @details Releases all internal resources and set parameters to default values. + * + * @since_tizen 2.4 + * + * @see MediaSource::MediaSource() + * @see MediaSource::fill() + */ + void clear(void); + + /** + * @brief Fills the MediaSource based on the buffer and metadata. + * + * @since_tizen 2.4 + * @param [in] buffer The buffer of image data + * @param [in] bufferSize The buffer size + * @param [in] width The image width + * @param [in] height The image height + * @param [in] colorspace The image colorspace + * @return true if filled process is ok. Otherwise return false. + * + * @see MediaSource::MediaSource() + * @see MediaSource::clear() + */ + bool fill(const unsigned char *buffer, unsigned int bufferSize, unsigned int + width, unsigned int height, mv_colorspace_e colorspace); + + /** + * @brief Gets data buffer of the MediaSource. + * + * @since_tizen 2.4 + * @return Pointer to the data buffer. + */ + unsigned char *getBuffer(void) const; + + /** + * @brief Gets buffer size of the MediaSource. + * + * @since_tizen 2.4 + * @return Size of data buffer. + */ + unsigned int getBufferSize(void) const; + + /** + * @brief Gets image width of the MediaSource. + * + * @since_tizen 2.4 + * @return Width of image. + */ + unsigned int getWidth(void) const; + + /** + * @brief Gets image height of the MediaSource. + * + * @since_tizen 2.4 + * @return Height of image. + */ + unsigned int getHeight(void) const; + + /** + * @brief Gets image colorspace of the MediaSource. + * + * @since_tizen 2.4 + * @return Colorspace of image. + */ + mv_colorspace_e getColorspace(void) const; + +private: + + unsigned char *m_pBuffer; /**< The data buffer */ + + unsigned int m_bufferSize; /**< The buffer size */ + + unsigned int m_width; /**< The image width */ + + unsigned int m_height; /**< The image height */ + + mv_colorspace_e m_colorspace; /**< The image colorspace */ +}; + +} /* Common */ +} /* MediaVision */ + +#endif /* __MEDIASOURCE_H__ */ diff --git a/mv_common/include/mv_common_c.h b/mv_common/include/mv_common_c.h new file mode 100644 index 0000000..a7fa1bb --- /dev/null +++ b/mv_common/include/mv_common_c.h @@ -0,0 +1,492 @@ +/** + * 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_COMMON_C_H__ +#define __TIZEN_MEDIAVISION_COMMON_C_H__ + +#include "mv_common.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file mv_common_c.h + * @brief This file contains the Media Vision Common module API. + */ + +/** + * @brief Creates a source handle. + * + * @since_tizen 2.4 + * @remarks You must release @a source by using @ref mv_destroy_source_c(). + * @param [out] source A new handle to the 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 + * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory + * + * @see mv_destroy_source_c() + */ +int mv_create_source_c( + mv_source_h *source); + +/** + * @brief Destroys the source handle and releases all its resources. + * + * @since_tizen 2.4 + * @param [in] source The handle to the source 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 + * + * @see mv_create_source_c() + */ +int mv_destroy_source_c( + mv_source_h source); + +/** + * @brief Fills the media source based on the media packet. + * + * @since_tizen 2.4 + * @param [in,out] source The handle to the source + * @param [in] media_packet The handle to the media packet from which + * will be filled the 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 + * @retval #MEDIA_VISION_ERROR_INVALID_OPERATION Invalid operation + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported media format + * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory + * + * @pre Create a source handle by calling @ref mv_create_source_c() + * + * @see mv_create_source_c() + * @see mv_destroy_source_c() + */ +int mv_source_fill_by_media_packet_c( + mv_source_h source, + media_packet_h media_packet); + +/** + * @brief Fills the media source based on the buffer and metadata. + * + * @since_tizen 2.4 + * @param [in,out] source The handle to the source + * @param [in] data_buffer The buffer of image data + * @param [in] buffer_size The buffer size + * @param [in] image_width The image width + * @param [in] image_height The image height + * @param [in] image_colorspace The image colorspace + * @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 + * + * @pre Create a source handle by calling @ref mv_create_source_c() + * + * @see mv_source_clear_c() + */ +int mv_source_fill_by_buffer_c( + mv_source_h source, + unsigned char *data_buffer, + unsigned int buffer_size, + unsigned int image_width, + unsigned int image_height, + mv_colorspace_e image_colorspace); + +/** + * @brief Clears the buffer of the media source. + * + * @since_tizen 2.4 + * @param [in] source The handle to the 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 + * + * @see mv_source_fill_by_buffer_c() + */ +int mv_source_clear_c( + mv_source_h source); + +/** + * @brief Gets buffer of the media source. + * + * @since_tizen 2.4 + * @remarks Note that the retrieved buffer will be destroyed when + * @ref mv_destroy_source_c() or @ref mv_source_clear_c() function + * is called for the @a source. + * + * @param [in] source The handle to the source + * @param [out] data_buffer The buffer of the source + * @param [out] buffer_size The size of 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 + * + * @see mv_source_get_width_c() + * @see mv_source_get_height_c() + * @see mv_source_get_colorspace_c() + */ +int mv_source_get_buffer_c( + mv_source_h source, + unsigned char **data_buffer, + unsigned int *buffer_size); + +/** + * @brief Gets height of the media source. + * + * @since_tizen 2.4 + * @param [in] source The handle to the source + * @param [out] image_height The height of the 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 + * + * @see mv_source_get_width_c() + * @see mv_source_get_colorspace_c() + * @see mv_source_get_buffer_c() + */ +int mv_source_get_height_c( + mv_source_h source, + unsigned int *image_height); + +/** + * @brief Gets width of the media source. + * + * @since_tizen 2.4 + * @param [in] source The handle to the source + * @param [out] image_width The width of the 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 + * + * @see mv_source_get_height_c() + * @see mv_source_get_colorspace_c() + * @see mv_source_get_buffer_c() + */ +int mv_source_get_width_c( + mv_source_h source, + unsigned int *image_width); + +/** + * @brief Gets colorspace of the media source. + * + * @since_tizen 2.4 + * @param [in] source The handle to the source + * @param [out] image_colorspace The colorspace of the 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 + * + * @see mv_source_get_width_c() + * @see mv_source_get_height_c() + * @see mv_source_get_buffer_c() + */ +int mv_source_get_colorspace_c( + mv_source_h source, + mv_colorspace_e *image_colorspace); + +/** + * @brief Creates the handle to the configuration of engine. + * + * @since_tizen 2.4 + * @param [out] engine_cfg The handle to the engine to be created + * @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 + * + * @see mv_engine_config_h + * @see mv_destroy_engine_config_c() + * @see mv_engine_config_set_double_attribute_c() + * @see mv_engine_config_set_int_attribute_c() + * @see mv_engine_config_set_bool_attribute_c() + * @see mv_engine_config_set_string_attribute_c() + * @see mv_engine_config_get_double_attribute_c() + * @see mv_engine_config_get_int_attribute_c() + * @see mv_engine_config_get_bool_attribute_c() + * @see mv_engine_config_get_string_attribute_c() + */ +int mv_create_engine_config_c( + mv_engine_config_h *engine_cfg); + +/** + * @brief Destroys the engine configuration handle and releases all its + * resources. + * + * @since_tizen 2.4 + * @param [in] engine_cfg The handle to the engine configuration + * 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 + * + * @see mv_engine_config_h + * @see mv_create_engine_config_c() + */ +int mv_destroy_engine_config_c( + mv_engine_config_h engine_cfg); + +/** + * @brief Sets the double attribute to the configuration. + * + * @since_tizen 2.4 + * @param [in] engine_cfg Engine configuration for which @a value has + * to be set + * @param [in] name String key of the attribute will be used for + * storing the @a value into configuration + * dictionary + * @param [in] value The double value of the attribute + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIA_VISION_ERROR_NONE Successful + * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter + * + * @see mv_engine_config_get_double_attribute_c() + * @see mv_engine_config_set_int_attribute_c() + * @see mv_engine_config_set_bool_attribute_c() + * @see mv_engine_config_set_string_attribute_c() + */ +int mv_engine_config_set_double_attribute_c( + mv_engine_config_h engine_cfg, + const char *name, + double value); + +/** + * @brief Sets the integer attribute to the configuration. + * + * @since_tizen 2.4 + * @param [in] engine_cfg Engine configuration for which @a value has + * to be set + * @param [in] name String key of the attribute will be used for + * storing the @a value into configuration + * dictionary + * @param [in] value The integer value of the attribute + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIA_VISION_ERROR_NONE Successful + * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter + * + * @see mv_engine_config_get_int_attribute_c() + * @see mv_engine_config_set_double_attribute_c() + * @see mv_engine_config_set_bool_attribute_c() + * @see mv_engine_config_set_string_attribute_c() + */ +int mv_engine_config_set_int_attribute_c( + mv_engine_config_h engine_cfg, + const char *name, + int value); + +/** + * @brief Sets the boolean attribute to the configuration. + * + * @since_tizen 2.4 + * @param [in] engine_cfg Engine configuration for which @a value has + * to be set + * @param [in] name String key of the attribute will be used for + * storing the @a value into configuration + * dictionary + * @param [in] value The boolean value of the attribute + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIA_VISION_ERROR_NONE Successful + * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter + * + * @see mv_engine_config_get_bool_attribute_c() + * @see mv_engine_config_set_double_attribute_c() + * @see mv_engine_config_set_int_attribute_c() + * @see mv_engine_config_set_string_attribute_c() + */ +int mv_engine_config_set_bool_attribute_c( + mv_engine_config_h engine_cfg, + const char *name, + bool attribute); + +/** + * @brief Sets the string attribute to the configuration. + * + * @since_tizen 2.4 + * @param [in] engine_cfg Engine configuration for which @a value has + * to be set + * @param [in] name String key of the attribute will be used for + * storing the @a value into configuration + * dictionary + * @param [in] value The string value of the attribute + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIA_VISION_ERROR_NONE Successful + * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter + * + * @see mv_engine_config_get_string_attribute_c() + * @see mv_engine_config_set_double_attribute_c() + * @see mv_engine_config_set_int_attribute_c() + * @see mv_engine_config_set_bool_attribute_c() + */ +int mv_engine_config_set_string_attribute_c( + mv_engine_config_h engine_cfg, + const char *name, + const char *value); + +/** + * @brief Gets the double attribute from the configuration dictionary. + * + * @since_tizen 2.4 + * @param [in] engine_cfg Engine configuration from which @a value + * has to be gotten + * @param [in] name String key of the attribute will be used for + * getting the @a value from the + * configuration dictionary + * @param [out] value The attribute to be filled with double value + * from dictionary + * @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_KEY_NOT_AVAILABLE Parameter key isn't available + * + * @see mv_engine_config_set_double_attribute_c() + * @see mv_engine_config_get_int_attribute_c() + * @see mv_engine_config_get_bool_attribute_c() + * @see mv_engine_config_get_string_attribute_c() + */ +int mv_engine_config_get_double_attribute_c( + mv_engine_config_h engine_cfg, + const char *name, + double *value); + +/** + * @brief Gets the integer attribute from the configuration dictionary. + * + * @since_tizen 2.4 + * @param [in] engine_cfg Engine configuration from which @a value + * has to be gotten + * @param [in] name String key of the attribute will be used for + * getting the @a value from the + * configuration dictionary + * @param [out] value The attribute to be filled with integer value + * from dictionary + * @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_KEY_NOT_AVAILABLE Parameter key isn't available + * + * @see mv_engine_config_set_int_attribute_c() + * @see mv_engine_config_get_double_attribute_c() + * @see mv_engine_config_get_bool_attribute_c() + * @see mv_engine_config_get_string_attribute_c() + */ +int mv_engine_config_get_int_attribute_c( + mv_engine_config_h engine_cfg, + const char *name, + int *value); + +/** + * @brief Gets the boolean attribute from the configuration dictionary. + * + * @since_tizen 2.4 + * @param [in] engine_cfg Engine configuration from which @a value + * has to be gotten + * @param [in] name String key of the attribute will be used for + * getting the @a value from the + * configuration dictionary + * @param [out] value The attribute to be filled with boolean value + * from dictionary + * @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_KEY_NOT_AVAILABLE Parameter key isn't available + * + * @see mv_engine_config_set_bool_attribute_c() + * @see mv_engine_config_get_double_attribute_c() + * @see mv_engine_config_get_int_attribute_c() + * @see mv_engine_config_get_string_attribute_c() + */ +int mv_engine_config_get_bool_attribute_c( + mv_engine_config_h engine_cfg, + const char *name, + bool *value); + +/** + * @brief Gets the string attribute from the configuration dictionary. + * + * @since_tizen 2.4 + * @remarks Function allocates memory required for output @a value, so + * it has to be removed by the user himself. + * @param [in] engine_cfg Engine configuration from which @a value + * has to be gotten + * @param [in] name String key of the attribute will be used for + * getting the @a value from the + * configuration dictionary + * @param [out] value The attribute to be filled with string value + * from dictionary + * @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_KEY_NOT_AVAILABLE Parameter key isn't available + * + * @see mv_engine_config_set_string_attribute_c() + * @see mv_engine_config_get_double_attribute_c() + * @see mv_engine_config_get_int_attribute_c() + * @see mv_engine_config_get_bool_attribute_c() + */ +int mv_engine_config_get_string_attribute_c( + mv_engine_config_h engine_cfg, + const char *name, + char **value); + +/** + * @brief Traverses the list of supported attribute names and types. + * @details Using this function names of supported attributes can be obtained. + * Names of the attributes can be used with @ref mv_engine_config_h + * related getters and setters to get/set appropriate attribute values. + * + * @since_tizen 2.4 + * @remarks If @a callback is called zero times after + * @ref mv_engine_config_foreach_supported_attribute() call, then + * engine configuration is not supported and setting of attributes will + * cause no effect. In this case for all Media Vision functions which + * require @ref mv_engine_config_h handle as in parameter this + * parameter can be set NULL. + * @remarks If @a callback is called at least once, then attribute names and + * types obtained in the @ref mv_supported_attribute_cb callback can be + * changed after mv_engine_config_h handle creation (with + * @ref mv_create_engine_config_c() function) by corresponding setters. + * Although, if attributes aren't changed by setters, then default + * values will be used.\n + * Changing of attribute values will affect internal functionality + * provided by concrete library underlying Media Vision API. + * @param [in] callback The iteration callback function + * @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 + * (@a callback can't be NULL) + * @retval #MEDIA_VISION_ERROR_NO_DATA Can't determine list of supported attributes + * + * @see mv_engine_config_set_double_attribute_c() + * @see mv_engine_config_set_int_attribute_c() + * @see mv_engine_config_set_bool_attribute_c() + * @see mv_engine_config_set_string_attribute_c() + * @see mv_engine_config_get_double_attribute_c() + * @see mv_engine_config_get_int_attribute_c() + * @see mv_engine_config_get_bool_attribute_c() + * @see mv_engine_config_get_string_attribute_c() + */ +int mv_engine_config_foreach_supported_attribute_c( + mv_supported_attribute_cb callback, + void *user_data); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIAVISION_COMMON_C_H__ */ diff --git a/mv_common/src/EngineConfig.cpp b/mv_common/src/EngineConfig.cpp new file mode 100644 index 0000000..3faedf1 --- /dev/null +++ b/mv_common/src/EngineConfig.cpp @@ -0,0 +1,327 @@ +/** + * 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 "EngineConfig.h" + +#include + +#include + +/** + * @file EngineConfig.cpp + * @brief Engine Configuration class methods implementation. + */ + +namespace MediaVision +{ +namespace Common +{ + +std::string EngineConfig::DefConfigFilePath = + std::string("/usr/share/config/capi-media-vision/media-vision-config.json"); + +std::map EngineConfig::DefDblDict; +std::map EngineConfig::DefIntDict; +std::map EngineConfig::DefBoolDict; +std::map EngineConfig::DefStrDict; + +EngineConfig::EngineConfig() +{ + // Force load default attributes from configuration file + cacheDictionaries(false); + + // Insert default attribute values into creating engine configuration + m_dblDict.insert(getDefaultDblDict().begin(), getDefaultDblDict().end()); + m_intDict.insert(getDefaultIntDict().begin(), getDefaultIntDict().end()); + m_boolDict.insert(getDefaultBoolDict().begin(), getDefaultBoolDict().end()); + m_strDict.insert(getDefaultStrDict().begin(), getDefaultStrDict().end()); +} + +EngineConfig::~EngineConfig() +{ + ; /* NULL */ +} + +int EngineConfig::setAttribute(const std::string& key, const double value) +{ + LOGI("Set double attribute for the engine config %p. [%s] = %f", + this, key.c_str(), value); + + if (m_dblDict.find(key) == m_dblDict.end()) + { + LOGE("Double attribute [%s] can't be set because isn't supported", key.c_str()); + return MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE; + } + + m_dblDict[key] = value; + + return MEDIA_VISION_ERROR_NONE; +} + +int EngineConfig::setAttribute(const std::string& key, const int value) +{ + LOGI("Set integer attribute for the engine config %p. [%s] = %i", + this, key.c_str(), value); + + if (m_intDict.find(key) == m_intDict.end()) + { + LOGE("Integer attribute [%s] can't be set because isn't supported", key.c_str()); + return MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE; + } + + m_intDict[key] = value; + + return MEDIA_VISION_ERROR_NONE; +} + +int EngineConfig::setAttribute(const std::string& key, const bool value) +{ + LOGI("Set boolean attribute for the engine config %p. [%s] = %s", + this, key.c_str(), value ? "TRUE" : "FALSE"); + + if (m_boolDict.find(key) == m_boolDict.end()) + { + LOGE("Boolean attribute [%s] can't be set because isn't supported", key.c_str()); + return MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE; + } + + m_boolDict[key] = value; + + return MEDIA_VISION_ERROR_NONE; +} + +int EngineConfig::setAttribute(const std::string& key, const std::string& value) +{ + LOGI("Set string attribute for the engine config %p. [%s] = %s", + this, key.c_str(), value.c_str()); + + if (m_strDict.find(key) == m_strDict.end()) + { + LOGE("String attribute [%s] can't be set because isn't supported", key.c_str()); + return MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE; + } + + m_strDict[key] = value; + + return MEDIA_VISION_ERROR_NONE; +} + +int EngineConfig::getDoubleAttribute(const std::string& key, double *value) const +{ + DictDblConstIter dictIter = m_dblDict.find(key); + if (dictIter == m_dblDict.end()) + { + LOGE("Attempt to access to the unsupported double attribute [%s] " + "of the engine config %p", key.c_str(), this); + return MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE; + } + + LOGD("Get double attribute from the engine config %p. [%s] = %f", + this, dictIter->first.c_str(), dictIter->second); + + *value = dictIter->second; + + return MEDIA_VISION_ERROR_NONE; +} + +int EngineConfig::getIntegerAttribute(const std::string& key, int *value) const +{ + DictIntConstIter dictIter = m_intDict.find(key); + if (dictIter == m_intDict.end()) + { + LOGE("Attempt to access to the unsupported integer attribute [%s] " + "of the engine config %p", key.c_str(), this); + return MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE; + } + + LOGD("Get integer attribute from the engine config %p. [%s] = %i", + this, dictIter->first.c_str(), dictIter->second); + + *value = dictIter->second; + + return MEDIA_VISION_ERROR_NONE; +} + +int EngineConfig::getBooleanAttribute(const std::string& key, bool *value) const +{ + DictBoolConstIter dictIter = m_boolDict.find(key); + if (dictIter == m_boolDict.end()) + { + LOGE("Attempt to access to the unsupported boolean attribute [%s] " + "of the engine config %p", key.c_str(), this); + return MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE; + } + + LOGD("Get boolean attribute from the engine config %p. [%s] = %s", + this, dictIter->first.c_str(), dictIter->second ? "TRUE" : "FALSE"); + + *value = dictIter->second; + + return MEDIA_VISION_ERROR_NONE; +} + +int EngineConfig::getStringAttribute(const std::string& key, std::string *value) const +{ + DictStrConstIter dictIter = m_strDict.find(key); + if (dictIter == m_strDict.end()) + { + LOGE("Attempt to access to the unsupported string attribute [%s] " + "of the engine config %p", key.c_str(), this); + return MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE; + } + + LOGD("Get string attribute from the engine config %p. [%s] = %s", + this, dictIter->first.c_str(), dictIter->second.c_str()); + + *value = dictIter->second; + + return MEDIA_VISION_ERROR_NONE; +} + +// static + +bool EngineConfig::setDefaultConfigFilePath(const std::string& confFilePath) +{ + if (0 != DefConfigFilePath.compare(confFilePath)) + { + DefConfigFilePath = confFilePath; + return true; + } + + return false; +} + +const std::map& EngineConfig::getDefaultDblDict() +{ + cacheDictionaries(); + + return DefDblDict; +} + +const std::map& EngineConfig::getDefaultIntDict() +{ + cacheDictionaries(); + + return DefIntDict; +} + +const std::map& EngineConfig::getDefaultBoolDict() +{ + cacheDictionaries(); + + return DefBoolDict; +} + +const std::map& EngineConfig::getDefaultStrDict() +{ + cacheDictionaries(); + + return DefStrDict; +} + +int EngineConfig::cacheDictionaries(bool isLazyCache, std::string configFilePath) +{ + static bool isCached = false; + if (!isLazyCache || !isCached) + { + LOGI("Start to cache default attributes from engine configuration file."); + + DefDblDict.clear(); + DefIntDict.clear(); + DefBoolDict.clear(); + DefStrDict.clear(); + + json_object *jobj = json_object_from_file(configFilePath.c_str()); + + enum json_type type = json_object_get_type(jobj); + if (json_type_object != type) + { + LOGE("Can't parse engine config file. Incorrect json markup. " + "Supported attributes can't be determined."); + json_object_put(jobj); + return MEDIA_VISION_ERROR_NO_DATA; + } + + json_object *pAttributesObj = json_object_object_get(jobj, "attributes"); + type = json_object_get_type(pAttributesObj); + if (json_type_array != type) + { + LOGE("Can't parse engine config file. Incorrect json markup. " + "Supported attributes can't be determined."); + json_object_put(jobj); + return MEDIA_VISION_ERROR_NO_DATA; + } + + const int attrNum = json_object_array_length(pAttributesObj); + + for (int attrInd = 0; attrInd < attrNum; ++attrInd) + { + json_object *pAttrObj = + json_object_array_get_idx(pAttributesObj, attrInd); + type = json_object_get_type(pAttrObj); + + json_object *pAttrNameObj = NULL; + json_object *pAttrTypeObj = NULL; + json_object *pAttrValueObj = NULL; + + if (json_type_object != type || + !json_object_object_get_ex(pAttrObj, "name", &pAttrNameObj) || + !json_object_object_get_ex(pAttrObj, "type", &pAttrTypeObj) || + !json_object_object_get_ex(pAttrObj, "value", &pAttrValueObj)) + { + LOGW("Attribute %i wasn't parsed from json file.", attrInd); + continue; + } + + const char *nameStr = json_object_get_string(pAttrNameObj); + const char *typeStr = json_object_get_string(pAttrTypeObj); + + if (0 == strcmp("double", typeStr)) + { + DefDblDict[std::string(nameStr)] = + json_object_get_double(pAttrValueObj); + } + else if (0 == strcmp("integer", typeStr)) + { + DefIntDict[std::string(nameStr)] = + json_object_get_int(pAttrValueObj); + } + else if (0 == strcmp("boolean", typeStr)) + { + DefBoolDict[std::string(nameStr)] = + json_object_get_boolean(pAttrValueObj) ? true : false; + } + else if (0 == strcmp("string", typeStr)) + { + DefStrDict[std::string(nameStr)] = + json_object_get_string(pAttrValueObj); + } + else + { + LOGW("Attribute %i:%s wasn't parsed from json file. Type isn't supported.", attrInd, nameStr); + continue; + } + } + + json_object_put(jobj); + isCached = true; + } + + return MEDIA_VISION_ERROR_NONE; +} + +} /* namespace Common */ +} /* namespace MediaVision */ diff --git a/mv_common/src/MediaSource.cpp b/mv_common/src/MediaSource.cpp new file mode 100644 index 0000000..1288625 --- /dev/null +++ b/mv_common/src/MediaSource.cpp @@ -0,0 +1,124 @@ +/** + * 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 "MediaSource.h" + +#include + +#include + +namespace MediaVision +{ +namespace Common +{ + +MediaSource::MediaSource() : m_pBuffer (NULL), m_bufferSize (0), m_width (0), + m_height (0), m_colorspace (MEDIA_VISION_COLORSPACE_INVALID) +{ +} + +MediaSource::~MediaSource() +{ + clear(); +} + +void MediaSource::clear(void) +{ + if (m_pBuffer != NULL) + { + LOGD("Delete internal buffer for media source %p", this); + delete[] m_pBuffer; + } + LOGD("Set defaults for media source %p : buffer = NULL; " + "bufferSize = 0; width = 0; height = 0; " + "colorspace = MEDIA_VISION_COLORSPACE_INVALID", this); + m_pBuffer = NULL; + m_bufferSize = 0; + m_width = 0; + m_height = 0; + m_colorspace = MEDIA_VISION_COLORSPACE_INVALID; +} + +bool MediaSource::fill(const unsigned char *buffer, unsigned int bufferSize, + unsigned int width, unsigned int height, mv_colorspace_e colorspace) +{ + if (bufferSize == 0 || buffer == NULL) + { + return false; + } + + LOGD("Call clear() first for media source %p", this); + clear(); + + try + { + LOGD("Allocate memory for buffer in media source %p", this); + m_pBuffer = new unsigned char[bufferSize]; + } + catch(...) + { + LOGE("Memory allocating for buffer in media source %p failed!", this); + m_pBuffer = NULL; + return false; + } + + LOGD("Copy data from external buffer (%p) to the internal buffer (%p) of " + "media source %p", buffer, m_pBuffer, this); + std::memcpy(m_pBuffer, buffer, bufferSize); + + LOGD("Assign new size of the internal buffer of media source %p. " + "New size is %ui.", this, bufferSize); + m_bufferSize = bufferSize; + + LOGD("Assign new size (%ui x %ui) of the internal buffer image for " + "the media source %p", width, height, this); + m_width = width; + m_height = height; + + LOGD("Assign new colorspace (%i) of the internal buffer image for " + "the media source %p", colorspace, this); + m_colorspace = colorspace; + + return true; +} + +unsigned char *MediaSource::getBuffer(void) const +{ + return m_pBuffer; +} + +unsigned int MediaSource::getBufferSize(void) const +{ + return m_bufferSize; +} + +unsigned int MediaSource::getWidth(void) const +{ + return m_width; +} + +unsigned int MediaSource::getHeight(void) const +{ + return m_height; +} + +mv_colorspace_e MediaSource::getColorspace(void) const +{ + return m_colorspace; +} + +} /* Common */ +} /* MediaVision */ diff --git a/mv_common/src/mv_common_c.cpp b/mv_common/src/mv_common_c.cpp new file mode 100644 index 0000000..ececf20 --- /dev/null +++ b/mv_common/src/mv_common_c.cpp @@ -0,0 +1,644 @@ +/** + * 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_common_c.h" + +#include "MediaSource.h" +#include "EngineConfig.h" + +#include + +#include +#include + +int mv_create_source_c( + mv_source_h *source_ptr) +{ + if (source_ptr == NULL) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + LOGD("Creating media vision source"); + (*source_ptr) = ((mv_source_h)new MediaVision::Common::MediaSource()); + + if (*source_ptr == NULL) + { + LOGE("Failed to create media vision source"); + return MEDIA_VISION_ERROR_OUT_OF_MEMORY; + } + LOGD("Media vision source [%p] has been created", *source_ptr); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_destroy_source_c( + mv_source_h source) +{ + if (!source) + { + LOGE("Media source can't be destroyed because handle is NULL"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + LOGD("Destroying media vision source [%p]", source); + delete ((MediaVision::Common::MediaSource*)source); + LOGD("Media vision source has been destroyed"); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_source_fill_by_media_packet_c( + mv_source_h source, + media_packet_h media_packet) +{ + if (!source || !media_packet) + { + LOGE("Media source can't be filled by media_packet handle because " + "one of the source or media_packet handles is NULL. " + "source = %p; media_packet = %p", source, media_packet); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + bool is_video = false; + int image_width = 0; + int image_height = 0; + media_format_h format = NULL; + media_format_mimetype_e mimetype = MEDIA_FORMAT_I420; + unsigned char *data_buffer = NULL; + uint64_t buffer_size = 0; + mv_colorspace_e image_colorspace = MEDIA_VISION_COLORSPACE_INVALID; + + int ret = media_packet_is_video(media_packet, &is_video); + if (ret != MEDIA_PACKET_ERROR_NONE) + { + LOGE("media_packet_is_video() failed, mv_source_h fill skipped"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (!is_video) + { + LOGE("Media packet isn't video, mv_source_h fill skipped"); + return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT; + } + + ret = media_packet_get_format(media_packet, &format); + if (ret != MEDIA_PACKET_ERROR_NONE) + { + LOGE("media_packet_get_format() failed, mv_source_h fill skipped"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + ret = media_format_get_video_info( + format, &mimetype, &image_width, &image_height, NULL, NULL); + if (ret != MEDIA_PACKET_ERROR_NONE) + { + LOGE("media_format_get_video_info() failed, mv_source_h fill skipped"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (mimetype > MEDIA_FORMAT_H261 && mimetype <= MEDIA_FORMAT_MPEG4_ASP) + { + LOGE("Media format mimetype is not the raw video, mv_source_h fill skipped"); + return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT; + } + + switch (mimetype) + { + case MEDIA_FORMAT_I420: + image_colorspace = MEDIA_VISION_COLORSPACE_I420; + break; + case MEDIA_FORMAT_NV12: + image_colorspace = MEDIA_VISION_COLORSPACE_NV12; + break; + case MEDIA_FORMAT_YV12: + image_colorspace = MEDIA_VISION_COLORSPACE_YV12; + break; + case MEDIA_FORMAT_NV21: + image_colorspace = MEDIA_VISION_COLORSPACE_NV21; + break; + case MEDIA_FORMAT_YUYV: + image_colorspace = MEDIA_VISION_COLORSPACE_YUYV; + break; + case MEDIA_FORMAT_UYVY: + image_colorspace = MEDIA_VISION_COLORSPACE_UYVY; + break; + case MEDIA_FORMAT_422P: + image_colorspace = MEDIA_VISION_COLORSPACE_422P; + break; + case MEDIA_FORMAT_RGB565: + image_colorspace = MEDIA_VISION_COLORSPACE_RGB565; + break; + case MEDIA_FORMAT_RGB888: + image_colorspace = MEDIA_VISION_COLORSPACE_RGB888; + break; + case MEDIA_FORMAT_RGBA: + image_colorspace = MEDIA_VISION_COLORSPACE_RGBA; + break; + default: + LOGE("Format of the media packet buffer is not supported by media " + "vision source (media_format_h mimetype=%i)", mimetype); + return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT; + } + + ret = media_packet_get_buffer_data_ptr(media_packet, (void**)&data_buffer); + if (ret != MEDIA_PACKET_ERROR_NONE) + { + LOGE("media_packet_get_buffer_data_ptr() failed, mv_source_h fill skipped"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + ret = media_packet_get_buffer_size(media_packet, &buffer_size); + if (ret != MEDIA_PACKET_ERROR_NONE) + { + LOGE("media_packet_get_buffer_size() failed, mv_source_h fill skipped"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (!((MediaVision::Common::MediaSource*)source)->fill(data_buffer, + buffer_size, (unsigned int)image_width, (unsigned int)image_height, image_colorspace)) + { + LOGE("mv_source_h filling from media_packet_h failed"); + return MEDIA_VISION_ERROR_OUT_OF_MEMORY; + } + + LOGD("Media source has been filled from media packet"); + return MEDIA_VISION_ERROR_NONE; +} + +int mv_source_fill_by_buffer_c( + mv_source_h source, + unsigned char *data_buffer, + unsigned int buffer_size, + unsigned int image_width, + unsigned int image_height, + mv_colorspace_e image_colorspace) +{ + if (!source || buffer_size == 0 || data_buffer == NULL) + { + LOGE("Media source can't be filled by buffer because " + "one of the source or data_buffer is NULL or buffer_size = 0. " + "source = %p; data_buffer = %p; buffer_size = %u", + source, data_buffer, buffer_size); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (!((MediaVision::Common::MediaSource*)source)->fill(data_buffer, + buffer_size, image_width, image_height, image_colorspace)) + { + LOGE("mv_source_h filling from buffer failed"); + return MEDIA_VISION_ERROR_OUT_OF_MEMORY; + } + + LOGD("Media source has been filled from buffer"); + return MEDIA_VISION_ERROR_NONE; +} + +int mv_source_clear_c( + mv_source_h source) +{ + if (!source) + { + LOGE("Media source can't be cleared because source handle is NULL"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + LOGD("Clear media vision source [%p]", source); + ((MediaVision::Common::MediaSource*)source)->clear(); + LOGD("Media vision source [%p] has been cleared", source); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_source_get_buffer_c( + mv_source_h source, + unsigned char **buffer, + unsigned int *size) +{ + if (!source) + { + LOGE("Impossible to get buffer for NULL mv_source_h handle"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + LOGD("Get media vision source [%p] buffer and buffer size to be returned", source); + *buffer = ((MediaVision::Common::MediaSource*)source)->getBuffer(); + *size = ((MediaVision::Common::MediaSource*)source)->getBufferSize(); + LOGD("Media vision source [%p] buffer (%p) and buffer size (%ui) has been returned", source, buffer, *size); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_source_get_height_c( + mv_source_h source, + unsigned int *height) +{ + if (!source) + { + LOGE("Impossible to get height for NULL mv_source_h handle"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + LOGD("Get media vision source [%p] height to be returned", source); + *height = ((MediaVision::Common::MediaSource*)source)->getHeight(); + LOGD("Media vision source [%p] height (%ui) has been returned", source, *height); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_source_get_width_c( + mv_source_h source, + unsigned int *width) +{ + if (!source) + { + LOGE("Impossible to get width for NULL mv_source_h handle"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + LOGD("Get media vision source [%p] width to be returned", source); + *width = ((MediaVision::Common::MediaSource*)source)->getWidth(); + LOGD("Media vision source [%p] width (%ui) has been returned", source, *width); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_source_get_colorspace_c( + mv_source_h source, + mv_colorspace_e *colorspace) +{ + if (!source) + { + LOGE("Impossible to get colorspace for NULL mv_source_h handle"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + LOGD("Get media vision source [%p] colorspace to be returned", source); + *colorspace = ((MediaVision::Common::MediaSource*)source)->getColorspace(); + LOGD("Media vision source [%p] colorspace (%i) has been returned", source, *colorspace); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_create_engine_config_c( + mv_engine_config_h *engine_cfg) +{ + if (engine_cfg == NULL) + { + LOGE("Impossible to create mv_engine_config_h handle"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + + LOGD("Creating media vision engine config"); + (*engine_cfg) = ((mv_engine_config_h)new MediaVision::Common::EngineConfig()); + LOGD("Media vision engine config [%p] has been created", *engine_cfg); + + if (*engine_cfg == NULL) + { + LOGE("Failed to create mv_engine_config_h handle"); + return MEDIA_VISION_ERROR_OUT_OF_MEMORY; + } + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_destroy_engine_config_c( + mv_engine_config_h engine_cfg) +{ + if (!engine_cfg) + { + LOGE("Impossible to destroy NULL mv_engine_config_h handle"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + LOGD("Destroying media vision engine config [%p]", engine_cfg); + delete ((MediaVision::Common::EngineConfig*)engine_cfg); + LOGD("Media vision engine config has been destroyed"); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_engine_config_set_double_attribute_c( + mv_engine_config_h engine_cfg, + const char *name, + double value) +{ + if (!engine_cfg || name == NULL) + { + LOGE("Impossible to set attribute. One of the required parameters is " + "NULL. engine_cfg = %p; name = %p;", + engine_cfg, name); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + int ret = ((MediaVision::Common::EngineConfig*)engine_cfg)->setAttribute( + std::string(name), value); + + if (ret != MEDIA_VISION_ERROR_NONE) + { + LOGE("Failed to set attribute [%s] with value %f. Error code (0x%08x)", + name, value, ret); + return ret; + } + + LOGD("Attribute [%s] (value %f) has been set", name, value); + return ret; +} + +int mv_engine_config_set_int_attribute_c( + mv_engine_config_h engine_cfg, + const char *name, + int value) +{ + if (!engine_cfg || name == NULL) + { + LOGE("Impossible to set attribute. One of the required parameters is " + "NULL. engine_cfg = %p; name = %p;", + engine_cfg, name); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + int ret = ((MediaVision::Common::EngineConfig*)engine_cfg)->setAttribute( + std::string(name), value); + + if (ret != MEDIA_VISION_ERROR_NONE) + { + LOGE("Failed to set attribute [%s] with value %i. Error code (0x%08x)", + name, value, ret); + return ret; + } + + LOGD("Attribute [%s] (value %i) has been set", name, value); + + return ret; +} + +int mv_engine_config_set_bool_attribute_c( + mv_engine_config_h engine_cfg, + const char *name, + bool value) +{ + if (!engine_cfg || name == NULL) + { + LOGE("Impossible to set attribute. One of the required parameters is " + "NULL. engine_cfg = %p; name = %p;", + engine_cfg, name); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + int ret = ((MediaVision::Common::EngineConfig*)engine_cfg)->setAttribute( + std::string(name), value); + + if (ret != MEDIA_VISION_ERROR_NONE) + { + LOGE("Failed to set attribute [%s] with value %s. Error code (0x%08x)", + name, value ? "TRUE" : "FALSE", ret); + return ret; + } + + LOGD("Attribute [%s] (value %s) has been set", + name, value ? "TRUE" : "FALSE"); + return ret; +} + +int mv_engine_config_set_string_attribute_c( + mv_engine_config_h engine_cfg, + const char *name, + const char *value) +{ + if (!engine_cfg || name == NULL || value == NULL) + { + LOGE("Impossible to set attribute. One of the required parameters is " + "NULL. engine_cfg = %p; name = %p; value = %p;", + engine_cfg, name, value); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + int ret = ((MediaVision::Common::EngineConfig*)engine_cfg)->setAttribute( + std::string(name), std::string(value)); + + if (ret != MEDIA_VISION_ERROR_NONE) + { + LOGE("Failed to set attribute [%s] with value %s. Error code (0x%08x)", + name, value, ret); + return ret; + } + + LOGD("Attribute [%s] (value %s) has been set", name, value); + return ret; +} + +int mv_engine_config_get_double_attribute_c( + mv_engine_config_h engine_cfg, + const char *name, + double *value) +{ + if (!engine_cfg || name == NULL || value == NULL) + { + LOGE("Impossible to get attribute. One of the required parameters is " + "NULL. engine_cfg = %p; name = %p; value = %p;", + engine_cfg, name, value); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + int ret = ((MediaVision::Common::EngineConfig*)engine_cfg)->getDoubleAttribute( + std::string(name), value); + + if (ret != MEDIA_VISION_ERROR_NONE) + { + LOGE("Failed to get attribute [%s]. Error code (0x%08x)", + name, ret); + return ret; + } + + LOGD("Attribute [%s] (value %f) has been gotten", + name, *value); + return ret; +} + +int mv_engine_config_get_int_attribute_c( + mv_engine_config_h engine_cfg, + const char *name, + int *value) +{ + if (!engine_cfg || name == NULL || value == NULL) + { + LOGE("Impossible to get attribute. One of the required parameters is " + "NULL. engine_cfg = %p; name = %p; value = %p;", + engine_cfg, name, value); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + int ret = ((MediaVision::Common::EngineConfig*)engine_cfg)->getIntegerAttribute( + std::string(name), value); + + if (ret != MEDIA_VISION_ERROR_NONE) + { + LOGE("Failed to get attribute [%s]. Error code (0x%08x)", + name, ret); + return ret; + } + + LOGD("Attribute [%s] (value %i) has been gotten", + name, *value); + return ret; +} + +int mv_engine_config_get_bool_attribute_c( + mv_engine_config_h engine_cfg, + const char *name, + bool *value) +{ + if (!engine_cfg || name == NULL || value == NULL) + { + LOGE("Impossible to get attribute. One of the required parameters is " + "NULL. engine_cfg = %p; name = %p; value = %p;", + engine_cfg, name, value); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + int ret = ((MediaVision::Common::EngineConfig*)engine_cfg)->getBooleanAttribute( + std::string(name), value); + + if (ret != MEDIA_VISION_ERROR_NONE) + { + LOGE("Failed to get attribute [%s]. Error code (0x%08x)", + name, ret); + return ret; + } + + LOGD("Attribute [%s] (value %s) has been gotten", + name, *value ? "TRUE" : "FALSE"); + return ret; +} + +int mv_engine_config_get_string_attribute_c( + mv_engine_config_h engine_cfg, + const char *name, + char **value) +{ + if (!engine_cfg || name == NULL || value == NULL) + { + LOGE("Impossible to get attribute. One of the required parameters is " + "NULL. engine_cfg = %p; name = %p; value = %p;", + engine_cfg, name, value); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + std::string attributeValue; + int ret = ((MediaVision::Common::EngineConfig*)engine_cfg)->getStringAttribute( + std::string(name), &attributeValue); + + if (ret != MEDIA_VISION_ERROR_NONE) + { + LOGE("Failed to get attribute [%s]. Error code (0x%08x)", + name, ret); + return ret; + } + + LOGD("Convert string to char*"); + int stringSize = attributeValue.size(); + (*value) = new char[stringSize + 1]; + + if (attributeValue.copy(*value, stringSize) != attributeValue.size()) + { + LOGE("Conversion from string to char* failed"); + delete[] (*value); + (*value) = NULL; + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + (*value)[stringSize] = '\0'; + + LOGD("Attribute [%s] (value %s) has been gotten", + name, *value); + return ret; +} + +int mv_engine_config_foreach_supported_attribute_c( + mv_supported_attribute_cb callback, + void *user_data) +{ + if (NULL == callback) + { + LOGE("Impossible to traverse supported by Media Vision engine " + "configuration attributes. Callback is NULL"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + using namespace MediaVision::Common; + + int err = EngineConfig::cacheDictionaries(); + + if (MEDIA_VISION_ERROR_NONE != err) + { + LOGE("Failed to get attribute names/types. " + "Failed to cache attributes from file"); + return err; + } + + DictDblConstIter dblDictIter = EngineConfig::getDefaultDblDict().begin(); + DictIntConstIter intDictIter = EngineConfig::getDefaultIntDict().begin(); + DictBoolConstIter boolDictIter = EngineConfig::getDefaultBoolDict().begin(); + DictStrConstIter strDictIter = EngineConfig::getDefaultStrDict().begin(); + + while (dblDictIter != EngineConfig::getDefaultDblDict().end()) + { + if (!callback(MV_ENGINE_CONFIG_ATTR_TYPE_DOUBLE, + dblDictIter->first.c_str(), user_data)) + { + LOGD("Attribute names/types traverse has been stopped by the user"); + return MEDIA_VISION_ERROR_NONE; + } + ++dblDictIter; + } + + while (intDictIter != EngineConfig::getDefaultIntDict().end()) + { + if (!callback(MV_ENGINE_CONFIG_ATTR_TYPE_INTEGER, + intDictIter->first.c_str(), user_data)) + { + LOGD("Attribute names/types traverse has been stopped by the user"); + return MEDIA_VISION_ERROR_NONE; + } + ++intDictIter; + } + + while (boolDictIter != EngineConfig::getDefaultBoolDict().end()) + { + if (!callback(MV_ENGINE_CONFIG_ATTR_TYPE_BOOLEAN, + boolDictIter->first.c_str(), user_data)) + { + LOGD("Attribute names/types traverse has been stopped by the user"); + return MEDIA_VISION_ERROR_NONE; + } + ++boolDictIter; + } + + while (strDictIter != EngineConfig::getDefaultStrDict().end()) + { + if (!callback(MV_ENGINE_CONFIG_ATTR_TYPE_STRING, + strDictIter->first.c_str(), user_data)) + { + LOGD("Attribute names/types traverse has been stopped by the user"); + return MEDIA_VISION_ERROR_NONE; + } + ++strDictIter; + } + + LOGD("Attribute names/types has been gotten"); + return MEDIA_VISION_ERROR_NONE; +} diff --git a/mv_face/CMakeLists.txt b/mv_face/CMakeLists.txt new file mode 100644 index 0000000..248d927 --- /dev/null +++ b/mv_face/CMakeLists.txt @@ -0,0 +1,8 @@ +project(mv_face_port) +cmake_minimum_required(VERSION 2.6) + +if(MEDIA_VISION_FACE_LICENSE_PORT) + add_subdirectory(${PROJECT_SOURCE_DIR}/face_lic) # Licensed port +else() + add_subdirectory(${PROJECT_SOURCE_DIR}/face) # Open port +endif() diff --git a/mv_face/face/CMakeLists.txt b/mv_face/face/CMakeLists.txt new file mode 100644 index 0000000..6cc1199 --- /dev/null +++ b/mv_face/face/CMakeLists.txt @@ -0,0 +1,36 @@ +project(${MV_FACE_LIB_NAME}) +cmake_minimum_required(VERSION 2.6) + +set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG _DEBUG) + +if(NOT SKIP_WARNINGS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_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") +include_directories("${PROJECT_SOURCE_DIR}/src") + +file(GLOB MV_FACE_INCLUDE_LIST "${PROJECT_SOURCE_DIR}/include/*.h") +file(GLOB MV_FACE_SRC_LIST "${PROJECT_SOURCE_DIR}/src/*.cpp") + +find_package(OpenCV REQUIRED core objdetect contrib) +if(NOT OpenCV_FOUND) + message(SEND_ERROR "Failed to find OpenCV") + return() +else() + include_directories(${OpenCV_INCLUDE_DIRS}) +endif() + +if(FORCED_STATIC_BUILD) + add_library(${PROJECT_NAME} STATIC ${MV_FACE_INCLUDE_LIST} ${MV_FACE_SRC_LIST}) +else() + add_library(${PROJECT_NAME} SHARED ${MV_FACE_INCLUDE_LIST} ${MV_FACE_SRC_LIST}) +endif() + +target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS} ${MV_COMMON_LIB_NAME} dlog) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}) diff --git a/mv_face/face/include/FaceDetector.h b/mv_face/face/include/FaceDetector.h new file mode 100644 index 0000000..f014a54 --- /dev/null +++ b/mv_face/face/include/FaceDetector.h @@ -0,0 +1,112 @@ +/** + * 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 __FACEDETECTOR_H__ +#define __FACEDETECTOR_H__ + +#include +#include +#include + +/** + * @file FaceDetector.h + * @brief This file contains the FaceDetector class which implement the face + * detection functionality. + */ + +namespace MediaVision +{ +namespace Face +{ + +/** + * @class FaceDetector + * @brief The Face Detector container. + * @details It is class which contains face detection functionality. + * + * @since_tizen 3.0 + */ +class FaceDetector +{ +public: + + /** + * @brief Creates a FaceDetector. + * + * @since_tizen 3.0 + */ + FaceDetector(); + + /** + * @brief Destroys the FaceDetector and releases all its resources. + * + * @since_tizen 3.0 + */ + virtual ~FaceDetector(); + + /** + * @brief Performs face detection functionality. + * @details Use this function to launch face detection algorithm which + * used the haarcascade set by setHaarcascadeFilepath(). + * + * @since_tizen 3.0 + * @param [in] image The image where faces will be detected + * @param [in] roi Region of image where faces will be detected + * @param [in] minSize Minimum size of faces which will be detected + * @param [out] faceLocations The result locations of detected faces. + * @return true if detect process is completely finished. Otherwise return false. + * + * @pre Set a face haarcascade by calling setHaarcascadeFilepath() + * + * @see setHaarcascadeFilepath() + */ + bool detectFaces( + const cv::Mat& image, + const cv::Rect& roi, + const cv::Size& minSize, + std::vector& faceLocations); + + /** + * @brief Loads haar cascade classifier for detection process. + * @details This method is mandatory for normally detecting process. + * + * @since_tizen 3.0 + * @param [in] haarcascadeFilepath The path to the file, which contains haar + * cascade classifier information for + * detection process. + * @return true if cascade is loaded from file and ready for detecting + * process. Otherwise is false. + */ + bool loadHaarcascade(const std::string& haarcascadeFilepath); + +private: + + cv::CascadeClassifier m_faceCascade; /**< Cascade classifier of the face + detecting process. */ + + std::string m_haarcascadeFilepath; /**< Path to the file, which contains + cascade classifier information. */ + + bool m_faceCascadeIsLoaded; /**< Flag to determine the state of the + m_faceCascade class. true if cascade is loaded + from file and is ready to detecting process. + Otherwise is false. */ +}; + +} /* Face */ +} /* MediaVision */ + +#endif /* __FACEDETECTOR_H__ */ diff --git a/mv_face/face/include/FaceExpressionRecognizer.h b/mv_face/face/include/FaceExpressionRecognizer.h new file mode 100644 index 0000000..fb445a4 --- /dev/null +++ b/mv_face/face/include/FaceExpressionRecognizer.h @@ -0,0 +1,85 @@ +/** + * 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 __FACEEXPRESSIONRECOGNIZER_H__ +#define __FACEEXPRESSIONRECOGNIZER_H__ + +#include "mv_common_c.h" +#include "mv_face_open.h" + +#include + +namespace cv +{ + class Mat; +} + +/** + * @file FaceExpressionRecognizer.h + * @brief This file contains the FaceExpressionRecognizer class which implements + * the facial expressions recognition functionality. + */ + +namespace MediaVision +{ +namespace Face +{ + +/** + * @brief Face expression recognition configuration. + * + * @since_tizen 3.0 + */ +struct FaceRecognizerConfig +{ + FaceRecognizerConfig(); + std::string mHaarcascadeFilepath; +}; + +/** + * @class FaceExpressionRecognizer + * @brief The FaceExpressionRecognizer implements the facial expressions + * recognition functionality. + * + * @since_tizen 3.0 + */ +class FaceExpressionRecognizer +{ +public: + /** + * @brief Recognizes facial expression on the image with known face location. + * + * @since_tizen 3.0 + * @param [in] grayImage The grayscale image with face + * @param [in] faceLocation The location of the face on the @a image + * @param [out] faceExpression Expression recognized for the face at + * @a faceLocation + * @param [in] config The configuration will be used for + * facial expression recognition + * + * @see MediaVision::Face::FaceRecognizerConfig + */ + static int recognizeFaceExpression( + const cv::Mat& grayImage, + const mv_rectangle_s& faceLocation, + mv_face_facial_expression_e *faceExpression, + const FaceRecognizerConfig& config = FaceRecognizerConfig()); +}; + +} /* Face */ +} /* MediaVision */ + +#endif /* __FACEEXPRESSIONRECOGNIZER_H__ */ diff --git a/mv_face/face/include/FaceEyeCondition.h b/mv_face/face/include/FaceEyeCondition.h new file mode 100644 index 0000000..56e1038 --- /dev/null +++ b/mv_face/face/include/FaceEyeCondition.h @@ -0,0 +1,76 @@ +/** + * 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 __FACEEYECONDITION_H__ +#define __FACEEYECONDITION_H__ + +#include +#include + +#include + +/** + * @file FaceEyeCondition.h + * @brief This file contains the FaceEyeCondition class which implements the face + * eye condition recognition functionality. + */ + +namespace MediaVision +{ +namespace Face +{ + +/** + * @class FaceEyeCondition + * @brief The FaceEyeCondition implements the face + * eye condition recognition functionality. + * + * @since_tizen 3.0 + */ +class FaceEyeCondition +{ +public: + + /** + * @brief Recognizes eye condition on the image with face location. + * + * @since_tizen 3.0 + * @param [in] grayImage The image in gray scale with face where + * eye condition will be recognized + * @param [in] faceLocation The rectangle with face location + * @param [out] eyeCondition The eye condition which was recognized + * @return @c 0 on success, otherwise a negative error value + */ + static int recognizeEyeCondition( + const cv::Mat& grayImage, + mv_rectangle_s faceLocation, + mv_face_eye_condition_e *eyeCondition); + +private: + + static void splitEyes( + /*[in]*/ const cv::Mat& grayImage, + /*[in]*/ mv_rectangle_s faceLocation, + /*[out]*/ cv::Mat& leftEye, + /*[out]*/ cv::Mat& rightEye); + + static int isEyeOpen(/*[in]*/const cv::Mat& eye); +}; + +} /* Face */ +} /* MediaVision */ + +#endif /* __FACEEYECONDITION_H__ */ diff --git a/mv_face/face/include/FaceRecognitionModel.h b/mv_face/face/include/FaceRecognitionModel.h new file mode 100644 index 0000000..b4888f2 --- /dev/null +++ b/mv_face/face/include/FaceRecognitionModel.h @@ -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. + */ + +#ifndef __FACERECOGNITIONMODEL_H__ +#define __FACERECOGNITIONMODEL_H__ + +#include "FaceUtil.h" + +#include +#include + +#include +#include + +/** + * @file FaceRecognitionModel.h + * @brief This file contains the FaceRecognitionModel class definition which + * provides face recognition model interface. + */ + +namespace MediaVision +{ +namespace Face +{ + +/** + * @brief Structure containing supported recognition algorithms settings. + * + * @since_tizen 3.0 + */ +struct FaceRecognitionModelConfig +{ + /** + * @brief Default constructor for the @ref FaceRecognitionModelConfig + * + * @since_tizen 3.0 + */ + FaceRecognitionModelConfig(); + + bool operator!=( + const FaceRecognitionModelConfig& other) const; + + FaceRecognitionModelType mModelType; /**< + Type of the recognition algorithm */ + + int mNumComponents; /**< How many principal components will be included + to the Eigenvectors */ + + double mThreshold; /**< Minimal distance between principal components of + the model allowed */ + + int mRadius; /**< Radius of the local features for LBHP algorithm */ + + int mNeighbors; /**< How many neighboring pixels has to be analyzed + when LBHP learning applied. Usually set as + 8*radius */ + + int mGridX; /**< X size of the spatial histogram (LBPH) */ + + int mGridY; /**< Y size of the spatial histogram (LBPH) */ + + int mImgWidth; /**< Width of the image to resize the samples for + algorithms working on the samples of the same + size (Eigenfaces, Fisherfaces) */ + + int mImgHeight; /**< Height of the image to resize the samples for + algorithms working on the samples of the same + size (Eigenfaces, Fisherfaces) */ +}; + +/** + * @brief Structure where results of + * @ref MediaVision::Face::FaceRecognitionModel::recognize() call is + * stored. + * + * @since_tizen 3.0 + */ +struct FaceRecognitionResults +{ + /** + * @brief Default constructor for the @ref FaceRecognitionResults + * + * @since_tizen 3.0 + */ + FaceRecognitionResults(); + + bool mIsRecognized; /**< The flag indication success of the + recognition */ + cv::Rect_ mFaceLocation; /**< Location of the face where face has + been recognized */ + int mFaceLabel; /**< Unique label of the face */ + double mConfidence; /**< Recognition confidence level */ +}; + +/** + * @class FaceRecognitionModel + * @brief Class providing interface for management of face recognition model. + * + * @since_tizen 3.0 + */ +class FaceRecognitionModel +{ +public: + + /** + * @brief Creates a FaceRecognitionModel class instance. + * + * @since_tizen 3.0 + */ + FaceRecognitionModel(); + + /** + * @brief Creates a FaceRecognitionModel class instance based on existed + * instance. + * + * @since_tizen 3.0 + * @param [in] origin The FaceRecognitionModel object that will be used + * for creation of new one + */ + FaceRecognitionModel(const FaceRecognitionModel& origin); + + /** + * @brief @ref FaceRecognitionModel copy assignment operator. + * @details Fills the information based on the @a copy + * + * @since_tizen 3.0 + * @param [in] copy @ref FaceRecognitionModel object which will be + * copied + */ + FaceRecognitionModel& operator=(const FaceRecognitionModel& copy); + + /** + * @brief Destroys the FaceRecognitionModel class instance including all + * its resources. + * + * @since_tizen 3.0 + */ + ~FaceRecognitionModel(); + + /** + * @brief Serializes FaceRecognitionModel object to the file. + * + * @since_tizen 3.0 + * @param [in] fileName The name of the file to which serialized + * FaceRecognitionModel object will be saved + * @return @c 0 on success, otherwise a negative error value + * + * @see FaceRecognitionModel::load() + */ + int save(const std::string& fileName); + + /** + * @brief Deserializes FaceRecognitionModel object from the file. + * + * @since_tizen 3.0 + * @param [in] fileName The name to the file from which serialized + * FaceRecognitionModel object will be deserialized + * @return @c 0 on success, otherwise a negative error value + * + * @see FaceRecognitionModel::save() + */ + int load(const std::string& fileName); + + /** + * @brief Adds face image example for face labeled by @a faceLabel + * + * @since_tizen 3.0 + * @param [in] faceImage Face image to be added to the training set + * @param [in] faceLabel Label that defines class of the face + * @return @c 0 on success, otherwise a negative error value + * + * @see FaceRecognitionModel::resetFaceExamples() + */ + int addFaceExample(const cv::Mat& faceImage, int faceLabel); + + /** + * @brief Clears the internal set of face image examples. + * + * @since_tizen 3.0 + * @remarks Internal set of face image examples contains all samples + * collected with @ref FaceRecognitionModel::addPositiveExample() + * method. + * @return @c 0 on success, otherwise a negative error value + * + * @see FaceRecognitionModel::addFaceExample() + */ + int resetFaceExamples(void); + + /** + * @brief Clears the internal set of face image examples labeled with + * @a faceLabel. + * + * @since_tizen 3.0 + * @remarks Internal set of face image examples contains all samples + * collected with @ref FaceRecognitionModel::addPositiveExample() + * method. + * @param faceLabel Unique for the model face label + * @return @c 0 on success, otherwise a negative error value + * + * @see FaceRecognitionModel::addFaceExample() + */ + int resetFaceExamples(int faceLabel); + + /** + * @brief Getter for the face labels learned by the model. + * + * @since_tizen 3.0 + * @remarks Returning vector will contain only labels had been learned by + * FaceRecognitionModel::learn() method. + * @return Vector of the face labels known by the model + * + * @see FaceRecognitionModel::addFaceExample() + * @see FaceRecognitionModel::learn() + */ + const std::set& getFaceLabels(void) const; + + /** + * @brief Learns recognition model based on the set of collected face image + * examples. + * + * @since_tizen 3.0 + * @param [in] config Configuration of the algorithm to be used for + * learning the model + * @return @c 0 on success, otherwise a negative error value + * + * @see FaceRecognitionModel::addFaceExample() + */ + int learn(const FaceRecognitionModelConfig& config = FaceRecognitionModelConfig()); + + /** + * @brief Recognizes faces in the image and outputs recognition results to + * the @a results structure. + * + * @since_tizen 3.0 + * @param [in] config Configuration of the algorithm to be used for + * face recognition + * @param [out] results Structure that will contain recognition results + * @return @c 0 on success, otherwise a negative error value + * + * @see FaceRecognitionModel::learn() + */ + int recognize(const cv::Mat& image, FaceRecognitionResults& results); + +private: + + /** + * Factory method for creating of the recognition algorithm based on input + * configuration: + */ + static cv::Ptr CreateRecognitionAlgorithm( + const FaceRecognitionModelConfig& config = + FaceRecognitionModelConfig()); + +private: + + bool m_canRecognize; /**< The flag showing possibility to recognize with + the face recognition model */ + + std::map > m_faceSamples; /**< Samples of the + images which + will be used for + the learning */ + + FaceRecognitionModelConfig m_learnAlgorithmConfig; /**< Configuration of the + learning method */ + + cv::Ptr m_recognizer; /**< Recognizer associated with + the current model */ + + std::set m_learnedLabels; /**< Vector of the labels had been learned + by the model */ +}; + +} /* Face */ +} /* MediaVision */ + +#endif /* __FACERECOGNITIONMODEL_H__ */ diff --git a/mv_face/face/include/FaceTrackingModel.h b/mv_face/face/include/FaceTrackingModel.h new file mode 100644 index 0000000..daa56c7 --- /dev/null +++ b/mv_face/face/include/FaceTrackingModel.h @@ -0,0 +1,175 @@ +/** + * 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 __FACETRACKINGMODEL_H__ +#define __FACETRACKINGMODEL_H__ + +#include "TrackerMedianFlow.h" + +/** + * @file FaceTrackingModel.h + * @brief This file contains the FaceTrackingModel class definition which + * provides face tracking model interface. + */ + +namespace MediaVision +{ +namespace Face +{ + +/** + * @brief Structure where results of + * @ref MediaVision::Face::FaceTrackingModel::track() call are stored. + * + * @since_tizen 3.0 + */ +struct FaceTrackingResults +{ + /** + * @brief Default constructor for the @ref FaceTrackingResults + * + * @since_tizen 3.0 + */ + FaceTrackingResults(); + + bool mIsTracked; /**< The flag indication success of the + tracking */ + cv::Rect_ mFaceLocation; /**< Location of the face at the current + track iteration where face position + is predicted */ + float mConfidence; /**< Tracking confidence level + (0.0 .. 1.0) */ +}; + +/** + * @class FaceTrackingModel + * @brief Class providing interface for management of face tracking model. + * + * @since_tizen 3.0 + */ +class FaceTrackingModel +{ +public: + /** + * @brief Creates a FaceTrackingModel class instance. + * + * @since_tizen 3.0 + */ + FaceTrackingModel(); + + /** + * @brief Creates a FaceTrackingModel class instance based on existed + * instance. + * + * @since_tizen 3.0 + * @param [in] origin The FaceTrackingModel object that will be used + * for creation of new one + */ + FaceTrackingModel(const FaceTrackingModel& origin); + + /** + * @brief @ref FaceTrackingModel copy assignment operator. + * @details Fills the information based on the @a copy + * + * @since_tizen 3.0 + * @param [in] copy @ref FaceTrackingModel object which will be + * copied + */ + FaceTrackingModel& operator=(const FaceTrackingModel& copy); + + /** + * @brief Destroys the FaceTrackingModel class instance including all + * its resources. + * + * @since_tizen 3.0 + */ + ~FaceTrackingModel(); + + /** + * @brief Serializes FaceTrackingModel object to the file. + * + * @since_tizen 3.0 + * @param [in] fileName The name to the file to which serialized + * FaceTrackingModel object will be saved + * @return @c 0 on success, otherwise a negative error value + * + * @see FaceTrackingModel::load() + */ + int save(const std::string& fileName); + + /** + * @brief Deserializes FaceTrackingModel object from the file. + * + * @since_tizen 3.0 + * @param [in] fileName The name of the file from which serialized + * FaceTrackingModel object will be deserialized + * @return @c 0 on success, otherwise a negative error value + * + * @see FaceTrackingModel::save() + */ + int load(const std::string& fileName); + + /** + * @brief Prepares FaceTrackingModel object to the next tracking session. + * + * @since_tizen 3.0 + * @param [in] image First frame of the video or image sequence for + * which tracking will be started + * @return @c 0 on success, otherwise a negative error value + * + * @see FaceTrackingModel::save() + */ + int prepare(const cv::Mat& image); + + /** + * @brief Prepares FaceTrackingModel object to the next tracking session. + * + * @since_tizen 3.0 + * @param [in] image First frame of the video or image sequence for + * which tracking will be started + * @param [in] boundingBox Rectangular location of the face on the @a + * image + * @return @c 0 on success, otherwise a negative error value + * + * @see FaceTrackingModel::save() + */ + int prepare(const cv::Mat& image, const cv::Rect_& boundingBox); + + /** + * @brief Performs one tracking iteration for the video frame or image + * from the continuous sequence of images. + * + * @since_tizen 3.0 + * @param [in] image + * @param [out] boundingBox + */ + int track(const cv::Mat& image, FaceTrackingResults& results); + +private: + + bool m_canTrack; /**< The flag showing possibility + of the tracking model to + perform track */ + + cv::Ptr m_tracker; /**< Underlying OpenCV tracking + model */ + +}; + +} /* Face */ +} /* MediaVision */ + +#endif /* __FACETRACKINGMODEL_H__ */ diff --git a/mv_face/face/include/FaceUtil.h b/mv_face/face/include/FaceUtil.h new file mode 100644 index 0000000..d79757d --- /dev/null +++ b/mv_face/face/include/FaceUtil.h @@ -0,0 +1,75 @@ +/** + * 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 __FACEUTIL_H__ +#define __FACEUTIL_H__ + +#include + +#include "mv_common_c.h" + +/** + * @file FaceUtil.h + * @brief This file contains the useful functionality for Face module. + */ +namespace MediaVision +{ +namespace Face +{ + +/** + * @brief Enumeration of supported learning algorithms. + * + * @since_tizen 3.0 + */ +enum FaceRecognitionModelType +{ + MEDIA_VISION_FACE_MODEL_TYPE_UNKNOWN = 0, /**< Unknown algorithm type */ + MEDIA_VISION_FACE_MODEL_TYPE_EIGENFACES = 1, /**< Eigenfaces algorithm */ + MEDIA_VISION_FACE_MODEL_TYPE_FISHERFACES = 2, /**< Fisherfaces algorithm */ + MEDIA_VISION_FACE_MODEL_TYPE_LBPH = 3 /**< Local Binary Patterns + Histograms algorithm */ +}; + +/** + * @brief Contains parameters for face recognition. + * + * @since_tizen 3.0 + */ +struct RecognitionParams +{ + RecognitionParams(FaceRecognitionModelType algType); + + RecognitionParams(); + + FaceRecognitionModelType mRecognitionAlgType; + /**< The type of the learning algorithm. */ +}; + +/** + * @brief Converts mv_source_h to cv::Mat class with grayscale type. + * + * @since_tizen 3.0 + * @param [in] mvSource The handle to the image from Media Vision API. + * @param [out] cvSource The cv::Mat class, which will be filled. + * @return @c 0 on success, otherwise a negative error value + */ +int convertSourceMV2GrayCV(mv_source_h mvSource, cv::Mat& cvSource); + +} /* Face */ +} /* MediaVision */ + +#endif /* __FACEUTIL_H__ */ diff --git a/mv_face/face/include/TrackerMedianFlow.h b/mv_face/face/include/TrackerMedianFlow.h new file mode 100644 index 0000000..7112a14 --- /dev/null +++ b/mv_face/face/include/TrackerMedianFlow.h @@ -0,0 +1,155 @@ +/*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) 2013, OpenCV Foundation, 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 __TRACKERMEDIANFLOW_H__ +#define __TRACKERMEDIANFLOW_H__ + +#include "opencv2/core/core.hpp" + +namespace cv +{ + +class TrackerMedianFlowModel; + +/** @brief Median Flow tracker implementation. + +Implementation of a paper @cite MedianFlow . + +The tracker is suitable for very smooth and predictable movements when object is visible throughout +the whole sequence. It's quite and accurate for this type of problems (in particular, it was shown +by authors to outperform MIL). During the implementation period the code at +, the courtesy of the author Arthur Amarra, was used for the +reference purpose. + */ +class TrackerMedianFlow : public virtual Algorithm +{ +public: + + struct Params + { + /** + * @brief TrackerMedianFlow algorithm parameters constructor + */ + Params(); + void read(const FileNode& fn); + void write(FileStorage& fs) const; + + int mPointsInGrid; /**< Square root of number of keypoints used. + Increase it to trade accurateness for speed. + Default value is sensible and recommended */ + + Size mWindowSize; /**< Size of the search window at each pyramid level + for Lucas-Kanade optical flow search used for + tracking */ + + int mPyrMaxLevel; /**< Number of pyramid levels for Lucas-Kanade optical + flow search used for tracking */ + }; + + TrackerMedianFlow(Params paramsIn = Params()); + + bool copyTo(TrackerMedianFlow& copy) const; + + bool init(const Mat& image, const Rect_& boundingBox); + bool update(const Mat& image, Rect_& boundingBox); + + bool isInited() const; + + float getLastConfidence() const; + Rect_ getLastBoundingBox() const; + + void read(FileStorage& fn); + void write(FileStorage& fs) const; + +private: + + bool isInit; + + bool medianFlowImpl(Mat oldImage, Mat newImage, Rect_& oldBox); + + Rect_ vote( + const std::vector& oldPoints, + const std::vector& newPoints, + const Rect_& oldRect, + Point2f& mD); + + template + T getMedian( + std::vector& values, int size = -1); + + void check_FB( + std::vector newPyramid, + const std::vector& oldPoints, + const std::vector& newPoints, + std::vector& status); + + void check_NCC( + const Mat& oldImage, + const Mat& newImage, + const std::vector& oldPoints, + const std::vector& newPoints, + std::vector& status); + + inline float l2distance(Point2f p1, Point2f p2); + + Params params; /**< Parameters used during tracking, see + @ref TrackerMedianFlow::Params */ + + TermCriteria termcrit; /**< Terminating criteria for OpenCV + Lucas–Kanade optical flow algorithm used + during tracking */ + + Rect_ m_boundingBox; /**< Tracking object bounding box */ + + float m_confidence; /**< Confidence that face was tracked correctly + at the last tracking iteration */ + + Mat m_image; /**< Last image for which tracking was + performed */ + + std::vector m_pyramid; /**< The pyramid had been calculated for + the previous frame (or when + initialize the model) */ +}; + +} /* namespace cv */ + +#endif /* __TRACKERMEDIANFLOW_H__ */ diff --git a/mv_face/face/include/mv_face_open.h b/mv_face/face/include/mv_face_open.h new file mode 100644 index 0000000..a127d5a --- /dev/null +++ b/mv_face/face/include/mv_face_open.h @@ -0,0 +1,791 @@ +/** + * 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_FACE_OPEN_H__ +#define __TIZEN_MEDIAVISION_FACE_OPEN_H__ + +#include "mv_face.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file mv_face_open.h + * @brief This file contains the Media Vision Face Open API. + */ + +/******************/ +/* Face detection */ +/******************/ + +/** + * @brief Performs face detection on the @a source for the @a engine_conf. + * @details Use this function to launch face detection algorithm configured by + * @a engine_conf configuration. Each time when mv_face_detect_open is + * called, @a detected_cb will receive a set of the detected + * faces at the media source. + * + * @since_tizen 3.0 + * @param [in] source The handle to the source of the media where faces + * will be detected + * @param [in] engine_cfg The handle to the configuration of engine will be + * used for detecting. If NULL, then default settings + * will be used. + * @param [in] detected_cb The callback which will be called for all face + * locations detected on media source. This callback + * will receive detecting results + * @param [in] user_data The user data passed from the code where + * @ref mv_face_detect_open() is invoked. This data will be + * accessible from @a detected_cb callback. + * @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_INVALID_OPERATION Invalid operation + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Source colorspace + * isn't supported + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create a source handle by calling @ref mv_create_source() + * @post @a detected_cb will be called to process detection results + * + * @see mv_face_detected_cb + */ +int mv_face_detect_open( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_face_detected_cb detected_cb, + void *user_data); + + +/********************/ +/* Face recognition */ +/********************/ + +/** + * @brief Performs face recognition on the @a source image. + * @details Use this function to launch face recognition algorithm configured by + * @a engine_conf configuration using @a recognition_model recognition + * model. Each time when @ref mv_face_recognize_open() is called, + * @a recognized_cb will receive recognition results:\n + * - Location in the @a source of the face has been recognized; + * - Label of the face has been recognized; + * - Confidence of the @a recognition_model that face has been + * recognized correctly (value from 0.0 to 1.0). + * + * @since_tizen 3.0 + * @remarks Using of untrained or weakly trained recognition models will cause + * not accurate results even if resulting confidence will be high. + * Use @ref mv_face_recognition_model_learn_open() function before + * @ref mv_face_recognize_open() call. Best results can be achieved + * when big set of face image examples were added by + * @ref mv_face_recognition_model_add_open() before + * @ref mv_face_recognition_model_learn_open() call. + * @param [in] source The handle to the source of the media to + * recognize face(s) for + * @param [in] recognition_model The handle to the model will be used for + * recognition + * @param [in] engine_cfg The handle to the configuration of engine + * will be used for recognition. If NULL, then + * default settings will be used + * @param [in] face_location Rectangular box bounding face image on the + * @a source. If NULL, then full source will be + * analyzed + * @param [in] recognized_cb The callback which will be called for the + * face recognition results on the @a source. + * @param [in] user_data The user data passed from the code where + * @ref mv_face_recognize_open() is invoked. + * This data will be accessible from + * @a recognized_cb callback. + * @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_INVALID_OPERATION Invalid operation + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Source colorspace + * isn't supported + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create a source handle by calling @ref mv_create_source() + * @pre Create a face recognition model handle by calling + * @ref mv_face_recognition_model_create_open() + * @post @a recognized_cb will be called to process recognition results + * + * @see mv_face_recognized_cb + */ +int mv_face_recognize_open( + mv_source_h source, + mv_face_recognition_model_h recognition_model, + mv_engine_config_h engine_cfg, + mv_rectangle_s *face_location, + mv_face_recognized_cb recognized_cb, + void *user_data); + + +/*****************/ +/* Face tracking */ +/*****************/ + +/** + * @brief Performs face tracking on the @a source for the @a tracking_model. + * @details Use this function to launch face tracking algorithm configured by + * @a engine_conf configuration using @a tracking_model tracking + * model. Each time when this function is called, @a tracked_cb + * will receive updated @a tracking_model, new location determined for + * the tracked face and model confidence that location is determined + * correctly. + * + * @since_tizen 3.0 + * @remarks To allow correct tracking @a tracking_model has to be already used + * in previous tracking process(es) or prepared with + * @ref mv_face_tracking_model_prepare_open(). Preparation requires + * specifying the face location for the @a source on which tracking was + * started. I.e. @ref mv_face_tracking_model_prepare_open() function + * has to be called at least once before this method call. + * @param [in] source The handle to the source of the media to + * recognize face for + * @param [in] tracking_model The handle to the model will be used for + * tracking + * @param [in] engine_cfg The handle to the configuration of engine will + * be used for tracking. If NULL, the default + * configuration will be used. + * @param [in] tracked_cb The callback which will be called for tracking + * event on the @a source where face would be + * tracked. This callback will receive tracking + * results + * @param [in] do_learn The model learning flag. If it is set @c true + * then model will try to learn (if it supports + * learning feature), otherwise model will be not + * learned during the invoking tracking iteration. + * Learning process improves tracking correctness, + * but can decrease tracking performance + * @param [in] user_data The user data passed from the code where + * @ref mv_face_track_open() is invoked. This data + * will be accessible from @a tracked_cb callback + * @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_INVALID_OPERATION Invalid operation + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Source colorspace + * isn't supported + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create a source handle by calling @ref mv_create_source() + * @pre Create a face tracking model handle by calling + * @ref mv_face_tracking_model_create_open() + * @post @a tracked_cb will be called to process tracking results + * + * @see mv_face_tracked_cb + */ +int mv_face_track_open( + mv_source_h source, + mv_face_tracking_model_h tracking_model, + mv_engine_config_h engine_cfg, + mv_face_tracked_cb tracked_cb, + bool do_learn, + void *user_data); + + +/********************************/ +/* Recognition of eye condition */ +/********************************/ + +/** + * @brief Determines eye-blink condition for @a face_location on media @a source. + * @details Use this function to recognize eye-blink condition for the face + * bounded by @a face_location at @a source. + * + * @since_tizen 3.0 + * @param [in] source The handle to the source of the media to + * recognize eye-blink condition for + * @param [in] engine_cfg The handle to the configuration of engine + * will be used for eye-blink condition + * recognition. If NULL, the default configuration + * will be used. + * @param [in] face_location The location bounding the face at the @a source + * @param [in] eye_condition_recognized_cb The callback for processing result + * of eye-blink condition recognition + * @param [in] user_data The user data passed from the code where + * @ref mv_face_eye_condition_recognize_open() is + * invoked. This data will be accessible from + * @a eye_condition_recognized_cb callback + * @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_FORMAT Source colorspace + * isn't supported + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create a source handle by calling @ref mv_create_source_open() + * + * @see mv_face_eye_condition_recognized_cb + */ +int mv_face_eye_condition_recognize_open( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s face_location, + mv_face_eye_condition_recognized_cb eye_condition_recognized_cb, + void *user_data); + + +/************************************/ +/* Recognition of facial expression */ +/************************************/ + +/** + * @brief Determines facial expression for @a face_location on media @a source. + * @details Use this function to determine facial expression for the face + * bounded by @a face_location at @a source. + * + * @since_tizen 3.0 + * @param [in] source The handle to the source of the media + * to recognize facial expression for + * @param [in] engine_cfg The handle to the configuration of + * engine will be used for expression recognition + * @param [in] face_location The location bounding the face at the @a source + * @param [in] expression_recognized_cb The callback for processing result + * of facial expression determining + * @param [in] user_data The user data passed from the code where + * @ref mv_face_facial_expression_recognize_open() is + * invoked. This data will be accessible from + * @a expression_recognized_cb callback. + * @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_FORMAT Source colorspace + * isn't supported + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create a source handle by calling @ref mv_create_source_open() + * @pre Create a face engine configuration handle by calling @ref mv_create_engine_config() + * + * @see mv_face_facial_expression_recognized_cb + */ +int mv_face_facial_expression_recognize_open( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s face_location, + mv_face_facial_expression_recognized_cb expression_recognized_cb, + void *user_data); + +/*******************************/ +/* Recognition model behavior */ +/*******************************/ + +/** + * @brief Creates a face recognition model handle. + * @details Use this function to create default face recognition model. Creating + * process is defined by concrete face engine library. After creation + * recognition model has to be learned with + * @ref mv_face_recognition_model_learn_open() function to provide + * appropriate results of face recognition functionality. Or learned + * earlier model can be loaded by + * @ref mv_face_recognition_model_load_open() function. + * + * @since_tizen 3.0 + * @remarks It can cause incompatibility issues when saved models (see + * @ref mv_face_recognition_model_save_open(), + * @ref mv_face_recognition_model_load_open() functions documentation) + * are used in applications for different platforms which use different + * computer vision libraries underlying this API. + * @remarks You must release @a recognition_model by using + * @ref mv_face_recognition_model_destroy_open() function. + * @param [out] recognition_model The handle to the recognition model to be + * created + * + * @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 + * + * @see mv_face_recognition_model_destroy_open() + */ +int mv_face_recognition_model_create_open( + mv_face_recognition_model_h *recognition_model); + +/** + * @brief Destroys the face recognition model handle and releases all its + * resources. + * + * @since_tizen 3.0 + * @param [in] recognition_model The handle to the face recognition model 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 + * + * @see mv_face_recognition_model_create_open() + */ +int mv_face_recognition_model_destroy_open( + mv_face_recognition_model_h recognition_model); + +/** + * @brief Creates a copy of existed recognition model handle and clones all its + * resources. + * + * @since_tizen 3.0 + * @remarks Cloning perform not only handle copy, but also copies all internal + * resources of the model. @a dst must be released using + * @a mv_face_recognition_model_destroy_open(). + * @param [in] src The handle to the recognition model to be copied + * @param [out] dst The handle to the copy of existed recognition model + * specified as @a src + * @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 + * + * @pre Create face recognition handles by calling + * @ref mv_face_recognition_model_create_open() + * + * @see mv_face_recognition_model_create_open() + */ +int mv_face_recognition_model_clone_open( + mv_face_recognition_model_h src, + mv_face_recognition_model_h *dst); + +/** + * @brief Saves recognition model to the file. + * + * @since_tizen 3.0 + * @remarks This function doesn't save added by + * @ref mv_face_recognition_model_add_open() function face + * image examples. This examples can be removed by + * @ref mv_face_recognition_model_reset_open() function + * if it is needed to clear the memory. + * @remarks After model is saved to the file, it can be loaded from this file + * by @ref mv_face_recognition_model_load_open() function. + * @param [in] file_name Name of the file to save the model + * @param [in] recognition_model The handle to the recognition model to be + * saved to the file + * @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_INVALID_PATH Invalid path + * @retval #MEDIA_VISION_ERROR_PERMISSION_DENIED Not permitted + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Not supported format + * @retval #MEDIA_VISION_ERROR_INVALID_OPERATION Invalid operation + * + * @pre Create a face recognition handle by calling + * @ref mv_face_recognition_model_create_open() function + * @post Saved model can be loaded later by calling + * @ref mv_face_recognition_model_load_open() function + * + * @see mv_face_recognition_model_load_open() + * @see mv_face_recognition_model_create_open() + */ +int mv_face_recognition_model_save_open( + const char *file_name, + mv_face_recognition_model_h recognition_model); + +/** + * @brief Loads recognition model from file. + * + * @since_tizen 3.0 + * @remarks This function doesn't modify the set of face image examples added + * with @ref mv_face_recognition_model_add_open() function. + * Model will be loaded from file without loss of collected examples. + * If you want to free memory from examples, use + * @ref mv_face_recognition_model_reset_open() function. + * It is recommended to clear the memory if learning algorithm doesn't + * support reinforcement learning. + * @remarks Recognition models can be load from files saved with + * mv_face_recognition_model_save_open() function. + * @remarks Recognition model must be destroyed using + * @ref mv_face_recognition_model_destroy. + * @param [in] file_name Name of the file to load the model from + * @param [out] recognition_model The handle to the recognition model + * to be loaded from the file + * @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_INVALID_PATH Invalid path + * @retval #MEDIA_VISION_ERROR_PERMISSION_DENIED Not permitted + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Not supported format + * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory + * + * @see mv_face_recognition_model_save_open() + * @see mv_face_recognition_model_destroy_open() + */ +int mv_face_recognition_model_load_open( + const char *file_name, + mv_face_recognition_model_h *recognition_model); + +/** + * @brief Adds face image example to be used for face recognition model learning + * with @ref mv_face_recognition_model_learn_open(). + * + * @since_tizen 3.0 + * @remarks It is possible to destroy @a source after calling this method. + * Source isn't used for learning directly. + * @remarks Face image @a example_location location can be determined using + * @ref mv_face_detect_open() function. + * @param [in] source The handle to @a source that contains face + * image + * @param [in] recognition_model The handle to the recognition model which + * could be learned based on example + * @param [in] example_location The pointer to the rectangular location of + * the face image at the source image. If NULL, + * then full image will be analyzed as the face + * image + * @param [in] face_label The label that identifies face for which + * example is adding. Specify the same labels + * for the face images of a single person when + * calling this method. Can't be NULL + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIA_VISION_ERROR_NONE Successful + * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter + * + * @pre Create a face recognition handle by calling + * @ref mv_face_recognition_model_create_open() function + * @post When appropriate amount of face image examples is added to the + * @a recognition_model, this model has to be learned by + * @ref mv_face_recognition_model_learn_open() function call. Only after + * learning of the model it can be used for face recognition with + * @a mv_face_recognize_open() function + * + * @see mv_face_recognition_model_reset_open() + * @see mv_face_recognition_model_learn_open() + */ +int mv_face_recognition_model_add_open( + const mv_source_h source, + mv_face_recognition_model_h recognition_model, + const mv_rectangle_s *example_location, + int face_label); + +/** + * @brief Remove from @a recognition_model all collected with + * @ref mv_face_recognition_model_add_open() function + * face examples labeled with @a face_label. + * + * @since_tizen 3.0 + * @remarks Be aware that if this function is called before + * @ref mv_face_recognition_model_learn_open() function call, all or + * part of the required for learning data will be lost. It means that + * face image examples determined by the @a face_label label will be + * removed from the model and not taken taken into account when + * @ref mv_face_recognition_model_learn_open() will be called next + * time. + * @remarks Call of this function will free all the memory has been allocated + * during previous + * @ref mv_face_recognition_model_add_open() calls for + * the corresponding @a face_label label. + * @param [in] recognition_model The handle to the recognition model for + * which face image examples will be reset. + * @param [in] face_label The label that identifies face for which + * examples will be removed from the + * @a recognition_model. If NULL, then all + * known by @a recognition_model face image + * examples will be removed + * @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_KEY_NOT_AVAILABLE Key not available + * + * @see mv_face_recognition_model_add_open() + * @see mv_face_recognition_model_learn_open() + */ +int mv_face_recognition_model_reset_open( + mv_face_recognition_model_h recognition_model, + const int *face_label); + +/** + * @brief Learns face recognition model. + * @details Before you start learning process, face recognition models has to be + * filled with training data - face image examples. These examples has + * to be provided by + * mv_face_recognition_model_add_open() function. Usually, + * recognition accuracy is increased when number of not identical + * examples is large. But it depends of the used learning algorithm. + * + * @since_tizen 3.0 + * @remarks Common flow is to collect face examples as much as possible, add + * them to the recognition model with + * @ref mv_face_recognition_model_add_open(), then call + * @ref mv_face_recognition_model_learn_open() for this recognition + * model to learn it (or reinforce the model if reinforcement learning + * is supported by the used algorithm). + * @remarks Selection of the learning algorithm can be performed by setting + * corresponding attributes for the @a engine_cfg. You can check + * supported by @a engine_cfg attributes using + * @ref mv_engine_config_foreach_supported_attribute() function call. + * @param [in] engine_cfg The handle to the configuration of + * engine will be used for learning of the + * recognition models. If NULL, then + * default settings will be used + * @param [in,out] recognition_model The model which will be learned. After + * learning process these model may be + * changed, so + * @ref mv_face_recognize_open() results + * may differ before and after method call + * respectively to the face examples + * collected for the @a recognition_model + * @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 + * @retval #MEDIA_VISION_ERROR_NO_DATA No data + * + * @pre Create a face engine configuration handle by calling + * @ref mv_create_engine_config() and set supported parameters if + * needed. Or just set @a engine_cfg as NULL to learn with default settings + * @pre Create a face recognition model handles by calling + * @ref mv_face_recognition_model_create_open() function + * @pre Add face image examples to the @a recognition_model by calling + * @ref mv_face_recognition_model_add_open() function + * @post If it is not planned to learn the model again, clear memory by + * @ref mv_face_recognition_model_reset_open() function + * @post When model has been learned, it can be used for face recognition with + * @ref mv_face_recognize_open() function + * + * @see mv_face_recognition_model_add_open() + * @see mv_face_recognition_model_reset_open() + * @see mv_face_recognize_open() + */ +int mv_face_recognition_model_learn_open( + mv_engine_config_h engine_cfg, + mv_face_recognition_model_h recognition_model); + +/** + * @brief Queries labels list and number of labels had been learned by the model. + * + * @since_tizen 3.0 + * @remarks @a labels array has to be released using free(). + * @param [in] recognition_model The handle to the recognition model for + * which set of the learned labels will be + * queried + * @param [out] labels The array which will be filled with labels + * had been learned by the model + * @param [out] number_of_labels The number of labels in @a labels array + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIA_VISION_ERROR_NONE Successful + * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter + * + * @pre Add face image examples with labels to the @a recognition_model by + * calling the @ref mv_face_recognition_model_add_open() + * function + * @pre Learn the @a recognition_model by labeled examples using + * @ref mv_face_recognition_model_learn_open() function + * @post @a labels array has to be freed in the function invoking code + * + * @see mv_face_recognition_model_add_open() + * @see mv_face_recognition_model_reset_open() + * @see mv_face_recognition_model_learn_open() + */ +int mv_face_recognition_model_query_labels_open( + mv_face_recognition_model_h recognition_model, + int **labels, + unsigned int *number_of_labels); + +/***************************/ +/* Tracking model behavior */ +/***************************/ + +/** + * @brief Call this function to create a face tracking model handle. + * @details Use this function to create default face tracking model handle. + * After creation this handle has to be initialized with + * @ref mv_face_tracking_model_prepare_open() function to provide + * appropriate results of face tracking functionality. When handle is + * prepared, it is possible to use it for tracking on continuous + * sequence of the sources. Call + * @ref mv_face_tracking_model_prepare_open() function each time before + * starting tracking on the new sequence. The exception is situation + * when the new sequence is continuation of the previous sequence for + * which model has been tracked. + * + * @since_tizen 3.0 + * @param [out] tracking_model The pointer to the handle to the tracking + * model that will be created + * @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 + * + * @post Model can be loaded from the file after creation. Use + * @ref mv_face_tracking_model_load_open() function to load it from file + * @post Use @ref mv_face_tracking_model_prepare_open() function before tracking + * on the new video or continuous images sequence + * @post You must release @a tracking_model by using + * mv_face_tracking_model_destroy_open() function when it is not needed + * anymore + * + * @see mv_face_tracking_model_destroy_open() + * @see mv_face_tracking_model_prepare_open() + * @see mv_face_tracking_model_load_open() + */ +int mv_face_tracking_model_create_open( + mv_face_tracking_model_h *tracking_model); + +/** + * @brief Call this function to destroy the face tracking model handle and + * release all its resources. + * + * @since_tizen 3.0 + * @param [in] tracking_model The handle to the face tracking model that + * will 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_face_tracking_model_create_open() + */ +int mv_face_tracking_model_destroy_open( + mv_face_tracking_model_h tracking_model); + +/** + * @brief Call this function to initialize tracking model by the location of the + * face to be tracked. + * @details This function is usually called once after tracking model is created + * and each time before tracking is started for the new sequence of + * sources which is not the direct continuation of the sequence for + * which tracking has been performed before. But it is allowed to call + * it between tracking sessions to allow Media Vision start to track + * more accurately. + * + * @since_tizen 3.0 + * @param [in] tracking_model The handle to the tracking model that will be + * prepared for tracking on new video or image + * sequence + * @param [in] engine_cfg The handle to the configuration of engine + * will be used for model preparing. If NULL, then + * default settings will be used. + * @param [in] source The handle to the source where face @a location + * is specified. Usually it is the first frame of + * the video or the first image in the continuous + * image sequence planned to be used for tracking + * @param [in] location The quadrangle-shaped location (actually, + * rectangle can be used) determining position + * of the face to be tracked on the @a source. If + * @c NULL, then last location determined by the + * tracking model for the tracked face will be + * used for preparation + * @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 Create a face tracking model handle by calling + * @ref mv_face_tracking_model_create_open() function + * @pre Create a source handle by calling @ref mv_create_source() function + * @post When model is prepared, @ref mv_face_track_open() function can be used + * to track on the video or continuous image sequence + * + * @see mv_face_tracking_model_create_open() + * @see mv_face_track_open() + */ +int mv_face_tracking_model_prepare_open( + mv_face_tracking_model_h tracking_model, + mv_engine_config_h engine_cfg, + mv_source_h source, + mv_quadrangle_s */*location*/); + +/** + * @brief Call this function to make a copy of existed tracking model handle and + * clone all its resources to the copy. + * + * @since_tizen 3.0 + * @remarks Cloning performs not only handle copy, but also copies all internal + * resources of the model. @a dst must be released using + * mv_face_tracking_model_destroy_open(). + * @param [in] src The handle to the tracking model to be copied + * @param [out] dst The handle to the copy of existed tracking model + * specified as @a src + * @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 + * + * @pre Create face tracking @a src handle by calling + * @ref mv_face_tracking_model_create_open() + * + * @see mv_face_tracking_model_create_open() + */ +int mv_face_tracking_model_clone_open( + mv_face_tracking_model_h src, + mv_face_tracking_model_h *dst); + +/** + * @brief Call this method to save tracking model to the file. + * + * @since_tizen 3.0 + * @remarks After model is saved to the file, it can be loaded from this file + * with @ref mv_face_tracking_model_load_open() function. + * @param [in] file_name The name of the file where model will be saved + * @param [in] tracking_model The handle to the tracking model to be + * saved to the file + * @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_INVALID_OPERATION Invalid operation + * @retval #MEDIA_VISION_ERROR_INVALID_PATH Invalid path + * @retval #MEDIA_VISION_ERROR_PERMISSION_DENIED Not permitted + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Not supported format + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create a face tracking handle by calling + * @ref mv_face_tracking_model_create_open() + * @post Saved model can be loaded from file using + * @ref mv_face_tracking_model_load_open() function + * + * @see mv_face_tracking_model_load_open() + * @see mv_face_tracking_model_create_open() + */ +int mv_face_tracking_model_save_open( + const char *file_name, + mv_face_tracking_model_h tracking_model); + +/** + * @brief Call this method to load a tracking model from file. + * + * @since_tizen 3.0 + * @remarks Tracking models can be load from files saved with + * mv_face_tracking_model_save_open() function. + * @param [in] file_name Path to the file from which model will be + * loaded + * @param [in] tracking_model The handle to the tracking model to be + * loaded from file + * @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_INVALID_OPERATION Invalid operation + * @retval #MEDIA_VISION_ERROR_INVALID_PATH Invalid path + * @retval #MEDIA_VISION_ERROR_PERMISSION_DENIED Not permitted + * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Not supported format + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Models has been saved by @ref mv_face_tracking_model_save_open() + * function can be loaded with this function + * @post After model has been loaded and if further tracking will be performed + * on the video which is not continuation of the last tracking performed + * for the model, it is recommended to call + * @ref mv_face_tracking_model_prepare_open() function + * + * @see mv_face_tracking_model_save_open() + * @see mv_face_tracking_model_destroy_open() + */ +int mv_face_tracking_model_load_open( + const char *file_name, + mv_face_tracking_model_h *tracking_model); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIAVISION_FACE_OPEN_H__ */ diff --git a/mv_face/face/src/FaceDetector.cpp b/mv_face/face/src/FaceDetector.cpp new file mode 100644 index 0000000..21d8195 --- /dev/null +++ b/mv_face/face/src/FaceDetector.cpp @@ -0,0 +1,105 @@ +/** + * 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 "FaceDetector.h" + +namespace MediaVision +{ +namespace Face +{ + +FaceDetector::FaceDetector() : + m_faceCascade(), + m_haarcascadeFilepath(), + m_faceCascadeIsLoaded(false) +{ + ; /* NULL */ +} + +FaceDetector::~FaceDetector() +{ + ; /* NULL */ +} + +bool FaceDetector::detectFaces( + const cv::Mat& image, + const cv::Rect& roi, + const cv::Size& minSize, + std::vector& faceLocations) +{ + if (!m_faceCascadeIsLoaded) + { + return false; + } + + faceLocations.clear(); + + cv::Mat intrestingRegion = image; + + bool roiIsUsed = false; + if (roi.x >= 0 && roi.y >= 0 && roi.width > 0 && roi.height > 0 && + (roi.x + roi.width) <= image.cols && (roi.y + roi.height) <= image.rows) + { + intrestingRegion = intrestingRegion(roi); + roiIsUsed = true; + } + + if (minSize.width > 0 && minSize.height > 0 && + minSize.width <= image.cols && minSize.height <= image.rows) + { + m_faceCascade.detectMultiScale( + intrestingRegion, + faceLocations, + 1.1, + 3, + 0, + minSize); + } + else + { + m_faceCascade.detectMultiScale(intrestingRegion, faceLocations); + } + + if (roiIsUsed) + { + const size_t numberOfLocations = faceLocations.size(); + for (size_t i = 0u; i < numberOfLocations; ++i) + { + faceLocations[i].x += roi.x; + faceLocations[i].y += roi.y; + } + } + + return true; +} + +bool FaceDetector::loadHaarcascade(const std::string& haarcascadeFilepath) +{ + + if (!m_faceCascadeIsLoaded || m_haarcascadeFilepath != haarcascadeFilepath) + { + if (!(m_faceCascadeIsLoaded = m_faceCascade.load(haarcascadeFilepath))) + { + return false; + } + m_haarcascadeFilepath = haarcascadeFilepath; + } + + return true; +} + +} /* Face */ +} /* MediaVision */ diff --git a/mv_face/face/src/FaceExpressionRecognizer.cpp b/mv_face/face/src/FaceExpressionRecognizer.cpp new file mode 100644 index 0000000..51d9d05 --- /dev/null +++ b/mv_face/face/src/FaceExpressionRecognizer.cpp @@ -0,0 +1,105 @@ +/** + * 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 "FaceExpressionRecognizer.h" + +#include "mv_private.h" + +#include + +#include + +namespace MediaVision +{ +namespace Face +{ + +static const int MinDetectionWidth = 30; +static const int MinDetectionHeight = 30; + +FaceRecognizerConfig::FaceRecognizerConfig() : + mHaarcascadeFilepath( + "/usr/share/OpenCV/haarcascades/haarcascade_smile.xml") +{ + ; /* NULL */ +} + +int FaceExpressionRecognizer::recognizeFaceExpression( + const cv::Mat& grayImage, + const mv_rectangle_s& faceLocation, + mv_face_facial_expression_e *faceExpression, + const FaceRecognizerConfig& config) +{ + if (NULL == faceExpression) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + const int smileRectHeight = cvRound((float)faceLocation.height / 2); + + const cv::Rect roi( + faceLocation.point.x, + faceLocation.point.y + faceLocation.height - smileRectHeight, + faceLocation.width, + smileRectHeight); + + if (roi.width < MinDetectionWidth || + roi.height < MinDetectionHeight) + { + (*faceExpression) = MV_FACE_UNKNOWN; + return MEDIA_VISION_ERROR_NONE; + } + + if (0 > roi.x || + 0 > roi.y || + roi.x + roi.width > grayImage.cols || + roi.y + roi.height > grayImage.rows) + { + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + const cv::Mat mouthImg(grayImage, roi); + + std::vector areas; + + cv::CascadeClassifier smileClassifier; + smileClassifier.load(config.mHaarcascadeFilepath); + smileClassifier.detectMultiScale( + mouthImg, + areas, + 1.1, + 80, + cv::CASCADE_FIND_BIGGEST_OBJECT | + cv::CASCADE_DO_CANNY_PRUNING | + cv::CASCADE_SCALE_IMAGE, + cv::Size(MinDetectionWidth, MinDetectionHeight)); + + (*faceExpression) = MV_FACE_UNKNOWN; + const size_t smilesFoundSize = areas.size(); + if (smilesFoundSize == 0) + { + (*faceExpression) = MV_FACE_NEUTRAL; + } + else if (smilesFoundSize == 1) + { + (*faceExpression) = MV_FACE_SMILE; + } + + return MEDIA_VISION_ERROR_NONE; +} + +} /* Face */ +} /* MediaVision */ diff --git a/mv_face/face/src/FaceEyeCondition.cpp b/mv_face/face/src/FaceEyeCondition.cpp new file mode 100644 index 0000000..9432d1e --- /dev/null +++ b/mv_face/face/src/FaceEyeCondition.cpp @@ -0,0 +1,229 @@ +/** + * 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 "FaceEyeCondition.h" + +#include + +#include + +namespace MediaVision +{ +namespace Face +{ + +void FaceEyeCondition::splitEyes( + const cv::Mat& grayImage, + mv_rectangle_s faceLocation, + cv::Mat& leftEye, + cv::Mat& rightEye) +{ + leftEye = grayImage.rowRange(0, grayImage.rows / 2 - grayImage.rows / 10) + .colRange(grayImage.cols / 2 + grayImage.cols / 10, + grayImage.cols) + .clone(); + + rightEye = grayImage.rowRange(grayImage.rows / 2 + grayImage.rows / 10, + grayImage.rows) + .colRange(grayImage.cols / 2 + grayImage.cols / 10, + grayImage.cols) + .clone(); + + const cv::Rect faceRect( + faceLocation.point.x, + faceLocation.point.y, + faceLocation.width, + faceLocation.height); + + const cv::Rect eyeAreaRight( + faceRect.x + faceRect.width / 16, + (int) (faceRect.y + (faceRect.height / 4.5)), + (faceRect.width - 2 * faceRect.width / 16) / 2, + (int) (faceRect.height / 3.0)); + + const cv::Rect eyeAreaLeft( + faceRect.x + faceRect.width / 16 + + (faceRect.width - 2 * faceRect.width / 16) / 2, + (int) (faceRect.y + (faceRect.height / 4.5)), + (faceRect.width - 2 * faceRect.width / 16) / 2, + (int) (faceRect.height / 3.0)); + + const double xLeftEyeCenter = (2 * eyeAreaLeft.x + eyeAreaLeft.width) / 2.; + const double yLeftEyeCenter = (2 * eyeAreaLeft.y + eyeAreaLeft.height) / 2.; + + const double xRightEyeCenter = (2 * eyeAreaRight.x + eyeAreaRight.width) / 2.; + const double yRightEyeCenter = (2 * eyeAreaRight.y + eyeAreaRight.height) / 2.; + + const cv::Rect leftEyeRect(xLeftEyeCenter - eyeAreaLeft.width / 4, + yLeftEyeCenter - eyeAreaLeft.height / 4, + eyeAreaLeft.width / 2, + eyeAreaLeft.height / 2); + + const cv::Rect rightEyeRect(xRightEyeCenter - eyeAreaRight.width / 4, + yRightEyeCenter - eyeAreaRight.height / 4, + eyeAreaRight.width / 2, + eyeAreaRight.height / 2); + + cv::resize( + grayImage(leftEyeRect), + leftEye, + leftEye.size()); + cv::resize( + grayImage(rightEyeRect), + rightEye, + rightEye.size()); +} + +int FaceEyeCondition::isEyeOpen(const cv::Mat& eye) +{ + int isOpen = MV_FACE_EYES_CLOSED; + + cv::Mat eyeEqualized; + cv::equalizeHist(eye, eyeEqualized); + + const int thresold = 8; + eyeEqualized = eyeEqualized < thresold; + + std::vector > contours; + std::vector hierarchy; + + cv::findContours( + eyeEqualized, + contours, + hierarchy, + CV_RETR_CCOMP, + CV_CHAIN_APPROX_SIMPLE); + + const size_t contoursSize = contours.size(); + + if (!contoursSize) + { + return MV_FACE_EYES_NOT_FOUND; + } + + const int xCenter = eyeEqualized.cols / 2; + const int yCenter = eyeEqualized.rows / 2; + const int width = eyeEqualized.cols / 2.5; + const int height = eyeEqualized.rows / 2.5; + + const cv::Rect boundThresold(xCenter - width, yCenter - height, 2 * width, 2 * height); + + const int widthHeightRatio = 3; + const double areaRatio = 0.005; + const double areaSmallRatio = 0.0005; + size_t rectanglesInsideCount = 0u; + + for (size_t i = 0; i < contoursSize; ++i) + { + const cv::Rect currentRect = cv::boundingRect(contours[i]); + const double currentArea = cv::contourArea(contours[i]); + + if (boundThresold.contains(currentRect.br()) && + boundThresold.contains(currentRect.tl()) && + currentArea > areaRatio * boundThresold.area() && + currentRect.width < widthHeightRatio * currentRect.height) + { + isOpen = MV_FACE_EYES_OPEN; + } + else if (boundThresold.contains(currentRect.br()) && + boundThresold.contains(currentRect.tl()) && + currentArea > areaSmallRatio * boundThresold.area()) + { + ++rectanglesInsideCount; + } + } + + if (rectanglesInsideCount > 8u) + { + isOpen = MV_FACE_EYES_CLOSED; + } + + return isOpen; +} + +int FaceEyeCondition::recognizeEyeCondition( + const cv::Mat& grayImage, + mv_rectangle_s faceLocation, + mv_face_eye_condition_e *eyeCondition) +{ + if (grayImage.empty()) + { + *eyeCondition = MV_FACE_EYES_NOT_FOUND; + + LOGE("Input image is empty. Eye condition recognition failed."); + return MEDIA_VISION_ERROR_NO_DATA; + } + + if (faceLocation.height <= 0 || faceLocation.width <= 0 || + faceLocation.point.x < 0 || faceLocation.point.y < 0 || + (faceLocation.point.x + faceLocation.width) > grayImage.cols || + (faceLocation.point.y + faceLocation.height) > grayImage.rows) + { + *eyeCondition = MV_FACE_EYES_NOT_FOUND; + + LOGE("Input face location is wrong. Eye condition recognition failed."); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (NULL == eyeCondition) + { + *eyeCondition = MV_FACE_EYES_NOT_FOUND; + + LOGE("Output eye condition is NULL. Eye condition recognition failed."); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + // split left and right eyes + cv::Mat leftEye; + cv::Mat rightEye; + splitEyes(grayImage, faceLocation, leftEye, rightEye); + + // recognize eyes conditions + const int isOpenLeft = isEyeOpen(leftEye); + + if (isOpenLeft == MV_FACE_EYES_CLOSED) + { + *eyeCondition = MV_FACE_EYES_CLOSED; + + return MEDIA_VISION_ERROR_NONE; + } + else if (isOpenLeft == MV_FACE_EYES_NOT_FOUND) + { + *eyeCondition = MV_FACE_EYES_NOT_FOUND; + + return MEDIA_VISION_ERROR_NONE; + } + + const int isOpenRight = isEyeOpen(rightEye); + + if (isOpenRight == MV_FACE_EYES_OPEN) + { + *eyeCondition = MV_FACE_EYES_OPEN; + } + else if (isOpenRight == MV_FACE_EYES_CLOSED) + { + *eyeCondition = MV_FACE_EYES_CLOSED; + } + else + { + *eyeCondition = MV_FACE_EYES_NOT_FOUND; + } + + return MEDIA_VISION_ERROR_NONE; +} + +} /* Face */ +} /* MediaVision */ diff --git a/mv_face/face/src/FaceRecognitionModel.cpp b/mv_face/face/src/FaceRecognitionModel.cpp new file mode 100644 index 0000000..1887cea --- /dev/null +++ b/mv_face/face/src/FaceRecognitionModel.cpp @@ -0,0 +1,546 @@ +/** + * 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 "FaceRecognitionModel.h" + +#include + +#include "mv_private.h" +#include "mv_common.h" + +#include + +#include +#include + +namespace MediaVision +{ +namespace Face +{ + +namespace +{ + +int CopyOpenCVAlgorithmParameters(const cv::Ptr& srcAlg, + cv::Ptr& dstAlg) +{ + char tempPath[1024]; + + sprintf(tempPath, "/tmp/alg_copy_%p_%p", srcAlg.obj, dstAlg.obj); + + srcAlg->save(tempPath); + dstAlg->load(tempPath); + + if (0 != remove(tempPath)) + { + LOGW("Error removing serialized FaceRecognizer in %s", tempPath); + } + + // todo: consider to uncomment this lines if OpenCV will support deep + // copy of AlgorithmInfo objects: + + /*std::vector paramNames; + srcAlg->getParams(paramNames); + size_t paramSize = paramNames.size(); + for (size_t i = 0; i < paramSize; ++i) + { + int pType = srcAlg->paramType(paramNames[i]); + + switch(pType) + { + case cv::Param::INT: + case cv::Param::UNSIGNED_INT: + case cv::Param::UINT64: + case cv::Param::SHORT: + case cv::Param::UCHAR: + dstAlg->set(paramNames[i], srcAlg->getInt(paramNames[i])); + break; + case cv::Param::BOOLEAN: + dstAlg->set(paramNames[i], srcAlg->getBool(paramNames[i])); + break; + case cv::Param::REAL: + case cv::Param::FLOAT: + dstAlg->set(paramNames[i], srcAlg->getDouble(paramNames[i])); + break; + case cv::Param::STRING: + dstAlg->set(paramNames[i], srcAlg->getString(paramNames[i])); + break; + case cv::Param::MAT: + dstAlg->set(paramNames[i], srcAlg->getMat(paramNames[i])); + break; + case cv::Param::MAT_VECTOR: + { + //std::vector value = srcAlg->getMatVector(paramNames[i]); + //dstAlg->info()->addParam(*(dstAlg.obj), paramNames[i].c_str(), value); + dstAlg->set(paramNames[i], srcAlg->getMatVector(paramNames[i])); + break; + } + case cv::Param::ALGORITHM: + dstAlg->set(paramNames[i], srcAlg->getAlgorithm(paramNames[i])); + break; + default: + LOGE("While copying algorothm parameters unsupported parameter " + "%s was found.", paramNames[i].c_str()); + + return MEDIA_VISION_ERROR_NOT_SUPPORTED; + break; + } + }*/ + + return MEDIA_VISION_ERROR_NONE; +} + +void ParseOpenCVLabels( + const cv::Ptr& recognizer, + std::set& outLabels) +{ + if (!recognizer.empty()) + { + cv::Mat labels = recognizer->getMat("labels"); + for(int i = 0; i < labels.rows; ++i) + { + outLabels.insert(labels.at(i, 0)); + } + } +} + +} /* anonymous namespace */ + +FaceRecognitionModelConfig::FaceRecognitionModelConfig() : + mModelType(MEDIA_VISION_FACE_MODEL_TYPE_UNKNOWN), + mNumComponents(0), + mThreshold(DBL_MAX), + mRadius(1), + mNeighbors(8), + mGridX(8), + mGridY(8), + mImgWidth(150), + mImgHeight(150) +{ + ; /* NULL */ +} + +FaceRecognitionResults::FaceRecognitionResults() : + mIsRecognized(false), + mFaceLabel(-1), + mConfidence(0.0) +{ + ; /* NULL */ +} + +bool FaceRecognitionModelConfig::operator!=( + const FaceRecognitionModelConfig& other) const +{ + return mModelType != other.mModelType || + mNumComponents != other.mNumComponents || + mThreshold != other.mThreshold || + mRadius != other.mRadius || + mNeighbors != other.mNeighbors || + mGridX != other.mGridX || + mGridY != other.mGridY || + mImgWidth != other.mImgWidth || + mImgHeight != other.mImgHeight; +} + +FaceRecognitionModel::FaceRecognitionModel() : + m_canRecognize(false), + m_recognizer(NULL) +{ + ; /* NULL */ +} + +FaceRecognitionModel::FaceRecognitionModel(const FaceRecognitionModel& origin) : + m_canRecognize(origin.m_canRecognize), + m_faceSamples(origin.m_faceSamples), + m_learnAlgorithmConfig(origin.m_learnAlgorithmConfig), + m_recognizer(CreateRecognitionAlgorithm(origin.m_learnAlgorithmConfig)), + m_learnedLabels(origin.m_learnedLabels) +{ + if (!m_recognizer.empty()) + { + CopyOpenCVAlgorithmParameters(origin.m_recognizer, m_recognizer); + } +} + +FaceRecognitionModel& FaceRecognitionModel::operator=( + const FaceRecognitionModel& copy) +{ + if (this != ©) + { + m_canRecognize = copy.m_canRecognize; + m_faceSamples = copy.m_faceSamples; + m_learnAlgorithmConfig = copy.m_learnAlgorithmConfig; + m_recognizer = CreateRecognitionAlgorithm(m_learnAlgorithmConfig); + m_learnedLabels = copy.m_learnedLabels; + + if (!m_recognizer.empty()) + { + CopyOpenCVAlgorithmParameters(copy.m_recognizer, m_recognizer); + } + } + + return *this; +} + +FaceRecognitionModel::~FaceRecognitionModel() +{ + ; /* NULL */ +} + +int FaceRecognitionModel::save(const std::string& fileName) +{ + if (!m_recognizer.empty()) + { + /* find directory */ + std::string prefix_path = std::string(app_get_data_path()); + LOGD("prefix_path: %s", prefix_path.c_str()); + + std::string filePath; + filePath += prefix_path; + filePath += fileName; + + /* check the directory is available */ + std::string prefix_path_check = filePath.substr(0, filePath.find_last_of('/')); + if (access(prefix_path_check.c_str(),F_OK)) + { + LOGE("Can't save recognition model. Path[%s] doesn't existed.", prefix_path_check.c_str()); + + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + cv::FileStorage storage(filePath, cv::FileStorage::WRITE); + if (!storage.isOpened()) + { + LOGE("Can't save recognition model. Write to file permission denied."); + return MEDIA_VISION_ERROR_PERMISSION_DENIED; + } + + switch (m_learnAlgorithmConfig.mModelType) + { + case MEDIA_VISION_FACE_MODEL_TYPE_EIGENFACES: + storage << "algorithm" << "Eigenfaces"; + break; + case MEDIA_VISION_FACE_MODEL_TYPE_FISHERFACES: + storage << "algorithm" << "Fisherfaces"; + break; + case MEDIA_VISION_FACE_MODEL_TYPE_LBPH: + storage << "algorithm" << "LBPH"; + break; + default: + storage.release(); + return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT; + } + + storage << "can_recognize" << m_canRecognize; + m_recognizer->save(storage); + + storage.release(); + } + else + { + LOGE("Attempt to save recognition model before learn"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + return MEDIA_VISION_ERROR_NONE; +} + +int FaceRecognitionModel::load(const std::string& fileName) +{ + /* find directory */ + std::string prefix_path = std::string(app_get_data_path()); + LOGD("prefix_path: %s", prefix_path.c_str()); + + std::string filePath; + filePath += prefix_path; + filePath += fileName; + + if (access(filePath.c_str(),F_OK)) + { + LOGE("Can't load face recognition model. File[%s] doesn't exist.", filePath.c_str()); + + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + cv::FileStorage storage(filePath, cv::FileStorage::READ); + if (!storage.isOpened()) + { + LOGE("Can't load recognition model. Read from file permission denied."); + + return MEDIA_VISION_ERROR_PERMISSION_DENIED; + } + + LOGD("Loading recognition model from file."); + + std::string algName; + int canRecognize = 0; + storage["algorithm"] >> algName; + storage["can_recognize"] >> canRecognize; + + cv::Ptr tempRecognizer; + FaceRecognitionModelConfig tempConfig; + std::set tempLearnedLabels; + + if (algName == "Eigenfaces") + { + tempRecognizer = cv::createEigenFaceRecognizer(); + tempRecognizer->load(storage); + tempConfig.mModelType = + MEDIA_VISION_FACE_MODEL_TYPE_EIGENFACES; + tempConfig.mNumComponents = + tempRecognizer->getInt("ncomponents"); + ParseOpenCVLabels(tempRecognizer, tempLearnedLabels); + } + else if (algName == "Fisherfaces") + { + tempRecognizer = cv::createFisherFaceRecognizer(); + tempRecognizer->load(storage); + tempConfig.mModelType = + MEDIA_VISION_FACE_MODEL_TYPE_FISHERFACES; + tempConfig.mNumComponents = + tempRecognizer->getInt("ncomponents"); + ParseOpenCVLabels(tempRecognizer, tempLearnedLabels); + } + else if (algName == "LBPH") + { + tempRecognizer = cv::createLBPHFaceRecognizer(); + tempRecognizer->load(storage); + tempConfig.mModelType = + MEDIA_VISION_FACE_MODEL_TYPE_LBPH; + tempConfig.mGridX = tempRecognizer->getInt("grid_x"); + tempConfig.mGridY = tempRecognizer->getInt("grid_y"); + tempConfig.mNeighbors = tempRecognizer->getInt("neighbors"); + tempConfig.mRadius = tempRecognizer->getInt("radius"); + ParseOpenCVLabels(tempRecognizer, tempLearnedLabels); + } + else + { + tempConfig = FaceRecognitionModelConfig(); + LOGE("Failed to load face recognition model from file. File is in " + "unsupported format"); + + storage.release(); + + return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT; + } + + tempConfig.mThreshold = tempRecognizer->getDouble("threshold"); + + LOGD("Recognition model of [%s] type has been loaded from file", + algName.c_str()); + + storage.release(); + + m_recognizer = tempRecognizer; + m_learnAlgorithmConfig = tempConfig; + m_canRecognize = (canRecognize == 1); + m_learnedLabels.clear(); + m_learnedLabels = tempLearnedLabels; + + return MEDIA_VISION_ERROR_NONE; +} + +int FaceRecognitionModel::addFaceExample( + const cv::Mat& faceImage, + int faceLabel) +{ + m_faceSamples[faceLabel].push_back(faceImage); + + LOGD("Added face image example for label %i for recognition model", + faceLabel); + + return MEDIA_VISION_ERROR_NONE; +} + +int FaceRecognitionModel::resetFaceExamples(void) +{ + m_faceSamples.clear(); + + LOGD("All face image examples have been removed from recognition model"); + + return MEDIA_VISION_ERROR_NONE; +} + +int FaceRecognitionModel::resetFaceExamples(int faceLabel) +{ + if (1 > m_faceSamples.erase(faceLabel)) + { + LOGD("Failed to remove face image examples for label %i. " + "No such examples", faceLabel); + + return MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE; + } + + LOGD("Face image examples for label %i have been removed from " + "recognition model", faceLabel); + + return MEDIA_VISION_ERROR_NONE; +} + +const std::set& FaceRecognitionModel::getFaceLabels(void) const +{ + return m_learnedLabels; +} + +int FaceRecognitionModel::learn(const FaceRecognitionModelConfig& config) +{ + bool isIncremental = false; + bool isUnisize = false; + + if (MEDIA_VISION_FACE_MODEL_TYPE_LBPH == config.mModelType) + { + isIncremental = true; + } + + if (MEDIA_VISION_FACE_MODEL_TYPE_EIGENFACES == config.mModelType || + MEDIA_VISION_FACE_MODEL_TYPE_FISHERFACES == config.mModelType) + { + isUnisize = true; + } + + std::vector samples; + std::vector labels; + std::set learnedLabels; + + if (isIncremental) + { + learnedLabels.insert(m_learnedLabels.begin(), m_learnedLabels.end()); + } + + std::map >::const_iterator it = + m_faceSamples.begin(); + for (; it != m_faceSamples.end(); ++it) + { + const size_t faceClassSamplesSize = it->second.size(); + labels.insert(labels.end(), faceClassSamplesSize, it->first); + learnedLabels.insert(it->first); + + if (!isUnisize) + { + LOGD("%u examples has been added with label %i", + it->second.size(), it->first); + samples.insert(samples.end(), it->second.begin(), it->second.end()); + } + else + { + for (size_t sampleInd = 0; sampleInd < faceClassSamplesSize; ++sampleInd) + { + cv::Mat resizedSample; + cv::resize(it->second[sampleInd], + resizedSample, + cv::Size(config.mImgWidth, config.mImgHeight), + 1.0, 1.0, cv::INTER_CUBIC); + samples.push_back(resizedSample); + } + } + } + + const size_t samplesSize = samples.size(); + const size_t labelsSize = labels.size(); + + if (0 != samplesSize && samplesSize == labelsSize) + { + LOGD("Start to learn the model for %u samples and %u labels", + samplesSize, labelsSize); + + if (m_learnAlgorithmConfig != config || m_recognizer.empty()) + { + m_recognizer = CreateRecognitionAlgorithm(config); + } + + if (m_recognizer.empty()) + { + LOGE("Can't create recognition algorithm for recognition model. " + "Configuration is not supported by any of known algorithms."); + + return MEDIA_VISION_ERROR_NOT_SUPPORTED; + } + + isIncremental ? m_recognizer->update(samples, labels) : + m_recognizer->train(samples, labels); + m_canRecognize = true; + m_learnedLabels.clear(); + m_learnedLabels = learnedLabels; + } + else + { + LOGE("Can't create recognition algorithm for no examples. Try to add " + "some face examples before learning"); + + return MEDIA_VISION_ERROR_NO_DATA; + } + + m_learnAlgorithmConfig = config; + + LOGD("Recognition model has been learned"); + + return MEDIA_VISION_ERROR_NONE; +} + +int FaceRecognitionModel::recognize(const cv::Mat& image, FaceRecognitionResults& results) +{ + if (!m_recognizer.empty() && m_canRecognize) + { + double absConf = 0.0; + m_recognizer->predict(image, results.mFaceLabel, absConf); + // Normalize the absolute value of the confidence + absConf = exp(7.5 - (0.05 * absConf)); + results.mConfidence = absConf / (1 + absConf); + results.mIsRecognized = true; + results.mFaceLocation = cv::Rect(0, 0, image.cols, image.rows); + } + else + { + LOGE("Attempt to recognize faces with untrained model"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + return MEDIA_VISION_ERROR_NONE; +} + +cv::Ptr FaceRecognitionModel::CreateRecognitionAlgorithm( + const FaceRecognitionModelConfig& config) +{ + cv::Ptr tempRecognizer; + switch (config.mModelType) + { + case MEDIA_VISION_FACE_MODEL_TYPE_EIGENFACES: + tempRecognizer = cv::createEigenFaceRecognizer( + config.mNumComponents, + config.mThreshold); + break; + case MEDIA_VISION_FACE_MODEL_TYPE_FISHERFACES: + tempRecognizer = cv::createFisherFaceRecognizer( + config.mNumComponents, + config.mThreshold); + break; + case MEDIA_VISION_FACE_MODEL_TYPE_LBPH: + tempRecognizer = cv::createLBPHFaceRecognizer( + config.mRadius, + config.mNeighbors, + config.mGridX, + config.mGridY, + config.mThreshold); + break; + default: + return NULL; + } + + return tempRecognizer; +} + +} /* Face */ +} /* MediaVision */ diff --git a/mv_face/face/src/FaceTrackingModel.cpp b/mv_face/face/src/FaceTrackingModel.cpp new file mode 100644 index 0000000..2c4fdd6 --- /dev/null +++ b/mv_face/face/src/FaceTrackingModel.cpp @@ -0,0 +1,217 @@ +/** + * 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 "FaceTrackingModel.h" + +#include + +#include "mv_private.h" +#include "mv_common.h" + +#include + +namespace MediaVision +{ +namespace Face +{ + +FaceTrackingResults::FaceTrackingResults() : + mIsTracked(false), + mConfidence(0.f) +{ + ; /* NULL */ +} + +FaceTrackingModel::FaceTrackingModel() : + m_canTrack(false), + m_tracker(new cv::TrackerMedianFlow()) +{ + ; /* NULL */ +} + +FaceTrackingModel::FaceTrackingModel(const FaceTrackingModel& origin) : + m_canTrack(origin.m_canTrack), + m_tracker(new cv::TrackerMedianFlow()) +{ + if (!origin.m_tracker.empty()) + { + origin.m_tracker->copyTo(*(m_tracker.obj)); + } +} + +FaceTrackingModel& FaceTrackingModel::operator=(const FaceTrackingModel& copy) +{ + if (this != ©) + { + m_canTrack = copy.m_canTrack; + m_tracker = cv::Ptr(new cv::TrackerMedianFlow()); + if (!copy.m_tracker.empty()) + { + copy.m_tracker->copyTo(*(m_tracker.obj)); + } + } + + return *this; +} + +FaceTrackingModel::~FaceTrackingModel() +{ + ; /* NULL */ +} + +int FaceTrackingModel::save(const std::string& fileName) +{ + if (m_tracker.empty()) + { + LOGE("Can't save tracking model. No tracking algorithm is used"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + std::string prefix_path = std::string(app_get_data_path()); + LOGD("prefix_path: %s", prefix_path.c_str()); + + std::string filePath; + filePath += prefix_path; + filePath += fileName; + + /* check the directory is available */ + std::string prefix_path_check = filePath.substr(0, filePath.find_last_of('/')); + if (access(prefix_path_check.c_str(),F_OK)) + { + LOGE("Can't save tracking model. Path[%s] doesn't existed.", prefix_path_check.c_str()); + + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + cv::FileStorage storage(filePath, cv::FileStorage::WRITE); + if (!storage.isOpened()) + { + LOGE("Can't save tracking model. Write to file permission denied."); + return MEDIA_VISION_ERROR_PERMISSION_DENIED; + } + + LOGD("Storing tracking model to the file started."); + + storage << "canTrack" << (m_canTrack ? 1 : 0); + m_tracker->write(storage); + + LOGD("Storing tracking model to the file finished."); + + storage.release(); + + return MEDIA_VISION_ERROR_NONE; +} + +int FaceTrackingModel::load(const std::string& fileName) +{ + /* find directory */ + std::string prefix_path = std::string(app_get_data_path()); + LOGD("prefix_path: %s", prefix_path.c_str()); + + std::string filePath; + filePath += prefix_path; + filePath += fileName; + + if (access(filePath.c_str(), F_OK)) + { + LOGE("Can't load face tracking model. File[%s] doesn't exist.", filePath.c_str()); + + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + cv::FileStorage storage(filePath, cv::FileStorage::READ); + if (!storage.isOpened()) + { + LOGE("Can't load tracking model. Read from file permission denied."); + return MEDIA_VISION_ERROR_PERMISSION_DENIED; + } + + int canTrack = 0; + storage["canTrack"] >> canTrack; + m_canTrack = (0 != canTrack); + m_tracker->read(storage); + + LOGD("Loading tracking model from file."); + + storage.release(); + + return MEDIA_VISION_ERROR_NONE; +} + +int FaceTrackingModel::prepare(const cv::Mat& image) +{ + if (m_tracker.empty()) + { + LOGE("Failed to prepare tracking model. No tracking algorithm " + "is available."); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + cv::Rect_ lastBoundingBox; + if (!m_tracker->isInited()) + { + lastBoundingBox.x = 0; + lastBoundingBox.y = 0; + lastBoundingBox.width = image.cols; + lastBoundingBox.height = image.rows; + } + else + { + lastBoundingBox = m_tracker->getLastBoundingBox(); + } + + return prepare(image, lastBoundingBox); +} + +int FaceTrackingModel::prepare( + const cv::Mat& image, + const cv::Rect_& boundingBox) +{ + if (m_tracker.empty()) + { + LOGE("Failed to prepare tracking model. No tracking algorithm " + "is available."); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + if (!m_tracker->init(image, boundingBox)) + { + LOGE("Failed to prepare tracking model."); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + m_canTrack = true; + return MEDIA_VISION_ERROR_NONE; +} + +int FaceTrackingModel::track(const cv::Mat& image, FaceTrackingResults& results) +{ + if (!m_tracker.empty() && m_canTrack) + { + results.mIsTracked = m_tracker->update(image, results.mFaceLocation); + results.mConfidence = m_tracker->getLastConfidence(); + } + else + { + LOGE("Attempt to track face with not prepared model"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + return MEDIA_VISION_ERROR_NONE; +} + +} /* Face */ +} /* MediaVision */ diff --git a/mv_face/face/src/FaceUtil.cpp b/mv_face/face/src/FaceUtil.cpp new file mode 100644 index 0000000..7d49dd3 --- /dev/null +++ b/mv_face/face/src/FaceUtil.cpp @@ -0,0 +1,138 @@ +/** + * 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 "FaceUtil.h" + +#include "mv_private.h" + +#include +#include + +namespace MediaVision +{ +namespace Face +{ + +RecognitionParams::RecognitionParams(FaceRecognitionModelType algType) : + mRecognitionAlgType(algType) +{ + ; /* NULL */ +} + +RecognitionParams::RecognitionParams() : + mRecognitionAlgType(MEDIA_VISION_FACE_MODEL_TYPE_LBPH) +{ + ; /* NULL */ +} + +int convertSourceMV2GrayCV(mv_source_h mvSource, cv::Mat& cvSource) +{ + MEDIA_VISION_INSTANCE_CHECK(mvSource); + + int depth = CV_8U; // Default depth. 1 byte for 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; +} + +} /* Face */ +} /* MediaVision */ diff --git a/mv_face/face/src/TrackerMedianFlow.cpp b/mv_face/face/src/TrackerMedianFlow.cpp new file mode 100644 index 0000000..a7a3b4f --- /dev/null +++ b/mv_face/face/src/TrackerMedianFlow.cpp @@ -0,0 +1,460 @@ +/*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) 2013, OpenCV Foundation, 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 "TrackerMedianFlow.h" + +#include "opencv2/video/tracking.hpp" +#include "opencv2/imgproc/imgproc.hpp" + +#include +#include + +namespace +{ + float FloatEps = 10e-6f; +} /* anonymous namespace */ + +namespace cv +{ + +TrackerMedianFlow::Params::Params() +{ + mPointsInGrid = 10; + mWindowSize = Size(3, 3); + mPyrMaxLevel = 5; +} + +void TrackerMedianFlow::Params::read( const cv::FileNode& fn ) +{ + mPointsInGrid = fn["pointsInGrid"]; + int winSizeHeight = fn["windowSizeHeight"]; + int winSizeWidth = fn["windowSizeWidth"]; + mWindowSize = Size(winSizeHeight, winSizeWidth); + mPyrMaxLevel = fn["pyrMaxLevel"]; +} + +void TrackerMedianFlow::Params::write( cv::FileStorage& fs ) const +{ + fs << "pointsInGrid" << mPointsInGrid; + fs << "windowSizeHeight" << mWindowSize.height; + fs << "windowSizeWidth" << mWindowSize.width; + fs << "pyrMaxLevel" << mPyrMaxLevel; +} + +TrackerMedianFlow::TrackerMedianFlow(Params paramsIn) : + termcrit(TermCriteria::COUNT | TermCriteria::EPS,20,0.3), + m_confidence(0.0) +{ + params = paramsIn; + isInit = false; +} + +bool TrackerMedianFlow::copyTo(TrackerMedianFlow& copy) const +{ + copy.isInit = isInit; + copy.params = params; + copy.termcrit = termcrit; + copy.m_boundingBox = m_boundingBox; + copy.m_confidence = m_confidence; + m_image.copyTo(copy.m_image); + return true; +} + +bool TrackerMedianFlow::init(const Mat& image, const Rect_& boundingBox) +{ + if (image.empty()) + { + return false; + } + + image.copyTo(m_image); + buildOpticalFlowPyramid( + m_image, m_pyramid, params.mWindowSize, params.mPyrMaxLevel); + m_boundingBox = boundingBox; + + isInit = true; + return isInit; +} + +bool TrackerMedianFlow::update(const Mat& image, Rect_& boundingBox) +{ + if (!isInit || image.empty()) return false; + + // Handles such behaviour when preparation frame has the size + // different to the tracking frame size. In such case, we resize preparation + // frame and bounding box. Then, track as usually: + if (m_image.rows != image.rows || m_image.cols != image.cols) + { + const float xFactor = (float) image.cols / m_image.cols; + const float yFactor = (float) image.rows / m_image.rows; + + resize(m_image, m_image, Size(), xFactor, yFactor); + + m_boundingBox.x *= xFactor; + m_boundingBox.y *= yFactor; + m_boundingBox.width *= xFactor; + m_boundingBox.height *= yFactor; + } + + Mat oldImage = m_image; + + Rect_ oldBox = m_boundingBox; + if(!medianFlowImpl(oldImage, image, oldBox)) + { + return false; + } + + boundingBox = oldBox; + image.copyTo(m_image); + m_boundingBox = boundingBox; + return true; +} + +bool TrackerMedianFlow::isInited() const +{ + return isInit; +} + +float TrackerMedianFlow::getLastConfidence() const +{ + return m_confidence; +} + +Rect_ TrackerMedianFlow::getLastBoundingBox() const +{ + return m_boundingBox; +} + +bool TrackerMedianFlow::medianFlowImpl( + Mat oldImage_gray, Mat newImage_gray, Rect_& oldBox) +{ + std::vector pointsToTrackOld, pointsToTrackNew; + + const float gridXStep = oldBox.width / params.mPointsInGrid; + const float gridYStep = oldBox.height / params.mPointsInGrid; + for (int i = 0; i < params.mPointsInGrid; i++) + { + for (int j = 0; j < params.mPointsInGrid; j++) + { + pointsToTrackOld.push_back( + Point2f(oldBox.x + .5f*gridXStep + 1.f*gridXStep*j, + oldBox.y + .5f*gridYStep + 1.f*gridYStep*i)); + } + } + + std::vector status(pointsToTrackOld.size()); + std::vector errors(pointsToTrackOld.size()); + + std::vector tempPyramid; + buildOpticalFlowPyramid( + newImage_gray, + tempPyramid, + params.mWindowSize, + params.mPyrMaxLevel); + + calcOpticalFlowPyrLK(m_pyramid, + tempPyramid, + pointsToTrackOld, + pointsToTrackNew, + status, + errors, + params.mWindowSize, + params.mPyrMaxLevel, + termcrit); + + std::vector di; + for (size_t idx = 0u; idx < pointsToTrackOld.size(); idx++) + { + if (status[idx] == 1) + { + di.push_back(pointsToTrackNew[idx] - pointsToTrackOld[idx]); + } + } + + std::vector filter_status; + check_FB(tempPyramid, + pointsToTrackOld, + pointsToTrackNew, + filter_status); + check_NCC(oldImage_gray, + newImage_gray, + pointsToTrackOld, + pointsToTrackNew, + filter_status); + + for (size_t idx = 0u; idx < pointsToTrackOld.size(); idx++) + { + if (!filter_status[idx]) + { + pointsToTrackOld.erase(pointsToTrackOld.begin() + idx); + pointsToTrackNew.erase(pointsToTrackNew.begin() + idx); + filter_status.erase(filter_status.begin() + idx); + idx--; + } + } + + if (pointsToTrackOld.size() == 0 || di.size() == 0) + { + return false; + } + + Point2f mDisplacement; + Rect_ boxCandidate = + vote(pointsToTrackOld, pointsToTrackNew, oldBox, mDisplacement); + + std::vector displacements; + for (size_t idx = 0u; idx < di.size(); idx++) + { + di[idx] -= mDisplacement; + displacements.push_back(sqrt(di[idx].ddot(di[idx]))); + } + + m_confidence = + (10.f - getMedian(displacements,(int)displacements.size())) / 10.f; + if (m_confidence <= 0.f) + { + m_confidence = 0.f; + return false; + } + + m_pyramid.swap(tempPyramid); + oldBox = boxCandidate; + return true; +} + +Rect_ TrackerMedianFlow::vote( + const std::vector& oldPoints, + const std::vector& newPoints, + const Rect_& oldRect, + Point2f& mD) +{ + Rect_ newRect; + Point2d newCenter(oldRect.x + oldRect.width/2.0, + oldRect.y + oldRect.height/2.0); + + int n = (int)oldPoints.size(); + std::vector buf(std::max( n*(n-1) / 2, 3), 0.f); + + if(oldPoints.size() == 1) + { + newRect.x = oldRect.x+newPoints[0].x-oldPoints[0].x; + newRect.y = oldRect.y+newPoints[0].y-oldPoints[0].y; + newRect.width=oldRect.width; + newRect.height=oldRect.height; + return newRect; + } + + float xshift = 0.f; + float yshift = 0.f; + for(int i = 0; i < n; i++) + { + buf[i] = newPoints[i].x - oldPoints[i].x; + } + + xshift = getMedian(buf, n); + newCenter.x += xshift; + for(int idx = 0; idx < n; idx++) + { + buf[idx] = newPoints[idx].y - oldPoints[idx].y; + } + + yshift = getMedian(buf, n); + newCenter.y += yshift; + mD = Point2f(xshift, yshift); + + if(oldPoints.size() == 1) + { + newRect.x = newCenter.x - oldRect.width / 2.0; + newRect.y = newCenter.y - oldRect.height / 2.0; + newRect.width = oldRect.width; + newRect.height = oldRect.height; + return newRect; + } + + float nd = 0.f; + float od = 0.f; + for (int i = 0, ctr = 0; i < n; i++) + { + for(int j = 0; j < i; j++) + { + nd = l2distance(newPoints[i], newPoints[j]); + od = l2distance(oldPoints[i], oldPoints[j]); + buf[ctr] = (od == 0.f ? 0.f : nd / od); + ctr++; + } + } + + float scale = getMedian(buf, n*(n-1) / 2); + newRect.x = newCenter.x - scale * oldRect.width / 2.f; + newRect.y = newCenter.y-scale * oldRect.height / 2.f; + newRect.width = scale * oldRect.width; + newRect.height = scale * oldRect.height; + + return newRect; +} + +template +T TrackerMedianFlow::getMedian(std::vector& values, int size) +{ + if (size == -1) + { + size = (int)values.size(); + } + + std::vector copy(values.begin(), values.begin() + size); + std::sort(copy.begin(),copy.end()); + if(size%2==0) + { + return (copy[size/2-1]+copy[size/2])/((T)2.0); + } + else + { + return copy[(size - 1) / 2]; + } +} + +float TrackerMedianFlow::l2distance(Point2f p1, Point2f p2) +{ + float dx = p1.x - p2.x; + float dy = p1.y - p2.y; + return sqrt(dx * dx + dy * dy); +} + +void TrackerMedianFlow::check_FB( + std::vector newPyramid, + const std::vector& oldPoints, + const std::vector& newPoints, + std::vector& status) +{ + if(status.size() == 0) + { + status = std::vector(oldPoints.size(), true); + } + + std::vector LKstatus(oldPoints.size()); + std::vector errors(oldPoints.size()); + std::vector FBerror(oldPoints.size()); + std::vector pointsToTrackReprojection; + + calcOpticalFlowPyrLK(newPyramid, + m_pyramid, + newPoints, + pointsToTrackReprojection, + LKstatus, + errors, + params.mWindowSize, + params.mPyrMaxLevel, + termcrit); + + for (size_t idx = 0u; idx < oldPoints.size(); idx++) + { + FBerror[idx] = l2distance(oldPoints[idx], pointsToTrackReprojection[idx]); + } + + float FBerrorMedian = getMedian(FBerror) + FloatEps; + for (size_t idx = 0u; idx < oldPoints.size(); idx++) + { + status[idx] = (FBerror[idx] < FBerrorMedian); + } +} + +void TrackerMedianFlow::check_NCC( + const Mat& oldImage, + const Mat& newImage, + const std::vector& oldPoints, + const std::vector& newPoints, + std::vector& status) +{ + std::vector NCC(oldPoints.size(), 0.f); + Size patch(30, 30); + Mat p1; + Mat p2; + + for (size_t idx = 0u; idx < oldPoints.size(); idx++) + { + getRectSubPix(oldImage, patch, oldPoints[idx], p1); + getRectSubPix(newImage, patch, newPoints[idx], p2); + + const int N = 900; + const float s1 = sum(p1)(0); + const float s2 = sum(p2)(0); + const float n1 = norm(p1); + const float n2 = norm(p2); + const float prod = p1.dot(p2); + const float sq1 = sqrt(n1 * n1 - s1 * s1 / N); + const float sq2 = sqrt(n2 * n2 - s2 * s2 / N); + NCC[idx] = (sq2==0 ? sq1 / std::abs(sq1) + : (prod - s1 * s2 / N) / sq1 / sq2); + } + + float median = getMedian(NCC) - FloatEps; + for(size_t idx = 0u; idx < oldPoints.size(); idx++) + { + status[idx] = status[idx] && (NCC[idx] > median); + } +} + +void TrackerMedianFlow::read( cv::FileStorage& fs ) +{ + params.read(fs.root()); + float bbX = 0.f; + float bbY = 0.f; + float bbW = 0.f; + float bbH = 0.f; + fs["lastLocationX"] >> bbX; + fs["lastLocationY"] >> bbY; + fs["lastLocationW"] >> bbW; + fs["lastLocationH"] >> bbH; + m_boundingBox = Rect_(bbX, bbY, bbW, bbH); + fs["lastImage"] >> m_image; +} + +void TrackerMedianFlow::write( cv::FileStorage& fs ) const +{ + params.write(fs); + fs << "lastLocationX" << m_boundingBox.x; + fs << "lastLocationY" << m_boundingBox.y; + fs << "lastLocationW" << m_boundingBox.width; + fs << "lastLocationH" << m_boundingBox.height; + fs << "lastImage" << m_image; +} + +} /* namespace cv */ diff --git a/mv_face/face/src/mv_face_open.cpp b/mv_face/face/src/mv_face_open.cpp new file mode 100644 index 0000000..41f2398 --- /dev/null +++ b/mv_face/face/src/mv_face_open.cpp @@ -0,0 +1,1048 @@ +/** + * 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_face_open.h" + +#include "FaceDetector.h" +#include "FaceUtil.h" +#include "FaceRecognitionModel.h" +#include "FaceTrackingModel.h" +#include "FaceEyeCondition.h" +#include "FaceExpressionRecognizer.h" + +#include "mv_private.h" + +#include +#include +#include + +using namespace ::MediaVision::Face; + +static const RecognitionParams defaultRecognitionParams = RecognitionParams(); + +static void extractRecognitionParams( + mv_engine_config_h engine_cfg, + RecognitionParams& recognitionParams) +{ + mv_engine_config_h working_cfg = NULL; + + if (NULL == engine_cfg) + { + mv_create_engine_config(&working_cfg); + } + else + { + working_cfg = engine_cfg; + } + + int algType = 0; + mv_engine_config_get_int_attribute_c( + working_cfg, + "MV_FACE_RECOGNITION_MODEL_TYPE", + &algType); + + if (0 < algType && 4 > algType) + { + recognitionParams.mRecognitionAlgType = + (FaceRecognitionModelType)algType; + } + else + { + recognitionParams.mRecognitionAlgType = + defaultRecognitionParams.mRecognitionAlgType; + } + + if (NULL == engine_cfg) + { + mv_destroy_engine_config(working_cfg); + } +} + +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; +} + +int mv_face_detect_open( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_face_detected_cb detected_cb, + void *user_data) +{ + cv::Mat image; + + int error = convertSourceMV2GrayCV(source, image); + if (error != MEDIA_VISION_ERROR_NONE) + { + LOGE("Convertion mv_source_h to gray failed"); + return error; + } + + char *haarcascadeFilepath; + error = mv_engine_config_get_string_attribute_c( + engine_cfg, + "MV_FACE_DETECTION_MODEL_FILE_PATH", + &haarcascadeFilepath); + + //default path + std::string haarcascadeFilePathStr = + "/usr/share/OpenCV/haarcascades/haarcascade_frontalface_alt2.xml"; + + if (error == MEDIA_VISION_ERROR_NONE) + { + LOGI("Haarcascade file was set as default"); + haarcascadeFilePathStr = std::string(haarcascadeFilepath); + + delete[] haarcascadeFilepath; + } + else + { + LOGE("Error occurred during face detection haarcascade file receiving." + " (%i)", error); + } + + static FaceDetector faceDetector; + + if (!faceDetector.loadHaarcascade(haarcascadeFilePathStr)) + { + LOGE("Loading Haarcascade failed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + cv::Rect roi(-1, -1, -1, -1); + error = mv_engine_config_get_int_attribute_c( + engine_cfg, + MV_FACE_DETECTION_ROI_X, + &roi.x); + if (error != MEDIA_VISION_ERROR_NONE) + { + LOGE("Error occurred during face detection roi (x) receiving." + " (%i)", error); + } + + error = mv_engine_config_get_int_attribute_c( + engine_cfg, + MV_FACE_DETECTION_ROI_Y, + &roi.y); + if (error != MEDIA_VISION_ERROR_NONE) + { + LOGE("Error occurred during face detection roi (y) receiving." + " (%i)", error); + } + + error = mv_engine_config_get_int_attribute_c( + engine_cfg, + MV_FACE_DETECTION_ROI_WIDTH, + &roi.width); + if (error != MEDIA_VISION_ERROR_NONE) + { + LOGE("Error occurred during face detection roi (width) receiving." + " (%i)", error); + } + + error = mv_engine_config_get_int_attribute_c( + engine_cfg, + MV_FACE_DETECTION_ROI_HEIGHT, + &roi.height); + if (error != MEDIA_VISION_ERROR_NONE) + { + LOGE("Error occurred during face detection roi (height) receiving." + " (%i)", error); + } + + cv::Size minSize(-1, -1); + error = mv_engine_config_get_int_attribute_c( + engine_cfg, + MV_FACE_DETECTION_MIN_SIZE_WIDTH, + &minSize.width); + if (error != MEDIA_VISION_ERROR_NONE) + { + LOGE("Error occurred during face detection minimum width receiving." + " (%i)", error); + } + + error = mv_engine_config_get_int_attribute_c( + engine_cfg, + MV_FACE_DETECTION_MIN_SIZE_HEIGHT, + &minSize.height); + if (error != MEDIA_VISION_ERROR_NONE) + { + LOGE("Error occurred during face detection minimum height receiving." + " (%i)", error); + } + + std::vector faceLocations; + if (!faceDetector.detectFaces(image, roi, minSize, faceLocations)) + { + LOGE("Face detection in OpenCV failed"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + static const int StartMaxResultsNumber = 50; + static std::vector results(StartMaxResultsNumber); + + const int numberOfResults = faceLocations.size(); + if (numberOfResults > StartMaxResultsNumber) + { + results.resize(numberOfResults); + } + + for(int rectNum = 0; rectNum < numberOfResults; ++rectNum) + { + convertRectCV2MV(faceLocations[rectNum], results[rectNum]); + } + + LOGI("Call the detect callback for %i detected faces", numberOfResults); + detected_cb(source, engine_cfg, results.data(), numberOfResults, user_data); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_face_recognize_open( + mv_source_h source, + mv_face_recognition_model_h recognition_model, + mv_engine_config_h engine_cfg, + mv_rectangle_s *face_location, + mv_face_recognized_cb recognized_cb, + void *user_data) +{ + if (!source) + { + LOGE("Can't recognize for the NULL Media Vision source handle"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + if (!recognized_cb) + { + LOGE("Recognition failed. Can't output recognition results without " + "callback function"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + if (!recognition_model) + { + LOGE("Can't recognize for the NULL Media Vision Face recognition model"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + FaceRecognitionModel *pRecModel = static_cast(recognition_model); + + if (!pRecModel) + { + LOGE("Face recognition failed. Incorrect Media Vision Face recognition model handle is used"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + cv::Mat grayImage; + int ret = convertSourceMV2GrayCV(source, grayImage); + + if (MEDIA_VISION_ERROR_NONE != ret) + { + LOGE("Convertion mv_source_h to gray failed"); + return ret; + } + + cv::Mat image; + if (NULL == face_location) + { + image = grayImage; + } + else + { + cv::Rect_ roi; + roi.x = face_location->point.x; + roi.y = face_location->point.y; + roi.width = face_location->width; + roi.height = face_location->height; + image = grayImage(roi); + } + + FaceRecognitionResults results; + + LOGD("Face recognition is started"); + + ret = pRecModel->recognize(image, results); + + if (MEDIA_VISION_ERROR_NONE != ret) + { + LOGE("Error occurred during the recognition. Failed"); + return ret; + } + + if (!results.mIsRecognized) + { + recognized_cb( + source, + recognition_model, + engine_cfg, + NULL, + NULL, + 0.0, + user_data); + } + else + { + mv_rectangle_s location; + location.point.x = results.mFaceLocation.x; + location.point.y = results.mFaceLocation.y; + location.width = results.mFaceLocation.width; + location.height = results.mFaceLocation.height; + + if (face_location != NULL) + { + location.point.x += face_location->point.x; + location.point.y += face_location->point.y; + } + + recognized_cb( + source, + recognition_model, + engine_cfg, + &location, + &(results.mFaceLabel), + results.mConfidence, + user_data); + } + + LOGD("Face recognition is finished"); + + return ret; +} + +int mv_face_track_open( + mv_source_h source, + mv_face_tracking_model_h tracking_model, + mv_engine_config_h engine_cfg, + mv_face_tracked_cb tracked_cb, + bool /*do_learn*/, + void *user_data) +{ + if (!source) + { + LOGE("Can't track for the NULL Media Vision source handle"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + if (!tracked_cb) + { + LOGE("Tracking failed. Can't output tracking results without " + "callback function"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + if (!tracking_model) + { + LOGE("Can't track for the NULL Media Vision Face tracking model"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + FaceTrackingModel *pTrackModel = + static_cast(tracking_model); + + if (!pTrackModel) + { + LOGE("Face tracking failed. " + "Incorrect Media Vision Face tracking model handle is used"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + cv::Mat grayImage; + int ret = convertSourceMV2GrayCV(source, grayImage); + + if (MEDIA_VISION_ERROR_NONE != ret) + { + LOGE("Convertion mv_source_h to gray failed"); + return ret; + } + + FaceTrackingResults results; + ret = pTrackModel->track(grayImage, results); + + if (MEDIA_VISION_ERROR_NONE != ret) + { + LOGE("Tracking can't be performed. " + "Check that tracking model is prepared when tracking starts"); + return ret; + } + + if (results.mIsTracked) + { + mv_quadrangle_s predictedLocation; + predictedLocation.points[0].x = results.mFaceLocation.x; + predictedLocation.points[0].y = results.mFaceLocation.y; + predictedLocation.points[1].x = + results.mFaceLocation.x + results.mFaceLocation.width; + predictedLocation.points[1].y = results.mFaceLocation.y; + predictedLocation.points[2].x = + results.mFaceLocation.x + results.mFaceLocation.width; + predictedLocation.points[2].y = + results.mFaceLocation.y + results.mFaceLocation.height; + predictedLocation.points[3].x = results.mFaceLocation.x; + predictedLocation.points[3].y = + results.mFaceLocation.y + results.mFaceLocation.height; + tracked_cb( + source, + tracking_model, + engine_cfg, + &predictedLocation, + results.mConfidence, + user_data); + } + else + { + tracked_cb( + source, + tracking_model, + engine_cfg, + NULL, + results.mConfidence, + user_data); + } + + return ret; +} + +int mv_face_eye_condition_recognize_open( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s face_location, + mv_face_eye_condition_recognized_cb eye_condition_recognized_cb, + void *user_data) +{ + cv::Mat image; + + int error = convertSourceMV2GrayCV(source, image); + if (error != MEDIA_VISION_ERROR_NONE) + { + LOGE("Convertion mv_source_h to gray failed"); + return error; + } + + mv_face_eye_condition_e eye_condition; + error = FaceEyeCondition::recognizeEyeCondition( + image, + face_location, + &eye_condition); + + if (error != MEDIA_VISION_ERROR_NONE) + { + LOGE("eye contition recognition failed"); + return error; + } + + eye_condition_recognized_cb( + source, + engine_cfg, + face_location, + eye_condition, + user_data); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_face_facial_expression_recognize_open( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s face_location, + mv_face_facial_expression_recognized_cb expression_recognized_cb, + void *user_data) +{ + cv::Mat image; + + int error = convertSourceMV2GrayCV(source, image); + if (error != MEDIA_VISION_ERROR_NONE) + { + LOGE("Convertion mv_source_h to gray failed"); + return error; + } + + mv_face_facial_expression_e expression; + error = FaceExpressionRecognizer::recognizeFaceExpression( + image, face_location, &expression); + + if (error != MEDIA_VISION_ERROR_NONE) + { + LOGE("eye contition recognition failed"); + return error; + } + + expression_recognized_cb( + source, + engine_cfg, + face_location, + expression, + user_data); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_face_recognition_model_create_open( + mv_face_recognition_model_h *recognition_model) +{ + if (recognition_model == NULL) + { + LOGE("Recognition model can't be created because handle pointer is NULL"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + (*recognition_model) = + static_cast(new (std::nothrow)FaceRecognitionModel()); + + if (*recognition_model == NULL) + { + LOGE("Failed to create media vision recognition model"); + return MEDIA_VISION_ERROR_OUT_OF_MEMORY; + } + + LOGD("Recognition model [%p] has been created", *recognition_model); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_face_recognition_model_destroy_open( + mv_face_recognition_model_h recognition_model) +{ + if (!recognition_model) + { + LOGE("Recognition model can't be destroyed because handle is NULL"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + LOGD("Destroying media vision recognition model [%p]", recognition_model); + delete static_cast(recognition_model); + LOGD("Media vision recognition model has been destroyed"); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_face_recognition_model_clone_open( + mv_face_recognition_model_h src, + mv_face_recognition_model_h *dst) +{ + if (!src || !dst) + { + LOGE("Can't clone recognition model. Both source and destination" + "recognition model handles has to be not NULL"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + (*dst) = static_cast(new (std::nothrow)FaceRecognitionModel()); + + if (*dst == NULL) + { + LOGE("Failed to create media vision recognition model"); + return MEDIA_VISION_ERROR_OUT_OF_MEMORY; + } + + LOGD("Recognition model [%p] has been created", *dst); + + const FaceRecognitionModel *pSrcModel = static_cast(src); + FaceRecognitionModel *pDstModel = static_cast(*dst); + + *pDstModel = *pSrcModel; + + LOGD("Media vision recognition model has been cloned"); + return MEDIA_VISION_ERROR_NONE; +} + +int mv_face_recognition_model_save_open( + const char *file_name, + mv_face_recognition_model_h recognition_model) +{ + if (!recognition_model) + { + LOGE("Can't save recognition model to the file. Handle has to be not NULL"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (NULL == file_name) + { + LOGE("Can't save recognition model to the file. File name has to be specified"); + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + FaceRecognitionModel *pRecModel = static_cast(recognition_model); + const int ret = pRecModel->save(std::string(file_name)); + + if (MEDIA_VISION_ERROR_NONE != ret) + { + LOGE("Error occurred when save recognition model to the file"); + return ret; + } + + LOGD("Media vision recognition model has been saved to the file [%s]", file_name); + return ret; +} + +int mv_face_recognition_model_load_open( + const char *file_name, + mv_face_recognition_model_h *recognition_model) +{ + if (!recognition_model) + { + LOGE("Can't load recognition model from the file. " + "Handle has to be not NULL"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (NULL == file_name) + { + LOGE("Can't load recognition model from the file. " + "File name has to be specified"); + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + (*recognition_model) = + static_cast(new (std::nothrow)FaceRecognitionModel()); + + if (*recognition_model == NULL) + { + LOGE("Failed to create media vision recognition model"); + return MEDIA_VISION_ERROR_OUT_OF_MEMORY; + } + + FaceRecognitionModel *pRecModel = + static_cast(*recognition_model); + + if (!pRecModel) + { + LOGE("Loading of the face recognition model from file failed. " + "Incorrect Media Vision Face recognition model handle is used"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + const int ret = pRecModel->load(std::string(file_name)); + + if (MEDIA_VISION_ERROR_NONE != ret) + { + LOGE("Error occurred when loading recognition model to the file"); + return ret; + } + + LOGD("Media vision recognition model has been loaded from the file [%s]", file_name); + return ret; +} + +int mv_face_recognition_model_add_open( + const mv_source_h source, + mv_face_recognition_model_h recognition_model, + const mv_rectangle_s *example_location, + int face_label) +{ + if (!source) + { + LOGE("Can't add face image example for recognition model. " + "Media Vision source handle has to be not NULL"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (!recognition_model) + { + LOGE("Can't add face image example for recognition model. " + "Model handle has to be not NULL"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + FaceRecognitionModel *pRecModel = + static_cast(recognition_model); + + if (!pRecModel) + { + LOGE("Add face image example to the model failed. " + "Incorrect Media Vision Face recognition model handle is used"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + cv::Mat image; + int ret = convertSourceMV2GrayCV(source, image); + if (MEDIA_VISION_ERROR_NONE != ret) + { + LOGE("Convertion mv_source_h to gray failed"); + return ret; + } + + if (!example_location) + { + ret = pRecModel->addFaceExample(image, face_label); + } + else + { + cv::Rect_ roi; + roi.x = example_location->point.x; + roi.y = example_location->point.y; + roi.width = example_location->width; + roi.height = example_location->height; + ret = pRecModel->addFaceExample(image(roi).clone(), face_label); + } + + if (MEDIA_VISION_ERROR_NONE != ret) + { + LOGE("Error occurred when adding face image example to the recognition model"); + return ret; + } + + LOGD("The face image example labeled %i has been added " + "to the Media Vision recognition model", face_label); + return ret; +} + +int mv_face_recognition_model_reset_open( + mv_face_recognition_model_h recognition_model, + const int *face_label) +{ + if (!recognition_model) + { + LOGE("Can't reset positive examples for NULL recognition model"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + FaceRecognitionModel *pRecModel = + static_cast(recognition_model); + + if (!pRecModel) + { + LOGE("Loading of the face recognition model from file failed. " + "Incorrect Media Vision Face recognition model handle is used"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + int ret = (NULL != face_label ? + pRecModel->resetFaceExamples(*face_label) : + pRecModel->resetFaceExamples()); + + if (MEDIA_VISION_ERROR_NONE != ret) + { + LOGE("Error occurred when reset positive examples of the recognition model"); + return ret; + } + + LOGD("The positive examples has been removed from recognition model"); + return ret; +} + +int mv_face_recognition_model_learn_open( + mv_engine_config_h engine_cfg, + mv_face_recognition_model_h recognition_model) +{ + if (!recognition_model) + { + LOGE("Can't learn recognition model. Model handle has to be not NULL"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + FaceRecognitionModel *pRecModel = + static_cast(recognition_model); + + if (!pRecModel) + { + LOGE("Learning of the face recognition model failed. " + "Incorrect Media Vision Face recognition model handle is used"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + RecognitionParams recognitionParams; + extractRecognitionParams(engine_cfg, recognitionParams); + FaceRecognitionModelConfig learnConfig; + learnConfig.mModelType = recognitionParams.mRecognitionAlgType; + + const int ret = pRecModel->learn(learnConfig); + + if (MEDIA_VISION_ERROR_NONE != ret) + { + LOGE("Error occurred when learn face recognition model"); + return ret; + } + + LOGD("Face recognition model has been learned"); + return ret; +} + +int mv_face_recognition_model_query_labels_open( + mv_face_recognition_model_h recognition_model, + int **labels, + unsigned int *number_of_labels) +{ + if (!recognition_model) + { + LOGE("Can't get list of labels for NULL recognition model"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (NULL == labels || NULL == number_of_labels) + { + LOGE("Can't get list of labels. labels and number_of_labels out " + "parameters both has to be not NULL."); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + FaceRecognitionModel *pRecModel = + static_cast(recognition_model); + + if (!pRecModel) + { + LOGE("Learning of the face recognition model failed. " + "Incorrect Media Vision Face recognition model handle is used"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + const std::set& learnedLabels = pRecModel->getFaceLabels(); + *number_of_labels = learnedLabels.size(); + (*labels) = new int[*number_of_labels]; + + std::set::const_iterator it = learnedLabels.begin(); + int i = 0; + for (; it != learnedLabels.end(); ++it) + { + (*labels)[i] = *it; + ++i; + } + + LOGD("List of the labels learned by the recognition model has been retrieved"); + return MEDIA_VISION_ERROR_NONE; +} + +int mv_face_tracking_model_create_open( + mv_face_tracking_model_h *tracking_model) +{ + if (tracking_model == NULL) + { + LOGE("Tracking model can't be created because handle pointer is NULL"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + (*tracking_model) = + static_cast(new (std::nothrow)FaceTrackingModel()); + + if (*tracking_model == NULL) + { + LOGE("Failed to create media vision tracking model"); + return MEDIA_VISION_ERROR_OUT_OF_MEMORY; + } + + LOGD("Tracking model [%p] has been created", *tracking_model); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_face_tracking_model_destroy_open( + mv_face_tracking_model_h tracking_model) +{ + if (!tracking_model) + { + LOGE("Tracking model can't be destroyed because handle is NULL"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + LOGD("Destroying media vision tracking model [%p]", tracking_model); + delete static_cast(tracking_model); + LOGD("Media vision tracking model has been destroyed"); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_face_tracking_model_prepare_open( + mv_face_tracking_model_h tracking_model, + mv_engine_config_h /*engine_cfg*/, + mv_source_h source, + mv_quadrangle_s *location) +{ + if (!tracking_model) + { + LOGE("Can't prepare tracking model. Handle has to be not NULL"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (!source) + { + LOGE("Can't prepare tracking model. " + "Media Vision source handle has to be not NULL"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + FaceTrackingModel *pTrackModel = + static_cast(tracking_model); + + if (!pTrackModel) + { + LOGE("Preparation of the face tracking model failed. " + "Incorrect Media Vision Face tracking model handle is used"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + cv::Mat image; + int ret = convertSourceMV2GrayCV(source, image); + if (MEDIA_VISION_ERROR_NONE != ret) + { + LOGE("Convertion mv_source_h to gray failed"); + return ret; + } + + cv::Rect_ roi; + if (!location) + { + ret = pTrackModel->prepare(image); + } + else + { + int minX = image.cols; + int minY = image.rows; + int maxX = 0.0; + int maxY = 0.0; + for (unsigned i = 0; i < 4; ++i) + { + minX = minX > location->points[i].x ? location->points[i].x : minX; + minY = minY > location->points[i].y ? location->points[i].y : minY; + maxX = maxX < location->points[i].x ? location->points[i].x : maxX; + maxY = maxY < location->points[i].y ? location->points[i].y : maxY; + } + + roi.x = minX; + roi.y = minY; + roi.width = maxX - minX; + roi.height = maxY - minY; + ret = pTrackModel->prepare(image, roi); + } + + if (MEDIA_VISION_ERROR_NONE != ret) + { + LOGE("Error occurred when prepare face tracking model"); + return ret; + } + + LOGD("Face tracking model has been prepared"); + + return ret; +} + +int mv_face_tracking_model_clone_open( + mv_face_tracking_model_h src, + mv_face_tracking_model_h *dst) +{ + if (!src || !dst) + { + LOGE("Can't clone tracking model. Both source and destination" + "tracking model handles has to be not NULL"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + (*dst) = static_cast(new (std::nothrow)FaceTrackingModel()); + + if (*dst == NULL) + { + LOGE("Failed to create media vision tracking model"); + return MEDIA_VISION_ERROR_OUT_OF_MEMORY; + } + + LOGD("Tracking model [%p] has been created", *dst); + + const FaceTrackingModel *pSrcModel = static_cast(src); + FaceTrackingModel *pDstModel = static_cast(*dst); + + *pDstModel = *pSrcModel; + + LOGD("Media vision tracking model has been cloned"); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_face_tracking_model_save_open( + const char *file_name, + mv_face_tracking_model_h tracking_model) +{ + if (!tracking_model) + { + LOGE("Can't save tracking model to the file. " + "Handle has to be not NULL"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (NULL == file_name) + { + LOGE("Can't save tracking model to the file. " + "File name has to be specified"); + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + FaceTrackingModel *pTrackModel = static_cast(tracking_model); + + if (!pTrackModel) + { + LOGE("Saving of the face tracking model to file failed. " + "Incorrect Media Vision Face tracking model handle is used"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + const int ret = pTrackModel->save(std::string(file_name)); + + if (MEDIA_VISION_ERROR_NONE != ret) + { + LOGE("Error occurred when save tracking model to the file"); + return ret; + } + + LOGD("Media vision tracking model has been saved to the file [%s]", file_name); + + return ret; +} + +int mv_face_tracking_model_load_open( + const char *file_name, + mv_face_tracking_model_h *tracking_model) +{ + if (!tracking_model) + { + LOGE("Can't load tracking model from the file. " + "Handle has to be not NULL"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (NULL == file_name) + { + LOGE("Can't load tracking model from the file. " + "File name has to be specified"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + (*tracking_model) = + static_cast(new (std::nothrow)FaceTrackingModel()); + + if (*tracking_model == NULL) + { + LOGE("Failed to create media vision tracking model"); + return MEDIA_VISION_ERROR_OUT_OF_MEMORY; + } + + FaceTrackingModel *pTrackModel = + static_cast(*tracking_model); + + if (!pTrackModel) + { + LOGE("Loading of the face tracking model from file failed. " + "Incorrect Media Vision Face tracking model handle is used"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + const int ret = pTrackModel->load(std::string(file_name)); + + if (MEDIA_VISION_ERROR_NONE != ret) + { + LOGE("Error occurred when save recognition model to the file"); + return ret; + } + + LOGD("Media vision recognition model has been loaded from the file [%s]", file_name); + + return ret; +} diff --git a/mv_face/face_lic/CMakeLists.txt b/mv_face/face_lic/CMakeLists.txt new file mode 100644 index 0000000..905f56f --- /dev/null +++ b/mv_face/face_lic/CMakeLists.txt @@ -0,0 +1,25 @@ +project(${MV_FACE_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_FACE_INC_LIST "${PROJECT_SOURCE_DIR}/include/*.h") +file(GLOB MV_FACE_SRC_LIST "${PROJECT_SOURCE_DIR}/src/*.c") + +if(FORCED_STATIC_BUILD) + add_library(${PROJECT_NAME} STATIC ${MV_FACE_INC_LIST} ${MV_FACE_SRC_LIST}) +else() + add_library(${PROJECT_NAME} SHARED ${MV_FACE_INC_LIST} ${MV_FACE_SRC_LIST}) +endif() + +target_link_libraries(${PROJECT_NAME} ${MV_COMMON_LIB_NAME}) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}) diff --git a/mv_face/face_lic/include/mv_face_lic.h b/mv_face/face_lic/include/mv_face_lic.h new file mode 100644 index 0000000..dec74b4 --- /dev/null +++ b/mv_face/face_lic/include/mv_face_lic.h @@ -0,0 +1,778 @@ +/** + * 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_FACE_LIC_H__ +#define __TIZEN_MEDIAVISION_FACE_LIC_H__ + +#include "mv_face.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file mv_face_lic.h + * @brief This file contains the Media Vision Face licensed API + */ + +/******************/ +/* Face detection */ +/******************/ + +/** + * @brief Performs face detection on the @a source for the @a engine_conf. + * @details Use this function to launch face detection algorithm configured by + * @a engine_conf configuration. Each time when mv_face_detect_lic is + * called, @a detected_cb will receive a set of the detected + * faces at the media source. + * + * @since_tizen 3.0 + * @param [in] source The handle to the source of the media where faces + * will be detected + * @param [in] engine_cfg The handle to the configuration of engine will be + * used for detecting. If NULL, then default settings + * will be used. + * @param [in] detected_cb The callback which will be called for all face + * locations detected on media source. This callback + * will receive detecting results + * @param [in] user_data The user data passed from the code where + * @ref mv_face_detect_lic() is invoked. This data will be + * accessible from @a detected_cb callback. + * @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 Create a source handle by calling @ref mv_create_source() + * @post @a detected_cb will be called to process detection results + * + * @see mv_face_detected_cb + */ +int mv_face_detect_lic( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_face_detected_cb detected_cb, + void *user_data); + + +/********************/ +/* Face recognition */ +/********************/ + +/** + * @brief Performs face recognition on the @a source image. + * @details Use this function to launch face recognition algorithm configured by + * @a engine_conf configuration using @a recognition_model recognition + * model. Each time when @ref mv_face_recognize_lic() is called, + * @a recognized_cb will receive recognition results:\n + * - Location in the @a source of the face has been recognized; + * - Label of the face has been recognized; + * - Confidence of the @a recognition_model that face has been + * recognized correctly (value from 0.0 to 1.0). + * + * @since_tizen 3.0 + * @remarks Using of untrained or weakly trained recognition models will cause + * not accurate results even if resulting confidence will be high. + * Use @ref mv_face_recognition_model_learn_lic() function before + * @ref mv_face_recognize_lic() call. Best results can be achieved + * when big set of face image examples were added by + * @ref mv_face_recognition_model_add_lic() before + * @ref mv_face_recognition_model_learn_lic() call. + * @param [in] source The handle to the source of the media to + * recognize face(s) for + * @param [in] recognition_model The handle to the model will be used for + * recognition + * @param [in] engine_cfg The handle to the configuration of engine + * will be used for recognition. If NULL, then + * default settings will be used + * @param [in] face_location Rectangular box bounding face image on the + * @a source. If NULL, then full source will be + * analyzed + * @param [in] recognized_cb The callback which will be called for the + * face recognition results on the @a source. + * @param [in] user_data The user data passed from the code where + * @ref mv_face_recognize_lic() is invoked. + * This data will be accessible from + * @a recognized_cb callback. + * @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 Create a source handle by calling @ref mv_create_source() + * @pre Create a face recognition model handle by calling + * @ref mv_face_recognition_model_create_lic() + * @post @a recognized_cb will be called to process recognition results + * + * @see mv_face_recognized_cb + */ +int mv_face_recognize_lic( + mv_source_h source, + mv_face_recognition_model_h recognition_model, + mv_engine_config_h engine_cfg, + mv_rectangle_s *face_location, + mv_face_recognized_cb recognized_cb, + void *user_data); + + +/*****************/ +/* Face tracking */ +/*****************/ + +/** + * @brief Performs face tracking on the @a source for the @a tracking_model. + * @details Use this function to launch face tracking algorithm configured by + * @a engine_conf configuration using @a tracking_model tracking + * model. Each time when this function is called, @a tracked_cb + * will receive updated @a tracking_model, new location determined for + * the tracked face and model confidence that location is determined + * correctly. + * + * @since_tizen 3.0 + * @remarks To allow correct tracking @a tracking_model has to be already used + * in previous tracking process(es) or prepared with + * @ref mv_face_tracking_model_prepare_lic(). Preparation requires + * specifying the face location for the @a source on which tracking was + * started. I.e. @ref mv_face_tracking_model_prepare_lic() function + * has to be called at least once before this method call. + * @param [in] source The handle to the source of the media to + * recognize face for + * @param [in] tracking_model The handle to the model will be used for + * tracking + * @param [in] engine_cfg The handle to the configuration of engine will + * be used for tracking. If NULL, the default + * configuration will be used. + * @param [in] tracked_cb The callback which will be called for tracking + * event on the @a source where face would be + * tracked. This callback will receive tracking + * results + * @param [in] do_learn The model learning flag. If it is set @c true + * then model will try to learn (if it supports + * learning feature), otherwise model will be not + * learned during the invoking tracking iteration. + * Learning process improves tracking correctness, + * but can decrease tracking performance + * @param [in] user_data The user data passed from the code where + * @ref mv_face_track_lic() is invoked. This data + * will be accessible from @a tracked_cb callback + * @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 Create a source handle by calling @ref mv_create_source() + * @pre Create a face tracking model handle by calling + * @ref mv_face_tracking_model_create_lic() + * @post @a tracked_cb will be called to process tracking results + * + * @see mv_face_tracked_cb + */ +int mv_face_track_lic( + mv_source_h source, + mv_face_tracking_model_h tracking_model, + mv_engine_config_h engine_cfg, + mv_face_tracked_cb tracked_cb, + bool do_learn, + void *user_data); + + +/********************************/ +/* Recognition of eye condition */ +/********************************/ + +/** + * @brief Determines eye-blink condition for @a face_location on media @a source. + * @details Use this function to recognize eye-blink condition for the face + * bounded by @a face_location at @a source. + * + * @since_tizen 3.0 + * @param [in] source The handle to the source of the media to + * recognize eye-blink condition for + * @param [in] engine_cfg The handle to the configuration of engine + * will be used for eye-blink condition + * recognition. If NULL, the default configuration + * will be used. + * @param [in] face_location The location bounding the face at the @a source + * @param [in] eye_condition_recognized_cb The callback for processing result + * of eye-blink condition recognition + * @param [in] user_data The user data passed from the code where + * @ref mv_face_eye_condition_recognize_lic() is + * invoked. This data will be accessible from + * @a eye_condition_recognized_cb callback + * @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 Create a source handle by calling @ref mv_create_source() + * + * @see mv_face_eye_condition_recognized_cb + */ +int mv_face_eye_condition_recognize_lic( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s face_location, + mv_face_eye_condition_recognized_cb eye_condition_recognized_cb, + void *user_data); + + +/************************************/ +/* Recognition of facial expression */ +/************************************/ + +/** + * @brief Determines facial expression for @a face_location on media @a source. + * @details Use this function to determine facial expression for the face + * bounded by @a face_location at @a source. + * + * @since_tizen 3.0 + * @param [in] source The handle to the source of the media + * to recognize facial expression for + * @param [in] engine_cfg The handle to the configuration of + * engine will be used for expression recognition + * @param [in] face_location The location bounding the face at the @a source + * @param [in] expression_recognized_cb The callback for processing result + * of facial expression determining + * @param [in] user_data The user data passed from the code where + * @ref mv_face_facial_expression_recognize_lic() is + * invoked. This data will be accessible from + * @a expression_recognized_cb callback. + * @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 Create a source handle by calling @ref mv_create_source() + * @pre Create a face engine configuration handle by calling @ref mv_create_engine_config() + * + * @see mv_face_facial_expression_recognized_cb + */ +int mv_face_facial_expression_recognize_lic( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s face_location, + mv_face_facial_expression_recognized_cb expression_recognized_cb, + void *user_data); + +/*******************************/ +/* Recognition model behavior */ +/*******************************/ + +/** + * @brief Creates a face recognition model handle. + * @details Use this function to create default face recognition model. Creating + * process is defined by concrete face engine library. After creation + * recognition model has to be learned with + * @ref mv_face_recognition_model_learn_lic() function to provide + * appropriate results of face recognition functionality. Or learned + * earlier model can be loaded by + * @ref mv_face_recognition_model_load_lic() function. + * + * @since_tizen 3.0 + * @remarks It can cause incompatibility issues when saved models (see + * @ref mv_face_recognition_model_save_lic(), + * @ref mv_face_recognition_model_load_lic() functions documentation) + * are used in applications for different platforms which use different + * computer vision libraries underlying this API. + * @remarks You must release @a recognition_model by using + * @ref mv_face_recognition_model_destroy_lic() function. + * @param [out] recognition_model The handle to the recognition model to be + * created + * + * @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 + * + * @post Model can be loaded from the file after creation. Use + * @ref mv_face_recognition_model_load_lic() function to load it from file + * @post Release @a recognition_model by using + * @ref mv_face_recognition_model_destroy_lic() function when it is not needed + * anymore + * + * @see mv_face_recognition_model_destroy_lic() + */ +int mv_face_recognition_model_create_lic( + mv_face_recognition_model_h *recognition_model); + +/** + * @brief Destroys the face recognition model handle and releases all its + * resources. + * + * @since_tizen 3.0 + * @param [in] recognition_model The handle to the face recognition model 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 + * + * @pre Create recognition model by using @ref mv_face_recognition_model_create_lic() + * + * @see mv_face_recognition_model_create_lic() + */ +int mv_face_recognition_model_destroy_lic( + mv_face_recognition_model_h recognition_model); + +/** + * @brief Creates a copy of existed recognition model handle and clones all its + * resources. + * + * @since_tizen 3.0 + * @remarks Cloning perform not only handle copy, but also copies all internal + * resources of the model. @a dst must be released using + * @a mv_face_recognition_model_destroy_open_lic(). + * @param [in] src The handle to the recognition model to be copied + * @param [out] dst The handle to the copy of existed recognition model + * specified as @a src + * @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 Create face recognition handles by calling + * @ref mv_face_recognition_model_create_lic() + * + * @see mv_face_recognition_model_create_lic() + */ +int mv_face_recognition_model_clone_lic( + mv_face_recognition_model_h src, + mv_face_recognition_model_h *dst); + +/** + * @brief Saves recognition model to the file. + * + * @since_tizen 3.0 + * @remarks This function doesn't save added by + * @ref mv_face_recognition_model_add_lic() function face + * image examples. This examples can be removed by + * @ref mv_face_recognition_model_reset_lic() function + * if it is needed to clear the memory. + * @remarks After model is saved to the file, it can be loaded from this file + * by @ref mv_face_recognition_model_load_lic() function. + * @param [in] file_name Name of the file to save the model + * @param [in] recognition_model The handle to the recognition model to be + * saved to the file + * @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 Create a face recognition handle by calling + * @ref mv_face_recognition_model_create_lic() function + * @post Saved model can be loaded later by calling + * @ref mv_face_recognition_model_load_lic() function + * + * @see mv_face_recognition_model_load_lic() + * @see mv_face_recognition_model_create_lic() + */ +int mv_face_recognition_model_save_lic( + const char *file_name, + mv_face_recognition_model_h recognition_model); + +/** + * @brief Loads recognition model from file. + * + * @since_tizen 3.0 + * @remarks This function doesn't modify the set of face image examples added + * with @ref mv_face_recognition_model_add_lic() function. + * Model will be loaded from file without loss of collected examples. + * If you want to free memory from examples, use + * @ref mv_face_recognition_model_reset_lic() function. + * It is recommended to clear the memory if learning algorithm doesn't + * support reinforcement learning. + * @remarks @a recognition_model is loaded from the application's data directory. + * @a recognition_model must be destroyed using + * @ref mv_face_recognition_model_destroy_open_lic(). + * @param [in] file_name Name of file to load the model + * @param [out] recognition_model The handle to the recognition model + * to be loaded from the file + * @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 Create a face recognition handle by calling + * @ref mv_face_recognition_model_create_lic() function + * + * @see mv_face_recognition_model_save_lic() + * @see mv_face_recognition_model_create_lic() + */ +int mv_face_recognition_model_load_lic( + const char *file_name, + mv_face_recognition_model_h *recognition_model); + +/** + * @brief Adds face image example to be used for face recognition model learning + * with @ref mv_face_recognition_model_learn_lic(). + * + * @since_tizen 3.0 + * @remarks It is possible to destroy @a source after calling this method. + * Source isn't used for learning directly. + * @remarks Face image @a example_location location can be determined using + * @ref mv_face_detect_lic function. + * @param [in] source The handle to @a source that contains face + * image + * @param [in] recognition_model The handle to the recognition model which + * could be learned based on example + * @param [in] example_location The pointer to the rectangular location of + * the face image at the source image. If NULL, + * then full image will be analyzed as the face + * image + * @param [in] face_label The label that identifies face for which + * example is adding. Specify the same labels + * for the face images of a single person when + * calling this method. Has to be unique for + * each face + * @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 Create a face recognition handle by calling + * @ref mv_face_recognition_model_create_lic() function + * @post When appropriate amount of face image examples is added to the + * @a recognition_model, this model has to be learned by + * @ref mv_face_recognition_model_learn_lic() function call. Only after + * learning of the model it can be used for face recognition with + * @a mv_face_recognize_lic() function + * + * @see mv_face_recognition_model_reset_lic() + * @see mv_face_recognition_model_learn_lic() + */ +int mv_face_recognition_model_add_lic( + const mv_source_h source, + mv_face_recognition_model_h recognition_model, + const mv_rectangle_s *example_location, + int face_label); + +/** + * @brief Remove from @a recognition_model all collected with + * @ref mv_face_recognition_model_add_lic() function + * face examples labeled with @a face_label. + * + * @since_tizen 3.0 + * @remarks Be aware that if this function is called before + * @ref mv_face_recognition_model_learn_lic() function call, all or + * part of the required for learning data will be lost. It means that + * face image examples determined by the @a face_label label will be + * removed from the model and not taken taken into account when + * @ref mv_face_recognition_model_learn_lic() will be called next + * time. + * @remarks Call of this function will free all the memory has been allocated + * during previous + * @ref mv_face_recognition_model_add_lic() calls for + * the corresponding @a face_label label. + * @param [in] recognition_model The handle to the recognition model for + * which face image examples will be reset. + * @param [in] face_label The label that identifies face for which + * examples will be removed from the + * @a recognition_model. If NULL, then all + * known by @a recognition_model face image + * examples will be removed + * @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_face_recognition_model_add_lic() + * @see mv_face_recognition_model_learn_lic() + */ +int mv_face_recognition_model_reset_lic( + mv_face_recognition_model_h recognition_model, + const int *face_label); + +/** + * @brief Learns face recognition model. + * @details Before you start learning process, face recognition models has to be + * filled with training data - face image examples. These examples has + * to be provided by + * mv_face_recognition_model_add_lic() function. Usually, + * recognition accuracy is increased when number of not identical + * examples is large. But it depends of the used learning algorithm. + * + * @since_tizen 3.0 + * @remarks Common flow is to collect face examples as much as possible, add + * them to the recognition model with + * @ref mv_face_recognition_model_add_lic(), then call + * @ref mv_face_recognition_model_learn_lic() for this recognition + * model to learn it (or reinforce the model if reinforcement learning + * is supported by the used algorithm). + * @remarks Selection of the learning algorithm can be performed by setting + * corresponding attributes for the @a engine_cfg. You can check + * supported by @a engine_cfg attributes using + * @ref mv_engine_config_foreach_supported_attribute() function call. + * @param [in] engine_cfg The handle to the configuration of + * engine will be used for learning of the + * recognition models. If NULL, then + * default settings will be used + * @param [in,out] recognition_model The model which will be learned. After + * learning process these model may be + * changed, so + * @ref mv_face_recognize_lic() results + * may differ before and after method call + * respectively to the face examples + * collected for the @a recognition_model + * @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 Create a face engine configuration handle by calling + * @ref mv_create_engine_config() and set supported parameters if + * needed. Or just set @a engine_cfg as NULL to learn with default settings + * @pre Create a face recognition model handles by calling + * @ref mv_face_recognition_model_create_lic() function + * @pre Add face image examples to the @a recognition_model by calling + * @ref mv_face_recognition_model_add_lic() function + * @post If it is not planned to learn the model again, clear memory by + * @ref mv_face_recognition_model_reset_lic() function + * @post When model has been learned, it can be used for face recognition with + * @ref mv_face_recognize_lic() function + * + * @see mv_face_recognition_model_add_lic() + * @see mv_face_recognition_model_reset_lic() + * @see mv_face_recognize_lic() + */ +int mv_face_recognition_model_learn_lic( + mv_engine_config_h engine_cfg, + mv_face_recognition_model_h recognition_model); + +/** + * @brief Queries labels list and number of labels had been learned by the model. + * + * @since_tizen 3.0 + * @remarks @a labels array has to be released using free(). + * @param [in] recognition_model The handle to the recognition model for + * which set of the learned labels will be + * queried + * @param [out] labels The array which will be filled with labels + * had been learned by the model + * @param [out] number_of_labels The number of labels in @a labels array + * @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 Add face image examples with labels to the @a recognition_model by + * calling the @ref mv_face_recognition_model_add_lic() + * function + * @pre Learn the @a recognition_model by labeled examples using + * @ref mv_face_recognition_model_learn_lic() function + * @post @a labels array has to be freed in the function invoking code + * + * @see mv_face_recognition_model_add_lic() + * @see mv_face_recognition_model_reset_lic() + * @see mv_face_recognition_model_learn_lic() + */ +int mv_face_recognition_model_query_labels_lic( + mv_face_recognition_model_h recognition_model, + int **labels, + unsigned int *number_of_labels); + +/***************************/ +/* Tracking model behavior */ +/***************************/ + +/** + * @brief Calls this function to create a face tracking model handle. + * @details Use this function to create default face tracking model handle. + * After creation this handle has to be initialized with + * @ref mv_face_tracking_model_prepare_lic() function to provide + * appropriate results of face tracking functionality. When handle is + * prepared, it is possible to use it for tracking on continuous + * sequence of the sources. Call + * @ref mv_face_tracking_model_prepare_lic() function each time before + * starting tracking on the new sequence. The exception is situation + * when the new sequence is continuation of the previous sequence for + * which model has been tracked. + * + * @since_tizen 3.0 + * @param [out] tracking_model The pointer to the handle to the tracking + * model that will be created + * @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 Model can be loaded from the file after creation. Use + * @ref mv_face_tracking_model_load_lic() function to load it from file + * @post Use @ref mv_face_tracking_model_prepare_lic() function before tracking + * on the new video or continuous images sequence + * @post You must release @a tracking_model by using + * mv_face_tracking_model_destroy_lic() function when it is not needed + * anymore + * + * @see mv_face_tracking_model_destroy_lic() + * @see mv_face_tracking_model_prepare_lic() + * @see mv_face_tracking_model_load_lic() + */ +int mv_face_tracking_model_create_lic( + mv_face_tracking_model_h *tracking_model); + +/** + * @brief Calls this function to destroy the face tracking model handle and + * release all its resources. + * + * @since_tizen 3.0 + * @param [in] tracking_model The handle to the face tracking model that + * will 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 + * + * @pre Create tracking model by using @ref mv_face_tracking_model_create_lic() + * + * @see mv_face_tracking_model_create_lic() + */ +int mv_face_tracking_model_destroy_lic( + mv_face_tracking_model_h tracking_model); + +/** + * @brief Calls this function to initialize tracking model by the location of the + * face to be tracked. + * @details This function is usually called once after tracking model is created + * and each time before tracking is started for the new sequence of + * sources which is not the direct continuation of the sequence for + * which tracking has been performed before. But it is allowed to call + * it between tracking sessions to allow Media Vision start to track + * more accurately. + * + * @since_tizen 3.0 + * @param [in] tracking_model The handle to the tracking model that will be + * prepared for tracking on new video or image + * sequence + * @param [in] engine_cfg The handle to the configuration of engine + * will be used for model preparing. If NULL, then + * default settings will be used. + * @param [in] source The handle to the source where face @a location + * is specified. Usually it is the first frame of + * the video or the first image in the continuous + * image sequence planned to be used for tracking + * @param [in] location The quadrangle-shaped location (actually, + * rectangle can be used) determining position + * of the face to be tracked on the @a source. If + * @c NULL, then tracking model will try to find + * previously tracked face by itself. Don't set + * NULL when called first time for the tracking + * model. + * @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 Create a face tracking model handle by calling + * @ref mv_face_tracking_model_create_lic() function + * @pre Create a source handle by calling @ref mv_create_source() function + * @post When model is prepared, @ref mv_face_track_lic() function can be used + * to track on the video or continuous image sequence + * + * @see mv_face_tracking_model_create_lic() + * @see mv_face_track_lic() + */ +int mv_face_tracking_model_prepare_lic( + mv_face_tracking_model_h tracking_model, + mv_engine_config_h engine_cfg, + mv_source_h source, + mv_quadrangle_s *location); + +/** + * @brief Calls this function to make a copy of existed tracking model handle and + * clone all its resources to the copy. + * + * @since_tizen 3.0 + * @remarks Cloning performs not only handle copy, but also copies all internal + * resources of the model. + * @param [in] src The handle to the tracking model to be copied + * @param [out] dst The handle to the copy of existed tracking model + * specified as @a src + * @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 Create face tracking @a src and @a dst handles by calling + * @ref mv_face_tracking_model_create_lic() + * + * @see mv_face_tracking_model_create_lic() + */ +int mv_face_tracking_model_clone_lic( + mv_face_tracking_model_h src, + mv_face_tracking_model_h *dst); + +/** + * @brief Calls this method to save tracking model to the file. + * + * @since_tizen 3.0 + * @remarks @ tracking_model is saved to the application's data directory. + * After model is saved to the file, it can be loaded from this file + * with @ref mv_face_tracking_model_load_lic() function. + * @param [in] file_name Name of the file to save the model + * @param [in] tracking_model The handle to the tracking model to be + * saved to the file + * @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 Create a face tracking handle by calling + * @ref mv_face_tracking_model_create_lic() + * @post Saved model can be loaded from file using + * @ref mv_face_tracking_model_load_lic() function + * + * @see mv_face_tracking_model_load_lic() + * @see mv_face_tracking_model_create_lic() + */ +int mv_face_tracking_model_save_lic( + const char *file_name, + mv_face_tracking_model_h tracking_model); + +/** + * @brief Calls this method to load a tracking model from file. + * + * @since_tizen 3.0 + * @remarks @a tracking_model is loaded from the application's data directory. + * @a tracking_model must be destroyed using + * @ref mv_face_tracking_model_destroy_lic(). + * @param [in] file_name Name of file to load the model + * @param [out] tracking_model The handle to the tracking model to be + * loaded from file + * @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 Models has been saved by @ref mv_face_tracking_model_save_lic() + * function can be loaded with this function + * @post After model has been loaded and if further tracking will be performed + * on the video which is not continuation of the last tracking performed + * for the model, it is recommended to call + * @ref mv_face_tracking_model_prepare_lic() function + * + * @see mv_face_tracking_model_save_lic() + * @see mv_face_tracking_model_create_lic() + */ +int mv_face_tracking_model_load_lic( + const char *file_name, + mv_face_tracking_model_h *tracking_model); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIAVISION_FACE_LIC_H__ */ diff --git a/mv_face/face_lic/src/mv_face_lic.c b/mv_face/face_lic/src/mv_face_lic.c new file mode 100644 index 0000000..00a516e --- /dev/null +++ b/mv_face/face_lic/src/mv_face_lic.c @@ -0,0 +1,208 @@ +/** + * 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_face_lic.h" + +/******************/ +/* Face detection */ +/******************/ + +int mv_face_detect_lic( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_face_detected_cb detected_cb, + void *user_data) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + + +/********************/ +/* Face recognition */ +/********************/ + +int mv_face_recognize_lic( + mv_source_h source, + mv_face_recognition_model_h recognition_model, + mv_engine_config_h engine_cfg, + mv_rectangle_s *face_location, + mv_face_recognized_cb recognized_cb, + void *user_data) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + + +/*****************/ +/* Face tracking */ +/*****************/ + +int mv_face_track_lic( + mv_source_h source, + mv_face_tracking_model_h tracking_model, + mv_engine_config_h engine_cfg, + mv_face_tracked_cb tracked_cb, + bool do_learn, + void *user_data) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + + +/********************************/ +/* Recognition of eye condition */ +/********************************/ + +int mv_face_eye_condition_recognize_lic( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s face_location, + mv_face_eye_condition_recognized_cb eye_condition_recognized_cb, + void *user_data) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + + +/************************************/ +/* Recognition of facial expression */ +/************************************/ + +int mv_face_facial_expression_recognize_lic( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s face_location, + mv_face_facial_expression_recognized_cb expression_recognized_cb, + void *user_data) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + + +/******************************/ +/* Recognition model behavior */ +/******************************/ + +int mv_face_recognition_model_create_lic( + mv_face_recognition_model_h *recognition_model) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_face_recognition_model_destroy_lic( + mv_face_recognition_model_h recognition_model) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_face_recognition_model_clone_lic( + mv_face_recognition_model_h src, + mv_face_recognition_model_h *dst) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_face_recognition_model_save_lic( + const char *file_name, + mv_face_recognition_model_h recognition_model) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_face_recognition_model_load_lic( + const char *file_name, + mv_face_recognition_model_h recognition_model_h) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_face_recognition_model_add_lic( + const mv_source_h source, + mv_face_recognition_model_h recognition_model, + const mv_rectangle_s *example_location, + int face_label) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_face_recognition_model_reset_lic( + mv_face_recognition_model_h recognition_model, + const int *face_label) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_face_recognition_model_learn_lic( + mv_engine_config_h engine_cfg, + mv_face_recognition_model_h recognition_model) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_face_recognition_model_query_labels_lic( + mv_face_recognition_model_h recognition_model, + int **labels, + unsigned int *number_of_labels) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + + +/***************************/ +/* Tracking model behavior */ +/***************************/ + +int mv_face_tracking_model_create_lic( + mv_face_tracking_model_h *tracking_model) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_face_tracking_model_destroy_lic( + mv_face_tracking_model_h tracking_model) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_face_tracking_model_prepare_lic( + mv_face_tracking_model_h tracking_model, + mv_engine_config_h engine_cfg, + mv_source_h source, + mv_quadrangle_s *location) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_face_tracking_model_clone_lic( + mv_face_tracking_model_h src, + mv_face_tracking_model_h *dst) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_face_tracking_model_save_lic( + const char *file_name, + mv_face_tracking_model_h tracking_model) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_face_tracking_model_load_lic( + const char *file_name, + mv_face_tracking_model_h tracking_model) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} diff --git a/mv_image/CMakeLists.txt b/mv_image/CMakeLists.txt new file mode 100644 index 0000000..36d2037 --- /dev/null +++ b/mv_image/CMakeLists.txt @@ -0,0 +1,8 @@ +project(mv_image_port) +cmake_minimum_required(VERSION 2.6) + +if(MEDIA_VISION_IMAGE_PORT) + add_subdirectory(${PROJECT_SOURCE_DIR}/image_lic) # Licensed port +else() + add_subdirectory(${PROJECT_SOURCE_DIR}/image) # Open port +endif() diff --git a/mv_image/image/CMakeLists.txt b/mv_image/image/CMakeLists.txt new file mode 100644 index 0000000..0269712 --- /dev/null +++ b/mv_image/image/CMakeLists.txt @@ -0,0 +1,33 @@ +project(${MV_IMAGE_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_IMAGE_INC_LIST "${PROJECT_SOURCE_DIR}/include/*.h") +file(GLOB MV_IMAGE_SRC_LIST "${PROJECT_SOURCE_DIR}/src/*.cpp") + +find_package(OpenCV REQUIRED core highgui imgproc objdetect features2d calib3d) +if(NOT OpenCV_FOUND) + message(SEND_ERROR "Failed to find OpenCV") + return() +else() + include_directories(${OpenCV_INCLUDE_DIRS}) +endif() + +if(FORCED_STATIC_BUILD) + add_library(${PROJECT_NAME} STATIC ${MV_IMAGE_INC_LIST} ${MV_IMAGE_SRC_LIST}) +else() + add_library(${PROJECT_NAME} SHARED ${MV_IMAGE_INC_LIST} ${MV_IMAGE_SRC_LIST}) +endif() + +target_link_libraries(${PROJECT_NAME} ${MV_COMMON_LIB_NAME} ${OpenCV_LIBS}) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}) diff --git a/mv_image/image/include/ImageConfig.h b/mv_image/image/include/ImageConfig.h new file mode 100644 index 0000000..2d43430 --- /dev/null +++ b/mv_image/image/include/ImageConfig.h @@ -0,0 +1,139 @@ +/** + * 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 __IMAGEUTIL_H__ +#define __IMAGEUTIL_H__ + +#include + +/** + * @file ImageUtil.h + * @brief This file contains Image Module utility. + */ + +namespace MediaVision +{ +namespace Image +{ + +/** + * @brief Contains parameters for features extracting from image objects. + * + * @since_tizen 3.0 + */ +struct FeaturesExtractingParams +{ + FeaturesExtractingParams( + double scaleFactor, + int maximumFeaturesNumber); + + FeaturesExtractingParams(); + + double mScaleFactor; /**< Recognition scale factor for the ORB detector. */ + + int mMaximumFeaturesNumber; /**< Maximum number of features, which will be + extracted from object image. */ +}; + +/** + * @brief Contains parameters for image objects recognition. + * + * @since_tizen 3.0 + */ +struct RecognitionParams +{ + RecognitionParams( + int minMatchesNumber, + double requiredMatchesPart, + double allowableMatchesPartError); + + RecognitionParams(); + + int mMinMatchesNumber; /**< The minimum matches number, which + will be taken into account for image objects recognition. */ + + double mRequiredMatchesPart; /**< The part of matches, which will be taken + into account for image objects recognition. Too low value will + result in unsustainable behavior, but effect of object overlapping + will be reduced. Value can be from 0 to 1.*/ + + double mAllowableMatchesPartError; /**< Allowable error of matches number. */ +}; + +/** + * @brief Contains parameters for contour stabilization during tracking of image + * objects. + * + * @since_tizen 3.0 + */ +struct StabilizationParams +{ + StabilizationParams( + int historyAmount, + double allowableShift, + double stabilizationSpeed, + double stabilizationAcceleration); + + StabilizationParams(); + + int mHistoryAmount; /**< Number of previous recognition results, which + will influence the stabilization. */ + + double mAllowableShift; /**< Relative value of maximum shift per one frame, + which will be ignored by stabilization (relative to the object size + in the current frame). */ + + double mStabilizationSpeed; /**< Start speed with which the object will be + stabilized. */ + + double mStabilizationAcceleration; /**< Acceleration with which the object + will be stabilized. (relative to the distance from current location + to stabilized location). Value can be from 0 to 1.*/ +}; + +/** + * @brief Contains parameters for image objects tracking. + * + * @since_tizen 3.0 + */ +struct TrackingParams +{ + TrackingParams( + FeaturesExtractingParams framesFeaturesExtractingParams, + RecognitionParams recognitionParams, + StabilizationParams stabilizationParams, + double expectedOffset); + + TrackingParams(); + + FeaturesExtractingParams mFramesFeaturesExtractingParams; /**< Parameters + for extracting features from frames. */ + + RecognitionParams mRecognitionParams; /**< Parameters for intermediate + recognition. */ + + StabilizationParams mStabilizationParams; /**< Parameters for contour + stabilization during tracking. */ + + double mExpectedOffset; /**< Relative offset value, for which expected the + object offset. (relative to the object size in the current + frame). */ +}; + +} /* Image */ +} /* MediaVision */ + +#endif /* __IMAGEUTIL_H__ */ diff --git a/mv_image/image/include/ImageContourStabilizator.h b/mv_image/image/include/ImageContourStabilizator.h new file mode 100644 index 0000000..1fae797 --- /dev/null +++ b/mv_image/image/include/ImageContourStabilizator.h @@ -0,0 +1,102 @@ +/** + * 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 __IMAGECONTOURSTABILIZATOR_H__ +#define __IMAGECONTOURSTABILIZATOR_H__ + +#include "ImageConfig.h" + +#include + +/** + * @file ImageContourStabilizator.h + * @brief This file contains functionality for image contour stabilization + * during tracking. + */ + +namespace MediaVision +{ +namespace Image +{ + +/** + * @class ImageContourStabilizator + * @brief This class contains functionality for image contour stabilization + * during tracking. + * + * @since_tizen 3.0 + */ +class ImageContourStabilizator +{ +public: + + /** + * @brief @ref ImageContourStabilizator default constructor. + * + * @since_tizen 3.0 + */ + ImageContourStabilizator(); + + /** + * @brief Stabilizes @a contour. + * + * @since_tizen 3.0 + * @remarks Call this function alternately for each contour from sequence + * @param [in,out] contour @ref contour, which will be stabilized + * @param [in] params configuration parameters + * @return true if contour is stabilized, otherwise return false + */ + bool stabilize( + std::vector& contour, + const StabilizationParams& params); + + /** + * @brief Resets stabilization process. + * + * @since_tizen 3.0 + * @remarks Call it before starting track on the new sequence of contours. + */ + void reset(void); + +private: + + std::vector computeStabilizedQuadrangleContour(void); + +private: + + static const size_t MovingHistoryAmount = 3u; + + std::vector m_speeds; + + std::vector m_currentCornersSpeed; + + std::deque > m_movingHistory; + + std::vector m_lastStabilizedContour; + + size_t m_currentHistoryAmount; + + int m_tempContourIndex; + + std::vector m_priorities; + + bool m_isPrepared; +}; + +} /* Image */ +} /* MediaVision */ + +#endif /* __IMAGECONTOURSTABILIZATOR_H__ */ diff --git a/mv_image/image/include/ImageMathUtil.h b/mv_image/image/include/ImageMathUtil.h new file mode 100644 index 0000000..ebc95d7 --- /dev/null +++ b/mv_image/image/include/ImageMathUtil.h @@ -0,0 +1,78 @@ +/** + * 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 __MATHUTIL_H__ +#define __MATHUTIL_H__ + +#include + +/** + * @file MathUtil.h + * @brief This file contains math utility for Image Module. + */ + +namespace MediaVision +{ +namespace Image +{ + +const size_t MinimumNumberOfFeatures = 4u; /* Minimum number of features + when perspective transform + parameters calculation + have sense */ + +const size_t NumberOfQuadrangleCorners = 4u; /* Number of quadrangle corneres */ + +/** + * @brief Calculates Euclidean distance between two points. + * + * @since_tizen 3.0 + * @param [in] point1 The first point + * @param [in] point2 The second point + * @return distance between two points + */ +float getDistance( + const cv::Point2f& point1, + const cv::Point2f& point2); + +/** + * @brief Calculates area of triangle. + * + * @since_tizen 3.0 + * @param [in] point1 The first corner of triangle + * @param [in] point2 The second corner of triangle + * @param [in] point3 The third corner of triangle + * @return area of triangle + */ +float getTriangleArea( + const cv::Point2f& point1, + const cv::Point2f& point2, + const cv::Point2f& point3); + +/** + * @brief Calculates area of quadrangle. + * + * @since_tizen 3.0 + * @param [in] points Four corners of quadrangle + * @return area of quadrangle + */ +float getQuadrangleArea( + const cv::Point2f points[NumberOfQuadrangleCorners]); + +} /* Image */ +} /* MediaVision */ + +#endif /* __MATHUTIL_H__ */ diff --git a/mv_image/image/include/ImageObject.h b/mv_image/image/include/ImageObject.h new file mode 100644 index 0000000..a494554 --- /dev/null +++ b/mv_image/image/include/ImageObject.h @@ -0,0 +1,220 @@ +/** + * 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 __IMAGEOBJECT_H__ +#define __IMAGEOBJECT_H__ + +#include "ImageConfig.h" + +#include + +/** + * @file ImageObject.h + * @brief This file contains the @ref ImageObject class. + */ + +namespace MediaVision +{ +namespace Image +{ + +/** + * @class ImageObject + * @brief This class contains the image information, which will + * be used in recognition algorithms. + * + * @since_tizen 3.0 + */ +class ImageObject +{ + +public: + + /** + * @brief @ref ImageObject default constructor. + * + * @since_tizen 3.0 + */ + ImageObject(); + + /** + * @brief @ref ImageObject constructor based on image. + * + * @since_tizen 3.0 + * @remarks Detects keypoints and extracts features from image and creates + * new @ref ImageObject + * @param [in] image The image for which instance of @ref ImageObject + * will be created + * @param [in] params Features extracting parameters + */ + ImageObject(const cv::Mat& image, const FeaturesExtractingParams& params); + + /** + * @brief @ref ImageObject copy constructor. + * @details Creates copy of @ref ImageObject + * + * @since_tizen 3.0 + * @param [in] copy @ref ImageObject which will be copied + */ + ImageObject(const ImageObject& copy); + + /** + * @brief @ref ImageObject copy assignment operator. + * @details Fills the information based on the @a copy + * + * @since_tizen 3.0 + * @param [in] copy @ref ImageObject which will be copied + * + */ + ImageObject& operator=(const ImageObject& copy); + + /** + * @brief @ref ImageObject destructor. + * + * @since_tizen 3.0 + */ + virtual ~ImageObject(); + + /** + * @brief Fills @ref ImageObject class based on image. + * @details Detects keypoints and extracts features from image and creates + * new @ref ImageObject + * + * @since_tizen 3.0 + * @param [in] image The image for which instance of @ref ImageObject + * will be created + * @param [in] params Features extracting parameters + */ + void fill(const cv::Mat& image, const FeaturesExtractingParams& params); + + /** + * @brief Fills @ref ImageObject class based on image. + * @details Detects keypoints and extracts features from image and creates + * new @ref ImageObject + * + * @since_tizen 3.0 + * @param [in] image The image for which instance of @ref + * ImageObject will be created + * @param [in] boundingBox Bounding box of the object being analyzed in + * the @a image + * @param [in] params Features extracting parameters + * @return @a true on success, otherwise a @a false value + * @retval true Successful + * @retval false Invalid ROI (bounding box) + */ + bool fill( + const cv::Mat& image, + const cv::Rect& boundingBox, + const FeaturesExtractingParams& params); + + /** + * @brief Gets a value that determines how well an @ref ImageObject can be recognized. + * @details Confidence can be from 0 to 1. If the recognition rate is 0 object can + * not be recognized + * + * @since_tizen 3.0 + * @return A value that determines how well an @ref ImageObject can be recognized. + */ + float getRecognitionRate(void) const; + + /** + * @brief Check whether the object is filled. + * @details Image object is empty if it wasn't filled. + * + * @since_tizen 3.0 + * @remarks Empty object can not be recognized or tracked. Fill the object + * by using corresponding constructor or function @ref fill() to + * make image object valid. Also you can load image object which is + * not empty by using @ref load(). + * @return @c false if object is filled, otherwise return @c true + */ + bool isEmpty() const; + + /** + * @brief Sets a label for the image object. + * + * @since_tizen 3.0 + * @param [in] label The label which will be assigned to the image object + */ + void setLabel(int label); + + /** + * @brief Gets a label of object. + * + * @since_tizen 3.0 + * @param [out] label The label of image object + * @return @c true if object is labeled, otherwise return @c false + */ + bool getLabel(int& label) const; + + /** + * @brief Stores the @ref ImageObject in a file. + * + * @since_tizen 3.0 + * @param [in] fileName File name which will be generated + * @return @a 0 on success, otherwise a negative error value + */ + int save(const char *fileName) const; + + /** + * @brief Loads the @ref ImageObject from the file. + * + * @since_tizen 3.0 + * @param [in] fileName File name from which will be loaded an @ref ImageObject + * @return @a 0 on success, otherwise a negative error value + */ + int load(const char *fileName); + +private: + + static const int MinWidth = 5; + static const int MinHeight = 5; + +private: + + void extractFeatures( + const cv::Mat& image, + const FeaturesExtractingParams& params); + + void computeRecognitionRate(const cv::Mat& image); + +private: + + bool m_isEmpty; + + bool m_isLabeled; + + int m_label; + + std::vector m_boundingContour; + + std::vector m_objectKeypoints; + + cv::Mat m_objectDescriptors; + + float m_recognitionRate; + + friend class ImageRecognizer; + + friend std::ostream& operator << (std::ostream& os, const ImageObject& obj); + + friend std::istream& operator >> (std::istream& is, ImageObject& obj); +}; + +} /* Image */ +} /* MediaVision */ + +#endif /* __IMAGEOBJECT_H__ */ diff --git a/mv_image/image/include/ImageRecognizer.h b/mv_image/image/include/ImageRecognizer.h new file mode 100644 index 0000000..8494e3a --- /dev/null +++ b/mv_image/image/include/ImageRecognizer.h @@ -0,0 +1,116 @@ +/** + * 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 __IMAGERECOGNIZER_H__ +#define __IMAGERECOGNIZER_H__ + +#include "ImageMathUtil.h" +#include "ImageConfig.h" +#include "ImageObject.h" + +#include + +/** + * @file ImageRecognizer.h + * @brief This file contains functionality for image object recognition. + */ + +namespace MediaVision +{ +namespace Image +{ + +/** + * @class ImageRecognizer + * @brief This class contains functionality for image object recognition. + * + * @since_tizen 3.0 + */ +class ImageRecognizer +{ +public: + + /** + * @brief @ref ImageRecognizer constructor based on scene image. + * + * @since_tizen 3.0 + * @param [in] sceneImage The scene in which image objects will be recognized + * @param [in] params Scene features extracting parameters + */ + ImageRecognizer(const cv::Mat& sceneImage, + const FeaturesExtractingParams& params); + + /** + * @brief @ref ImageRecognizer constructor based on thes scene @ref ImageObject. + * + * @since_tizen 3.0 + * @param [in] scene The scene for which the objects will be recognized by + * calling method recognize() + */ + ImageRecognizer(const ImageObject& scene); + + /** + * @brief @ref ImageRecognizer destructor. + * + * @since_tizen 3.0 + */ + virtual ~ImageRecognizer(); + + /** + * @brief Recognizes the @a target on the scene. + * + * @since_tizen 3.0 + * @param [in] target @ref ImageObject, which will be recognized + * @param [in] params Recognition parameters + * @param [out] contour The result contour of @a target object on the scene + * @return true if object is found on the scene, otherwise return false + */ + bool recognize( + const ImageObject& target, + const RecognitionParams& params, + std::vector& contour) const; + +private: + + ImageRecognizer(); + + bool findHomophraphyMatrix( + const ImageObject& target, + const RecognitionParams& params, + cv::Mat& homophraphyMatrix) const; + + size_t matchesSelection( + std::vector& examples, + unsigned int filterAmount, unsigned int allowableError) const; + + float computeLinearSupportElement( + const std::vector& examples, + int requiredNumber, int leftLimit, int rightLimit) const; + + static bool isPossibleQuadrangleCorners( + const cv::Point2f corners[NumberOfQuadrangleCorners]); + +private: + + ImageObject m_scene; + + cv::BFMatcher m_matcher; +}; + +} /* Image */ +} /* MediaVision */ + +#endif /* __IMAGERECOGNIZER_H__ */ diff --git a/mv_image/image/include/ImageTracker.h b/mv_image/image/include/ImageTracker.h new file mode 100644 index 0000000..2bfd5b1 --- /dev/null +++ b/mv_image/image/include/ImageTracker.h @@ -0,0 +1,103 @@ +/** + * 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 __IMAGETRACKER_H__ +#define __IMAGETRACKER_H__ + +#include "ImageConfig.h" + +#include + +/** + * @file ImageTracker.h + * @brief This file contains functionality for image object tracking. + */ + +namespace MediaVision +{ +namespace Image +{ + +class ImageRecognizer; +class ImageTrackingModel; + +/** + * @class ImageTracker + * @brief This class contains functionality for image object tracking. + * + * @since_tizen 3.0 + */ +class ImageTracker +{ +private: + + struct RecognitionInfo + { + cv::Mat mFrame; + + RecognitionParams mRecognitionParams; + + FeaturesExtractingParams mSceneFeaturesExtractingParams; + + ImageTrackingModel *mpTarget; + }; + + static void *recognitionThreadFunc(void *recognitionInfo); + +public: + + /** + * @brief @ref ImageTracker constructor based on tracking algorithm + * parameters. + * + * @since_tizen 3.0 + * @param [in] trackingParams Parameters for image objects tracking + */ + ImageTracker(const TrackingParams& trackingParams); + + /** + * @brief Tracks the @a target for the video stream consisting of frames. + * + * @since_tizen 3.0 + * @remarks Call this function alternately for each frame + * @param [in] frame Current frame of the video stream + * @param [in,out] target @ref ImageTrackingModel, which will be tracked + */ + void track(const cv::Mat& frame, ImageTrackingModel& target); + +private: + + void trackDetectedObject( + const cv::Mat& frame, + ImageTrackingModel& target); + + void trackUndetectedObject( + const cv::Mat& frame, + ImageTrackingModel& target); + + cv::Rect computeExpectedArea( + const ImageTrackingModel& target, + const cv::Size& frameSize); + +private: + + TrackingParams m_trackingParams; +}; + +} /* Image */ +} /* MediaVision */ + +#endif /* __IMAGETRACKER_H__ */ diff --git a/mv_image/image/include/ImageTrackingModel.h b/mv_image/image/include/ImageTrackingModel.h new file mode 100644 index 0000000..2f55c2d --- /dev/null +++ b/mv_image/image/include/ImageTrackingModel.h @@ -0,0 +1,219 @@ +/** + * 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 __IMAGETRACKINGMODEL_H__ +#define __IMAGETRACKINGMODEL_H__ + +#include "ImageObject.h" + +#include "ImageContourStabilizator.h" + +#include + +#include + +#include +#include + +/** + * @file ImageTrackingModel.h + * @brief This file contains the @ref ImageTrackingModel class. + */ + +namespace MediaVision +{ +namespace Image +{ + +class ImageContourStabilizator; + +/** + * @class ImageTrackingModel + * @brief This class contains the tracking functionality for image objects. + * + * @since_tizen 3.0 + */ +class ImageTrackingModel +{ +private: + /** + * @brief @ref ImageTrackingModel state enumeration. + * + * @since_tizen 3.0 + */ + enum State + { + Invalid, /**< Invalid tracking model can not be tracked. Set not + empty image object as target by using function + @ref setTarget() to make tracking model valid, also + you can load valid tracking model by using @ref load() */ + Undetected, /**< The object was not recognized on the last frame. Ready + for further recognition */ + Appeared, /**< The object was recognized on one of the last frames + after its absence */ + Tracked, /**< The object was recognized on the last frame. Its + location can be obtained by calling method getLocation() */ + InProcess /**< The object is in the recognition process */ + }; + +public: + + /** + * @brief @ref ImageTrackingModel default constructor + * + * @since_tizen 3.0 + */ + ImageTrackingModel(); + + /** + * @brief @ref ImageTrackingModel constructor based on tracking algorithm + * parameters. + * + * @since_tizen 3.0 + * @param[in] recognitionObject @ref ImageObject which will be tracked + */ + ImageTrackingModel(const ImageObject& recognitionObject); + + /** + * @brief @ref ImageTrackingModel copy constructor. + * @details Creates copy of @ref ImageTrackingModel + * + * @since_tizen 3.0 + * @param [in] copy @ref ImageTrackingModel which will be copied + */ + ImageTrackingModel(const ImageTrackingModel& copy); + + /** + * @brief @ref ImageTrackingModel destructor. + * + * @since_tizen 3.0 + */ + ~ImageTrackingModel(); + + /** + * @brief Sets @ref ImageObject as target which will be tracked. + * + * @since_tizen 3.0 + * @param [in] target @ref ImageObject which will be tracked + */ + void setTarget(const ImageObject& target); + + /** + * @brief Checks whether the tracking model is valid for tracking. + * @details Image tracking model is valid if its target is set and not empty. + * + * @since_tizen 3.0 + * @remarks Invalid tracking model can not be tracked. Set not empty target + * by using corresponding constructor or function @ref setTarget() + * to make tracking model valid. Also you can load valid tracking + * model by using @ref load(). + * @return @c true if tracking model is valid, otherwise return @c false + */ + bool isValid() const; + + /** + * @brief Refreshes tracking model. + * + * @since_tizen 3.0 + * @remarks Call it before starting track on the new video stream. + */ + void refresh(void); + + /** + * @brief @ref ImageTrackingModel copy assignment operator. + * @details Fills the information based on the @a copy + * + * @since_tizen 3.0 + * @param [in] copy @ref ImageTrackingModel which will be copied + */ + ImageTrackingModel& operator=(const ImageTrackingModel& copy); + + /** + * @brief Stores the @ref ImageTrackingModel in a file. + * + * @since_tizen 3.0 + * @param [in] filepath File name which will be generated + * @return @a 0 on success, otherwise a negative error value + */ + int save(const char *filepath) const; + + /** + * @brief Loads the @ref ImageTrackingModel from the file. + * + * @since_tizen 3.0 + * @param [in] filepath File name from which will be loaded a model + * @return @a 0 on success, otherwise a negative error value + */ + int load(const char *filepath); + + /** + * @brief Checks state of the @ref ImageTrackingModel. + * + * @since_tizen 3.0 + * @return @a true if object was detected on the last processed frame, + * otherwise a @a false value + */ + bool isDetected() const; + + /** + * @brief Gets last location of the @ref ImageTrackingModel. + * + * @since_tizen 3.0 + * @return Last detected location + */ + std::vector getLastlocation() const; + +private: + + ImageObject m_recognitionObject; + + ImageContourStabilizator m_stabilizator; + + std::vector m_lastLocation; + + State m_state; + + pthread_t m_recognitionThread; + + mutable pthread_mutex_t m_globalGuard; + + mutable pthread_spinlock_t m_lastLocationGuard; + + mutable pthread_spinlock_t m_stateGuard; + + friend std::ostream& operator << ( + std::ostream& os, + const ImageTrackingModel::State& state); + + friend std::istream& operator >> ( + std::istream& is, + ImageTrackingModel::State& state); + + friend std::ostream& operator << ( + std::ostream& os, + const ImageTrackingModel& obj); + + friend std::istream& operator >> ( + std::istream& is, + ImageTrackingModel& obj); + + friend class ImageTracker; +}; + +} /* Image */ +} /* MediaVision */ + +#endif /* __IMAGETRACKINGMODEL_H__ */ diff --git a/mv_image/image/include/mv_image_open.h b/mv_image/image/include/mv_image_open.h new file mode 100644 index 0000000..f6128fd --- /dev/null +++ b/mv_image/image/include/mv_image_open.h @@ -0,0 +1,561 @@ +/** + * 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_IMAGE_OPEN_H__ +#define __TIZEN_MEDIAVISION_IMAGE_OPEN_H__ + +#include "mv_image.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file mv_image_open.h + * @brief This file contains the Media Vision Image API for the open module. + * Working with images (like planar objects): recognition and tracking. + */ + +/****************************/ +/* Image object recognition */ +/****************************/ + +/** + * @brief Recognizes the given image objects on the source image. + * @details Use this function to launch image recognition algorithm configured + * by @a engine_conf configuration. + * + * @since_tizen 3.0 + * @param [in] source The handle to the source image on which image + * objects will be recognized + * @param [in] image_objects The set of handles to the image objects which + * will be processed as targets of recognition + * @param [in] number_of_objects The number of image objects + * @param [in] engine_cfg The handle to the configuration of engine + * which will be used for recognition. If NULL, + * then default settings will be used. + * @param [in] recognized_cb The callback which will be called in order to + * process recognition result + * @param [in] user_data The user data to be passed to the + * @a recognized_cb + * @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_FORMAT Source colorspace + * isn't supported + * + * @pre Create a set of image objects using @ref mv_image_object_create_open() + * for each of them and construct (fill / load / clone) them on images that + * will be recognized + * @pre Create a source handle by calling @ref mv_create_source() and fill + * by the image for which recognition will be performed + * @post @a mv_image_recognized_cb will be called to process recognition result + * @post Release source image by using @ref mv_destroy_source() + * @post Release image objects by using @ref mv_image_object_destroy_open() for + * each handle from @a image_objects set + * + * @see mv_image_recognized_cb + * @see mv_source_h + * @see mv_create_source() + * @see mv_destroy_source() + * @see mv_image_object_h + * @see mv_image_object_create_open() + * @see mv_image_object_destroy_open() + * @see mv_engine_config_h + */ +int mv_image_recognize_open( + mv_source_h source, + const mv_image_object_h *image_objects, + int number_of_objects, + mv_engine_config_h engine_cfg, + mv_image_recognized_cb recognized_cb, + void *user_data); + +/*************************/ +/* Image object tracking */ +/*************************/ + +/** + * @brief Tracks the given image tracking model on the current frame + * @details Image tracking on a sequence of frames assumes calling this + * function for each frame in the correct order. + * @a tracked_cb will be called for result processing. + * + * @since_tizen 3.0 + * @remarks Tracking algorithm is usually using for recognition of image object + * on the sequence of images that are organized by time. For example, + * it may be the sequence of frames from a video stream. + * @remarks If object is lost during the tracking, system tries to find it + * further for the following frames. Therefore, tracking will be + * recovered when object appears again. + * @remarks Previous calls of @ref mv_image_track_open() for this + * @a image_tracking_model will affect on current call + * @param [in] source The handle to the current image of + * sequence where image tracking model + * will be tracked + * @param [in,out] image_tracking_model The handle to the image tracking model + * which processed as target of tracking + * @param [in] engine_cfg The handle to the configuration of + * engine which will be used for tracking. + * If NULL, then default settings will be + * used. + * @param [in] tracked_cb The callback which will receive + * tracking results + * @param [in] user_data The user data to be passed to the + * @a tracked_cb + * @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_FORMAT Source colorspace + * isn't supported + * + * @pre Create image tracking model by calling + * @ref mv_image_tracking_model_create_open() and set target by calling + * @ref mv_image_tracking_model_set_target_open() + * @pre Create a source images by calling @ref mv_create_source() for each of + * them and construct them based on sequence of images for which will be + * held image tracking + * @post @a tracked_cb will be called to process tracking result + * @post Release image tracking model by using + * @ref mv_image_tracking_model_destroy_open() + * + * @see mv_image_tracked_cb + * @see mv_source_h + * @see image_tracking_model_h + * @see mv_image_tracking_model_create_open() + * @see mv_image_tracking_model_set_target_open() + * @see mv_image_tracking_model_destroy_open() + */ +int mv_image_track_open( + mv_source_h source, + mv_image_tracking_model_h image_tracking_model, + mv_engine_config_h engine_cfg, + mv_image_tracked_cb tracked_cb, + void *user_data); + +/**************************/ +/* Image object behaviour */ +/**************************/ + +/** + * @brief Creates an image object. + * + * @since_tizen 3.0 + * @param [out] image_object A new handle to the image object + * @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 + * + * @pre Release image object by using mv_image_object_destroy_open() + * + * @see mv_image_object_destroy_open() + */ +int mv_image_object_create_open( + mv_image_object_h *image_object); + +/** + * @brief Destroys the image object. + * + * @since_tizen 3.0 + * @param [in] image_object The handle to the image object 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 + * + * @see mv_image_object_create_open() + */ +int mv_image_object_destroy_open( + mv_image_object_h image_object); + +/** + * @brief Fills the image object. + * @details Extracts data from @a source image which will be needed for + * recognition of depicted object in @a location. + * + * @since_tizen 3.0 + * @remarks After filling the image object it can be evaluated by + * @ref mv_image_object_get_recognition_rate_open(). If recognition + * rate is too low, try to use another image of object or change + * configuration parameters (see @ref mv_engine_config_h) and construct + * the image object again. + * @param [in,out] image_object The handle to the image object which will be + * filled and can be recognized in future + * @param [in] engine_cfg The handle to the configuration of engine + * which will be used for extract recognition + * data from @a source. If NULL, then default + * settings will be used. + * @param [in] source The source image where image object is depicted + * @param [in] location The pointer to location of the image object + * on the source image, or NULL if the object is + * shown in full + * @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_FORMAT Source colorspace + * isn't supported + * + * @pre Create image object by using @ref mv_image_object_create_open() + * @post Release image object by using @ref mv_image_object_destroy_open() + * + * @see mv_image_object_h + * @see mv_image_object_create_open() + * @see mv_image_object_get_recognition_rate_open() + * @see mv_image_recognize_open() + * @see mv_image_object_destroy_open() + * @see mv_engine_config_h + */ +int mv_image_object_fill_open( + mv_image_object_h image_object, + mv_engine_config_h engine_cfg, + mv_source_h source, + mv_rectangle_s *location); + +/** + * @brief Gets a value that determines how well an image object can be recognized. + * @details Recognition rate determines how well an image object can be + * recognized. This value can be from 0 to 1. If the recognition rate + * is 0 object can not be recognized and the bigger it is the more + * likely to recognize the object. + * + * @since_tizen 3.0 + * @remarks If recognition rate is too low, try to use another image of object + * or change some configuration parameters (see @ref mv_engine_config_h) + * and fill the image object again + * (see @ref mv_image_object_fill_open()). + * @param [in] image_object The handle to the image object which will be + * evaluated by this function + * @param [out] recognition_rate A value that determines how well an image + * object can be recognized, if 0 then object + * can not be recognized + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIA_VISION_ERROR_NONE Successful + * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter + * + * @pre Create image object by using @ref mv_image_object_create_open() + * @post Release image object by using @ref mv_image_object_destroy_open() + * + * @see mv_image_object_h + * @see mv_image_object_create_open() + * @see mv_image_object_fill_open() + * @see mv_image_object_destroy_open() + * @see mv_engine_config_h + */ +int mv_image_object_get_recognition_rate_open( + mv_image_object_h image_object, + double *recognition_rate); + +/** + * @brief Sets a label for the image object. + * + * @since_tizen 3.0 + * @param [in] image_object The handle to the image object for which the label + * will be assigned + * @param [in] label The label which will be assigned to the image + * object + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIA_VISION_ERROR_NONE Successful + * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter + * + * @pre Create image object by using @ref mv_image_object_create_open() + * @post Label could be received by using + * @ref mv_image_object_get_label_open() + * @post Release image object by using @ref mv_image_object_destroy_open() + * + * @see mv_image_object_get_label_open() + * @see mv_image_object_h + * @see mv_image_object_create_open() + * @see mv_image_object_destroy_open() + */ +int mv_image_object_set_label_open( + mv_image_object_h image_object, + int label); + +/** + * @brief Gets a label of image object. + * + * @since_tizen 3.0 + * @remarks If @a image_object have not a label, this function return + * MEDIA_VISION_ERROR_NO_DATA value. + * @param [in] image_object The handle to the image object from which a + * label will be received + * @param [out] label The label of image object + * @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_NO_DATA Image object hasn't label + * + * @pre Create image object by using @ref mv_image_object_create_open() + * @pre Set label for the image object by using + * @ref mv_image_object_set_label_open() + * @post Release image object by using @ref mv_image_object_destroy_open() + * + * @see mv_image_object_set_label_open() + * @see mv_image_object_h + * @see mv_image_object_create_open() + * @see mv_image_object_destroy_open() + */ +int mv_image_object_get_label_open( + mv_image_object_h image_object, + int *label); + +/** + * @brief Clones the image object. + * + * @since_tizen 3.0 + * @remarks @a dst must be released using mv_image_object_destroy_open(). + * @param [in] src The handle to the source image object + * @param [out] dst The handle to the destination image object + * @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 + * + * @pre Create image object handles by calling mv_image_object_create_open() + * + * @see mv_image_object_create_open() + * @see mv_image_object_destroy_open() + */ +int mv_image_object_clone_open( + mv_image_object_h src, + mv_image_object_h *dst); + +/** + * @brief Saves the image object. + * + * @since_tizen 3.0 + * @remarks @a image_object is saved to the application's data directory. + * @param [in] file_name Name of the file to save the image object + * @param [in] image_object The handle to the image object which will be saved + * @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_INVALID_PATH Invalid path + * @retval #MEDIA_VISION_ERROR_PERMISSION_DENIED Not permitted + * + * @see mv_image_object_create_open() + * @see mv_image_object_load_open() + * @see mv_image_object_destroy_open() + */ +int mv_image_object_save_open( + const char *file_name, mv_image_object_h image_object); + +/** + * @brief Loads an image object from the file. + * + * @since_tizen 3.0 + * @remarks @a image_object is loaded from the application's data directory. + * @a image_object must be destroyed using + * @ref mv_image_object_destroy(). + * @param [in] file_name Name of file to load the image object + * @param [out] image_object The handle to the image object which will be + * filled + * @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_INVALID_PATH Invalid path + * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory + * @retval #MEDIA_VISION_ERROR_PERMISSION_DENIED Not permitted + * + * @pre Image object can be preliminary saved with mv_image_object_save() + * function + * + * @see mv_image_object_save_open() + * @see mv_image_object_destroy_open() + */ +int mv_image_object_load_open( + const char *file_name, mv_image_object_h *image_object); + +/**********************************/ +/* Image tracking model behaviour */ +/**********************************/ + +/** + * @brief Creates an image tracking model. + * + * @since_tizen 3.0 + * @param [out] image_tracking_model A new handle to the image tracking model + * @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 + * + * @pre Release image tracking model by using mv_image_tracking_model_destroy_open() + * + * @see mv_image_tracking_model_destroy_open() + */ +int mv_image_tracking_model_create_open( + mv_image_tracking_model_h *image_tracking_model); + +/** + * @brief Sets target of image tracking model. + * @details Sets image object which will be tracked by using tracking + * functionality with @a image_tracking_model. + * + * @since_tizen 3.0 + * @param [in] image_object Image object which will be set + * as target for tracking + * @param [in] image_tracking_model Handle to the image tracking model + * for which will be set a new target + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIA_VISION_ERROR_NONE Successful + * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter + * + * @pre Create image tracking model by calling + * @ref mv_image_tracking_model_create_open() + * @pre Create an image object using @ref mv_image_object_create_open() and + * construct (fill / load / clone) it on image that will be tracking + * @post Release image object by using @ref mv_image_object_destroy_open() + * @post Release image tracking model by using + * @ref mv_image_tracking_model_destroy_open() + * + * @see mv_image_object_h + * @see mv_image_tracking_model_h + * @see mv_image_object_create_open() + * @see mv_image_object_destroy_open() + * @see mv_image_tracking_model_create_open() + * @see mv_image_track_open() + * @see mv_image_tracking_model_destroy_open() + */ +int mv_image_tracking_model_set_target_open( + mv_image_object_h image_object, + mv_image_tracking_model_h image_tracking_model); + +/** + * @brief Destroys the image tracking model. + * + * @since_tizen 3.0 + * @param [in] image_tracking_model The handle to the image tracking model + * 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 + * + * @pre Create image tracking model by using mv_image_tracking_model_create() + * + * @see mv_image_tracking_model_create_open() + */ +int mv_image_tracking_model_destroy_open( + mv_image_tracking_model_h image_tracking_model); + +/** + * @brief Refreshes the state of image tracking model. + * @details Clears moving history and change state to undetected. This function + * is usually called each time before tracking is started for the new + * sequence of sources which is not the direct continuation of the + * sequence for which tracking has been performed before. Tracking + * algorithm will try to find image by itself. + * + * @since_tizen 3.0 + * @param [in] image_tracking_model The handle to the image tracking model + * which will be refreshed + * @param [in] engine_cfg The handle to the configuration of + * engine which will be used. If NULL, + * then default settings will be used. + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIA_VISION_ERROR_NONE Successful + * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter + * + * @pre Create image tracking model by calling + * @ref mv_image_tracking_model_create_open() + * @post Release image tracking model by using + * @ref mv_image_tracking_model_destroy_open() + * + * @see mv_image_tracking_model_h + * @see mv_image_tracking_model_create_open() + * @see mv_image_track_open() + * @see mv_image_tracking_model_destroy_open() + */ +int mv_image_tracking_model_refresh_open( + mv_image_tracking_model_h image_tracking_model, + mv_engine_config_h engine_cfg); + +/** + * @brief Clones the image tracking model. + * + * @since_tizen 3.0 + * @remarks @a dst must be released using mv_image_tracking_model_destroy_open(). + * @param [in] src The handle to the source image tracking model + * @param [out] dst The handle to the destination image tracking model + * @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 + * + * @see mv_image_tracking_model_create_open() + * @see mv_image_tracking_model_destroy_open() + */ +int mv_image_tracking_model_clone_open( + mv_image_tracking_model_h src, + mv_image_tracking_model_h *dst); + +/** + * @brief Saves the image tracking model. + * + * @since_tizen 3.0 + * @remarks @a image_tracking_model is saved to the application's data directory. + * @param [in] file_name Name of file to save the model + * @param [in] image_tracking_model The handle to the image tracking model + * to be saved + * @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_INVALID_PATH Invalid path + * @retval #MEDIA_VISION_ERROR_PERMISSION_DENIED Not permitted + * + * @pre Create image tracking model handle by calling + * mv_image_tracking_model_create() + * @post Saved model can be loaded later by calling + * mv_image_tracking_model_load() function + + * @see mv_image_tracking_model_create_open() + * @see mv_image_tracking_model_load_open() + * @see mv_image_tracking_model_destroy_open() + */ +int mv_image_tracking_model_save_open( + const char *file_name, mv_image_tracking_model_h image_tracking_model); + +/** + * @brief Loads an image tracking model from the file. + * + * @since_tizen 3.0 + * @remarks @a image_tracking_model is loaded from the application's data directory. + * @a image_tracking_model must be destroyed using + * @ref mv_image_tracking_model_destroy. + * @param [in] file_name Name of file to load model + * @param [out] image_tracking_model The handle to the image tracking + * model to be filled + * @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_INVALID_PATH Invalid path + * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory + * @retval #MEDIA_VISION_ERROR_PERMISSION_DENIED Not permitted + * + * @pre Image tracking model handle can be preliminary saved with + * mv_image_tracking_model_save() function + * + * @see mv_image_tracking_model_save_open() + * @see mv_image_tracking_model_destroy_open() + */ +int mv_image_tracking_model_load_open( + const char *file_name, mv_image_tracking_model_h *image_tracking_model); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIAVISION_IMAGE_OPEN_H__ */ diff --git a/mv_image/image/src/ImageConfig.cpp b/mv_image/image/src/ImageConfig.cpp new file mode 100644 index 0000000..47fdaef --- /dev/null +++ b/mv_image/image/src/ImageConfig.cpp @@ -0,0 +1,104 @@ +/** + * 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 "ImageConfig.h" + +namespace MediaVision +{ +namespace Image +{ + +FeaturesExtractingParams::FeaturesExtractingParams( + double scaleFactor, + int maximumFeaturesNumber) : + mScaleFactor(scaleFactor), + mMaximumFeaturesNumber(maximumFeaturesNumber) +{ + ; /* NULL */ +} + +FeaturesExtractingParams::FeaturesExtractingParams() : + mScaleFactor(1.2), + mMaximumFeaturesNumber(800) +{ + ; /* NULL */ +} + +RecognitionParams::RecognitionParams( + int minMatchesNumber, + double requiredMatchesPart, + double allowableMatchesPartError) : + mMinMatchesNumber(minMatchesNumber), + mRequiredMatchesPart(requiredMatchesPart), + mAllowableMatchesPartError(allowableMatchesPartError) +{ + ; /* NULL */ +} + +RecognitionParams::RecognitionParams() : + mMinMatchesNumber(0), + mRequiredMatchesPart(1.0), + mAllowableMatchesPartError(0.0) +{ + ; /* NULL */ +} + +StabilizationParams::StabilizationParams( + int historyAmount, + double allowableShift, + double stabilizationSpeed, + double stabilizationAcceleration) : + mHistoryAmount(historyAmount), + mAllowableShift(allowableShift), + mStabilizationSpeed(stabilizationSpeed), + mStabilizationAcceleration(stabilizationAcceleration) +{ + ; /* NULL */ +} + +StabilizationParams::StabilizationParams() : + mHistoryAmount(1), + mAllowableShift(0.0), + mStabilizationSpeed(0.0), + mStabilizationAcceleration(1.0) +{ + ; /* NULL */ +} + +TrackingParams::TrackingParams( + FeaturesExtractingParams framesFeaturesExtractingParams, + RecognitionParams recognitionParams, + StabilizationParams stabilizationParams, + double expectedOffset) : + mFramesFeaturesExtractingParams(framesFeaturesExtractingParams), + mRecognitionParams(recognitionParams), + mStabilizationParams(stabilizationParams), + mExpectedOffset(expectedOffset) +{ + ; /* NULL */ +} + +TrackingParams::TrackingParams() : + mFramesFeaturesExtractingParams(), + mRecognitionParams(), + mStabilizationParams(), + mExpectedOffset(0.0) +{ + ; /* NULL */ +} + +} /* Image */ +} /* MediaVision */ diff --git a/mv_image/image/src/ImageContourStabilizator.cpp b/mv_image/image/src/ImageContourStabilizator.cpp new file mode 100644 index 0000000..1c48659 --- /dev/null +++ b/mv_image/image/src/ImageContourStabilizator.cpp @@ -0,0 +1,300 @@ +/** + * 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 "ImageContourStabilizator.h" +#include "ImageMathUtil.h" + +#include "mv_private.h" + +namespace MediaVision +{ +namespace Image +{ + +ImageContourStabilizator::ImageContourStabilizator() : + m_movingHistory(MovingHistoryAmount), + m_priorities(MovingHistoryAmount) +{ + reset(); + + // increasing the stabilization rate + m_speeds.push_back(0.3f); + m_speeds.push_back(0.4f); + m_speeds.push_back(0.5f); + m_speeds.push_back(0.6f); + m_speeds.push_back(0.8f); + m_speeds.push_back(1.f); + + // calculation of priorities for positions in the moving history + for (size_t i = 0u; i < MovingHistoryAmount; ++i) + { + // linear dependence on the elapsed time + m_priorities[i] = (i + 1) / ((MovingHistoryAmount + 1) * MovingHistoryAmount / 2.0f); + } +} + +void ImageContourStabilizator::reset(void) +{ + m_isPrepared = false; + m_tempContourIndex = -1; + m_currentHistoryAmount = 0; + + LOGI("Outlier is detected."); +} + +bool ImageContourStabilizator::stabilize( + std::vector& contour, + const StabilizationParams& /*params*/) +{ + // current implementation stabilizes quadrangles only + if (contour.size() != NumberOfQuadrangleCorners) + { + LOGW("Not stabilized. Empty contour."); + + return false; + } + + m_currentCornersSpeed.resize(contour.size(), 0); + + if (contour[0].x == contour[1].x && contour[0].y == contour[1].y) + { + LOGW("Not stabilized. Invalid contour."); + + return false; + } + + if (m_lastStabilizedContour.empty()) + { + m_lastStabilizedContour = contour; + } + + std::vector stabilizedState; + + // history amount < 2 it's no sense + if (MovingHistoryAmount >= 2) + { + // first sample + if (m_tempContourIndex == -1) + { + m_movingHistory[1] = contour; + m_tempContourIndex = 1; + m_currentHistoryAmount = 1; + + LOGI("Not stabilized. Too small moving history. (the first one)"); + + return false; + } + + // too short moving history + if (m_currentHistoryAmount < MovingHistoryAmount - 1) + { + ++m_currentHistoryAmount; + ++m_tempContourIndex; + m_movingHistory[m_tempContourIndex] = contour; + + LOGI("Not stabilized. Too small moving history."); + + return false; + } + + // saving into moving history + m_movingHistory.pop_front(); + m_movingHistory.push_back(contour); + + if (!m_isPrepared) + { + m_lastStabilizedContour = m_movingHistory[MovingHistoryAmount - 2]; + + LOGI("Not stabilized. Too small moving history. (the last one)"); + + m_isPrepared = true; + } + + // stabilization + stabilizedState = computeStabilizedQuadrangleContour(); + + if (stabilizedState.empty()) + { + stabilizedState = m_lastStabilizedContour; + } + } + else + { + stabilizedState = m_lastStabilizedContour; + } + + const float tolerantShift = getQuadrangleArea(contour.data()) * 0.00006f + 1.3f; + + const size_t contourSize = stabilizedState.size(); + for (size_t i = 0u; i < contourSize; ++i) + { + if (fabs(getDistance(stabilizedState[i], contour[i])) > tolerantShift) + { + const float dirX = m_lastStabilizedContour[i].x - contour[i].x; + const float dirY = m_lastStabilizedContour[i].y - contour[i].y; + + const float speedX = dirX * m_speeds[m_currentCornersSpeed[i]]; + const float speedY = dirY * m_speeds[m_currentCornersSpeed[i]]; + + // final moving + m_lastStabilizedContour[i].x -= speedX; + m_lastStabilizedContour[i].y -= speedY; + + if (m_currentCornersSpeed[i] < m_speeds.size() - 1) + { + ++m_currentCornersSpeed[i]; + } + } + else + { + m_currentCornersSpeed[i] = 0; + } + } + + // m_lastStabilizedContour = stabilizedState; + contour = m_lastStabilizedContour; + + LOGI("Contour successfully stabilized."); + + return true; +} + +std::vector ImageContourStabilizator::computeStabilizedQuadrangleContour(void) +{ + // final contour + std::vector stabilizedState( + NumberOfQuadrangleCorners, cv::Point2f(0.f, 0.f)); + + // calculation the direction of contour corners to a new location + std::vector directions( + NumberOfQuadrangleCorners, cv::Point2f(0.f, 0.f)); + + // computing expected directions and outliers searching + bool expressiveTime = false; + float summPriorityWithoutToLastPos[NumberOfQuadrangleCorners]; + float priorityToLastPos[NumberOfQuadrangleCorners]; + std::vector directionsToLastPos(NumberOfQuadrangleCorners); + for (size_t j = 0u; j < NumberOfQuadrangleCorners; ++j) + { + // calculation the moving directions and computing average direction + std::vector trackDirections(MovingHistoryAmount - 1); + cv::Point2f averageDirections(0.f, 0.f); + + for (size_t i = 0u; i < MovingHistoryAmount - 1; ++i) + { + averageDirections.x += (trackDirections[i].x = + m_movingHistory[i+1][j].x - m_movingHistory[i][j].x) / + (MovingHistoryAmount - 1); + + averageDirections.y += (trackDirections[i].y = + m_movingHistory[i+1][j].y - m_movingHistory[i][j].y) / + (MovingHistoryAmount - 1); + } + + // calculation a deviations and select outlier + std::vector directionDistances(MovingHistoryAmount - 1); + float maxDistance = 0.f, prevMaxDistance = 0.f; + int idxWithMaxDistance = 0; + int numExpressiveDirection = -1; + for (size_t i = 0u; i < MovingHistoryAmount - 1; ++i) + { + directionDistances[i] = getDistance( + trackDirections[i], + averageDirections); + + if (directionDistances[i] > prevMaxDistance) + { + if (directionDistances[i] > maxDistance) + { + prevMaxDistance = maxDistance; + maxDistance = directionDistances[i]; + idxWithMaxDistance = i; + } + else + { + prevMaxDistance = directionDistances[i]; + } + } + } + + // check outlier + if (0.6f * maxDistance > prevMaxDistance) + { + LOGI("Outlier is detected."); + + numExpressiveDirection = idxWithMaxDistance; + } + + // final direction computing + float summPriority = 0.f; + for (size_t i = 0u; i < MovingHistoryAmount - 1; ++i) + { + if ((int)i != numExpressiveDirection) + { + directions[j].x += trackDirections[i].x * m_priorities[i]; + directions[j].y += trackDirections[i].y * m_priorities[i]; + summPriority += m_priorities[i]; + } + } + if (numExpressiveDirection == MovingHistoryAmount - 1) + { + expressiveTime = true; + } + + summPriorityWithoutToLastPos[j] = summPriority; + priorityToLastPos[j] = m_priorities[MovingHistoryAmount - 1]; + + directions[j].x -= directionsToLastPos[j].x = + (m_lastStabilizedContour[j].x - + m_movingHistory[MovingHistoryAmount - 1][j].x) * + priorityToLastPos[j]; + + directions[j].y -= directionsToLastPos[j].y = + (m_lastStabilizedContour[j].y - + m_movingHistory[MovingHistoryAmount - 1][j].y) * + priorityToLastPos[j]; + + summPriority += priorityToLastPos[j]; + + directions[j].x /= summPriority; + directions[j].y /= summPriority; + } + + // final corners computing + for (size_t j = 0u; j < NumberOfQuadrangleCorners; ++j) + { + if (expressiveTime) + { + directions[j].x *= (summPriorityWithoutToLastPos[j] + + priorityToLastPos[j]); + directions[j].x -= directionsToLastPos[j].x; + directions[j].x /= summPriorityWithoutToLastPos[j]; + + directions[j].y *= (summPriorityWithoutToLastPos[j] + + priorityToLastPos[j]); + directions[j].y -= directionsToLastPos[j].y; + directions[j].y /= summPriorityWithoutToLastPos[j]; + } + + stabilizedState[j].x = m_lastStabilizedContour[j].x + directions[j].x; + stabilizedState[j].y = m_lastStabilizedContour[j].y + directions[j].y; + } + + return stabilizedState; +} + +} /* Image */ +} /* MediaVision */ diff --git a/mv_image/image/src/ImageMathUtil.cpp b/mv_image/image/src/ImageMathUtil.cpp new file mode 100644 index 0000000..8bf5ba8 --- /dev/null +++ b/mv_image/image/src/ImageMathUtil.cpp @@ -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. + */ + +#include "ImageMathUtil.h" + +namespace MediaVision +{ +namespace Image +{ + +float getDistance( + const cv::Point2f& point1, + const cv::Point2f& point2) +{ + return sqrt( + (point1.x - point2.x) * (point1.x - point2.x) + + (point1.y - point2.y) * (point1.y - point2.y)); +} + +float getTriangleArea( + const cv::Point2f& point1, + const cv::Point2f& point2, + const cv::Point2f& point3) +{ + float distances[3]; + + distances[0] = getDistance(point1, point2); + distances[1] = getDistance(point2, point3); + distances[2] = getDistance(point3, point1); + + const float semiperimeter = (distances[0] + distances[1] + distances[2]) / 2.0f; + + return sqrt(semiperimeter * + (semiperimeter - distances[0]) * + (semiperimeter - distances[1]) * + (semiperimeter - distances[2])); +} + +float getQuadrangleArea(const cv::Point2f points[NumberOfQuadrangleCorners]) +{ + return getTriangleArea(points[0], points[1], points[2]) + + getTriangleArea(points[0], points[3], points[2]); +} + +} /* Image */ +} /* MediaVision */ diff --git a/mv_image/image/src/ImageObject.cpp b/mv_image/image/src/ImageObject.cpp new file mode 100644 index 0000000..531ec62 --- /dev/null +++ b/mv_image/image/src/ImageObject.cpp @@ -0,0 +1,475 @@ +/** + * 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 "ImageObject.h" + +#include "ImageMathUtil.h" + +#include + +#include "mv_private.h" +#include "mv_common.h" + +#include +#include + +#include +#include + +namespace MediaVision +{ +namespace Image +{ + +ImageObject::ImageObject() : + m_isEmpty(true), + m_isLabeled(false), + m_label(0), + m_recognitionRate(0.f) +{ + ; /* NULL */ +} + +ImageObject::ImageObject(const cv::Mat& image, const FeaturesExtractingParams& params) : + m_isEmpty(true), + m_isLabeled(false), + m_label(0), + m_recognitionRate(0.f) +{ + fill(image, params); +} + +ImageObject::ImageObject(const ImageObject& copy) : + m_isEmpty(copy.m_isEmpty), + m_isLabeled(copy.m_isLabeled), + m_label(copy.m_label), + m_boundingContour(copy.m_boundingContour), + m_objectKeypoints(copy.m_objectKeypoints), + m_objectDescriptors(copy.m_objectDescriptors.clone()), + m_recognitionRate(copy.m_recognitionRate) +{ + ; /* NULL */ +} + +ImageObject& ImageObject::operator=(const ImageObject& copy) +{ + if (this != ©) + { + m_isEmpty = copy.m_isEmpty; + m_isLabeled = copy.m_isLabeled; + m_label = copy.m_label; + m_boundingContour = copy.m_boundingContour; + m_objectKeypoints = copy.m_objectKeypoints; + m_objectDescriptors = copy.m_objectDescriptors.clone(); + m_recognitionRate = copy.m_recognitionRate; + } + return *this; +} + +ImageObject::~ImageObject() +{ + ; /* NULL */ +} + +void ImageObject::fill(const cv::Mat& image, const FeaturesExtractingParams& params) +{ + m_isEmpty = false; + m_boundingContour.resize(NumberOfQuadrangleCorners); + + m_boundingContour[0].x = 0.f; + m_boundingContour[0].y = 0.f; + + m_boundingContour[1].x = image.cols; + m_boundingContour[1].y = 0.f; + + m_boundingContour[2].x = image.cols; + m_boundingContour[2].y = image.rows; + + m_boundingContour[3].x = 0.f; + m_boundingContour[3].y = image.rows; + + extractFeatures(image, params); + + computeRecognitionRate(image); + + LOGI("[%s] Image object is filled.", __FUNCTION__); +} + +bool ImageObject::fill(const cv::Mat& image, const cv::Rect& boundingBox, + const FeaturesExtractingParams& params) +{ + if ((0 > boundingBox.x) || (0 >= boundingBox.width) || + (0 > boundingBox.y) || (0 >= boundingBox.height) || + (image.cols < (boundingBox.x + boundingBox.width)) || + (image.rows < (boundingBox.y + boundingBox.height))) + { + LOGE("[%s] Invalid ROI.", __FUNCTION__); + return false; + } + + m_isEmpty = false; + m_boundingContour.resize(NumberOfQuadrangleCorners); + + m_boundingContour[0].x = 0.f; + m_boundingContour[0].y = 0.f; + + m_boundingContour[1].x = boundingBox.width; + m_boundingContour[1].y = 0.f; + + m_boundingContour[2].x = boundingBox.width; + m_boundingContour[2].y = boundingBox.height; + + m_boundingContour[3].x = 0.f; + m_boundingContour[3].y = boundingBox.height; + + cv::Mat objectImage(image, boundingBox); + + extractFeatures(objectImage, params); + + computeRecognitionRate(image); + + LOGI("[%s] Image object is filled.", __FUNCTION__); + + return true; +} + +void ImageObject::extractFeatures(const cv::Mat& image, + const FeaturesExtractingParams& params) +{ + cv::ORB orb(params.mMaximumFeaturesNumber, params.mScaleFactor); + + if (image.cols < MinWidth || image.rows < MinHeight) + { + LOGW("[%s] Area is too small, recognition rate is 0.", __FUNCTION__); + m_objectKeypoints.clear(); + m_objectDescriptors = cv::Mat(); + } + else + { + orb.detect(image, m_objectKeypoints); + orb.compute(image, m_objectKeypoints, m_objectDescriptors); + } +} + +void ImageObject::computeRecognitionRate(const cv::Mat& image) +{ + const size_t numberOfKeypoints = m_objectKeypoints.size(); + + // it is impossible to calculate the perspective transformation parameters + // if number of key points less than MinimumNumberOfFeatures (4) + if (numberOfKeypoints < MinimumNumberOfFeatures) + { + m_recognitionRate = 0.f; + return; + } + + static const size_t xCellsNumber = 10u; + static const size_t yCellsNumber = 10u; + + cv::Mat cells[xCellsNumber][yCellsNumber]; + size_t accumulationCounter[xCellsNumber][yCellsNumber]; + + const size_t cellWidth = image.cols / xCellsNumber; + const size_t cellHeight = image.rows / yCellsNumber; + + for (size_t x = 0u; x < xCellsNumber; ++x) + { + for (size_t y = 0u; y < yCellsNumber; ++y) + { + cells[x][y] = image(cv::Rect( + x * cellWidth, + y * cellHeight, + cellWidth, + cellHeight)); + + accumulationCounter[x][y] = 0; + } + } + + for (size_t i = 0u; i < numberOfKeypoints; ++i) + { + size_t xCellIdx = m_objectKeypoints[i].pt.x / cellWidth; + if (xCellIdx >= xCellsNumber) + { + xCellIdx = xCellsNumber - 1; + } + size_t yCellIdx = m_objectKeypoints[i].pt.y / cellHeight; + if (yCellIdx >= yCellsNumber) + { + yCellIdx = yCellsNumber - 1; + } + ++(accumulationCounter[xCellIdx][yCellIdx]); + } + + const float exceptedNumber = numberOfKeypoints / + (float)(xCellsNumber * yCellsNumber); + + float distributedEvaluation = 0.f; + + for (size_t x = 0u; x < xCellsNumber; ++x) + { + for (size_t y = 0u; y < yCellsNumber; ++y) + { + distributedEvaluation += (accumulationCounter[x][y] - exceptedNumber) * + (accumulationCounter[x][y] - exceptedNumber) / exceptedNumber; + } + } + + float maximumDistributedEvaluation = (xCellsNumber * yCellsNumber - 1) * + exceptedNumber; + + maximumDistributedEvaluation += (numberOfKeypoints - exceptedNumber) * + (numberOfKeypoints - exceptedNumber) / exceptedNumber; + + distributedEvaluation = 1 - + (distributedEvaluation / maximumDistributedEvaluation); + + // Exponentiation to find an approximate confidence value based on the + // number of key points on the image. + const float cardinalityEvaluation = pow(-0.9, numberOfKeypoints - 3) + 1.0f; + + m_recognitionRate = + distributedEvaluation * + cardinalityEvaluation; +} + +float ImageObject::getRecognitionRate(void) const +{ + return m_recognitionRate; +} + +bool ImageObject::isEmpty() const +{ + return m_isEmpty; +} + +void ImageObject::setLabel(int label) +{ + m_isLabeled = true; + m_label = label; +} + +bool ImageObject::getLabel(int& label) const +{ + if (!m_isLabeled) + { + LOGW("[%s] Image hasn't label.", __FUNCTION__); + return false; + } + label = m_label; + return true; +} + +int ImageObject::save(const char *fileName) const +{ + std::string prefix_path = std::string(app_get_data_path()); + LOGD("prefix_path: %s", prefix_path.c_str()); + + std::string filePath; + filePath += prefix_path; + filePath += fileName; + + /* check the directory is available */ + std::string prefix_path_check = filePath.substr(0, filePath.find_last_of('/')); + if (access(prefix_path_check.c_str(), F_OK)) + { + LOGE("Can't save image object. Path[%s] doesn't existed.", prefix_path_check.c_str()); + + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + std::ofstream out; + + out.open(filePath.c_str()); + + if (!out.is_open()) + { + LOGE("[%s] Can't create/open file.", __FUNCTION__); + return MEDIA_VISION_ERROR_PERMISSION_DENIED; + } + + out<<(*this); + + out.close(); + LOGI("[%s] Image object is saved.", __FUNCTION__); + + return MEDIA_VISION_ERROR_NONE; +} + +int ImageObject::load(const char *fileName) +{ + /* find directory */ + std::string prefix_path = std::string(app_get_data_path()); + LOGD("prefix_path: %s", prefix_path.c_str()); + + std::string filePath; + filePath += prefix_path; + filePath += fileName; + + if (access(filePath.c_str(), F_OK)) + { + LOGE("Can't load image object model. Path[%s] doesn't existed.", filePath.c_str()); + + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + std::ifstream in; + in.open(filePath.c_str()); + + if (!in.is_open()) + { + LOGE("[%s] Can't open file.", __FUNCTION__); + return MEDIA_VISION_ERROR_PERMISSION_DENIED; + } + + in>>(*this); + + if (!in.good()) + { + LOGE("[%s] Unexpected end of file.", __FUNCTION__); + return MEDIA_VISION_ERROR_PERMISSION_DENIED; + } + + in.close(); + LOGI("[%s] Image object is loaded.", __FUNCTION__); + + return MEDIA_VISION_ERROR_NONE; +} + +std::ostream& operator << (std::ostream& os, const ImageObject& obj) +{ + os<(descriptorNum, featureNum)<<' '; + } + } + + return os; +} + +std::istream& operator >> (std::istream& is, ImageObject& obj) +{ + size_t numberOfContourPoints = 0u; + size_t numberOfKeyPoints = 0u; + int rows = 0, cols = 0; + int descriptorType = 0; + + ImageObject temporal; + +#define MEDIA_VISION_CHECK_IFSTREAM \ + if (!is.good()) \ + { \ + return is; \ + } + + is>>temporal.m_isEmpty; + MEDIA_VISION_CHECK_IFSTREAM + is>>temporal.m_isLabeled; + MEDIA_VISION_CHECK_IFSTREAM + is>>temporal.m_label; + MEDIA_VISION_CHECK_IFSTREAM + + is>>numberOfContourPoints; + MEDIA_VISION_CHECK_IFSTREAM + + temporal.m_boundingContour.resize(numberOfContourPoints); + for (size_t pointNum = 0; pointNum < temporal.m_boundingContour.size(); ++pointNum) + { + is>>temporal.m_boundingContour[pointNum].x; + MEDIA_VISION_CHECK_IFSTREAM + is>>temporal.m_boundingContour[pointNum].y; + MEDIA_VISION_CHECK_IFSTREAM + } + + is>>numberOfKeyPoints; + temporal.m_objectKeypoints.resize(numberOfKeyPoints); + for (size_t keypointNum = 0; keypointNum < temporal.m_objectKeypoints.size(); ++keypointNum) + { + is>>temporal.m_objectKeypoints[keypointNum].pt.x; + MEDIA_VISION_CHECK_IFSTREAM + is>>temporal.m_objectKeypoints[keypointNum].pt.y; + MEDIA_VISION_CHECK_IFSTREAM + is>>temporal.m_objectKeypoints[keypointNum].size; + MEDIA_VISION_CHECK_IFSTREAM + is>>temporal.m_objectKeypoints[keypointNum].response; + MEDIA_VISION_CHECK_IFSTREAM + is>>temporal.m_objectKeypoints[keypointNum].angle; + MEDIA_VISION_CHECK_IFSTREAM + is>>temporal.m_objectKeypoints[keypointNum].octave; + MEDIA_VISION_CHECK_IFSTREAM + is>>temporal.m_objectKeypoints[keypointNum].class_id; + MEDIA_VISION_CHECK_IFSTREAM + } + + is>>rows; + MEDIA_VISION_CHECK_IFSTREAM + is>>cols; + MEDIA_VISION_CHECK_IFSTREAM + is>>descriptorType; + MEDIA_VISION_CHECK_IFSTREAM + temporal.m_objectDescriptors = cv::Mat(rows, cols, descriptorType); + int value = 0; + for (int descriptorNum = 0; descriptorNum < temporal.m_objectDescriptors.rows; ++descriptorNum) + { + for (int featureNum = 0; featureNum < temporal.m_objectDescriptors.cols; ++featureNum) + { + is>>value; + MEDIA_VISION_CHECK_IFSTREAM + temporal.m_objectDescriptors.at(descriptorNum, featureNum) = (uchar)value; + } + } + +#undef MEDIA_VISION_CHECK_IFSTREAM + + obj = temporal; + + return is; +} + +} /* Image */ +} /* MediaVision */ diff --git a/mv_image/image/src/ImageRecognizer.cpp b/mv_image/image/src/ImageRecognizer.cpp new file mode 100644 index 0000000..c921555 --- /dev/null +++ b/mv_image/image/src/ImageRecognizer.cpp @@ -0,0 +1,312 @@ +/** + * 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 "ImageRecognizer.h" +#include "ImageObject.h" + +#include "mv_private.h" + +namespace MediaVision +{ +namespace Image +{ + +ImageRecognizer::ImageRecognizer( + const cv::Mat& sceneImage, + const FeaturesExtractingParams& params) : + m_scene(sceneImage, params) +{ + ; /* NULL */ +} + +ImageRecognizer::ImageRecognizer(const ImageObject& scene) : + m_scene(scene) +{ + ; /* NULL */ +} + +ImageRecognizer::~ImageRecognizer() +{ + ; /* NULL */ +} + +bool ImageRecognizer::recognize( + const ImageObject& target, + const RecognitionParams& params, + std::vector& contour) const +{ + cv::Mat homophraphyMatrix; + + contour.clear(); + + if (MinimumNumberOfFeatures > target.m_objectKeypoints.size()) + { + LOGW("[%s] Image object can't be recognized (Recognition rate is too small).", __FUNCTION__); + return false; + } + if (MinimumNumberOfFeatures > m_scene.m_objectKeypoints.size()) + { + LOGW("[%s] Scene image can't be analyzed (Too few features for recognition).", __FUNCTION__); + return false; + } + + if(!findHomophraphyMatrix(target, params, homophraphyMatrix)) + { + LOGE("[%s] Can't match the features.", __FUNCTION__); + return false; + } + + cv::perspectiveTransform(target.m_boundingContour, contour, homophraphyMatrix); + + if (target.m_boundingContour.size() == NumberOfQuadrangleCorners) + { + if (!isPossibleQuadrangleCorners(contour.data())) + { + LOGI("[%s] Image object isn't recognized.", __FUNCTION__); + contour.clear(); + return false; + } + } + + LOGI("[%s] Image object is recognized.", __FUNCTION__); + return true; +} + +bool ImageRecognizer::findHomophraphyMatrix( + const ImageObject& target, + const RecognitionParams& params, + cv::Mat& homophraphyMatrix) const +{ + std::vector matches; + + m_matcher.match(target.m_objectDescriptors, m_scene.m_objectDescriptors, matches); + + size_t matchesNumber = matches.size(); + + if (MinimumNumberOfFeatures > matchesNumber) + { + LOGE("[%s] Can't match the features.", __FUNCTION__); + return false; + } + + size_t requiredMatchesNumber = + params.mRequiredMatchesPart * matchesNumber; + + size_t allowableMatchesNumberError = + params.mAllowableMatchesPartError * requiredMatchesNumber; + + if (matchesNumber - allowableMatchesNumberError > + (size_t)params.mMinMatchesNumber && + requiredMatchesNumber + allowableMatchesNumberError < + matchesNumber) + { + if (requiredMatchesNumber - allowableMatchesNumberError < + (size_t)params.mMinMatchesNumber) + { + if (requiredMatchesNumber + allowableMatchesNumberError > + (size_t)params.mMinMatchesNumber) + { + requiredMatchesNumber = ((size_t)params.mMinMatchesNumber + + requiredMatchesNumber + allowableMatchesNumberError) / 2; + + allowableMatchesNumberError = requiredMatchesNumber- + (size_t)params.mMinMatchesNumber + + allowableMatchesNumberError; + } + else + { + const size_t minimalAllowableMatchesNumberError = 2u; + + requiredMatchesNumber = params.mMinMatchesNumber + + minimalAllowableMatchesNumberError; + + allowableMatchesNumberError = minimalAllowableMatchesNumberError; + } + } + + const size_t filterAmount = matchesSelection(matches, + requiredMatchesNumber, + allowableMatchesNumberError); + + if (filterAmount >= MinimumNumberOfFeatures) + { + matches.resize(filterAmount); + } + else + { + LOGW("[%s] Wrong filtration of feature matches.", __FUNCTION__); + } + + matchesNumber = matches.size(); + } + + std::vector objectPoints(matchesNumber); + std::vector scenePoints(matchesNumber); + + for (size_t matchIdx = 0; matchIdx < matchesNumber; ++matchIdx) + { + objectPoints[matchIdx] = + target.m_objectKeypoints[matches[matchIdx].queryIdx].pt; + + scenePoints[matchIdx] = + m_scene.m_objectKeypoints[matches[matchIdx].trainIdx].pt; + } + + homophraphyMatrix = cv::findHomography(objectPoints, scenePoints, CV_RANSAC); + + return true; +} + +size_t ImageRecognizer::matchesSelection( + std::vector& examples, + unsigned int filterAmount, unsigned int allowableError) const +{ + size_t sizeOfExamples = examples.size(); + + if ((filterAmount + allowableError) > sizeOfExamples) + { + return examples.size(); + } + + int startLeftLimit = 0; + int startRightLimit = sizeOfExamples - 1; + + int leftLimit = startLeftLimit; + int rightLimit = startRightLimit; + + int requiredNumber = filterAmount; + + float supportElement = 0.f; + + while (true) + { + if (leftLimit >= rightLimit) + { + if (leftLimit < (requiredNumber - (int)allowableError)) + { + leftLimit = requiredNumber + (int)allowableError; + } + + break; + } + + supportElement = computeLinearSupportElement(examples, requiredNumber, + leftLimit, rightLimit); + + // Iteration similar quicksort + while (true) + { + // Search the leftmost element which have bigger confidence than support element + while (examples[leftLimit].distance <= supportElement && + leftLimit < startRightLimit) + { + ++leftLimit; + } + + // Search the rightmost element which have smaller confidence than support element + while (examples[rightLimit].distance >= supportElement && + rightLimit >= startLeftLimit) + { + --rightLimit; + } + + if (leftLimit >= rightLimit) + { + break; + } + + // Swap + std::swap(examples[leftLimit], examples[rightLimit]); + } + if (abs(filterAmount - leftLimit) <= (int)allowableError) + { + break; + } + if ((int)filterAmount > leftLimit) + { + requiredNumber -= leftLimit - startLeftLimit; + + rightLimit = startRightLimit; + startLeftLimit = leftLimit; + } + else + { + leftLimit = startLeftLimit; + startRightLimit = rightLimit; + } + } + + return (size_t)leftLimit; +} + +float ImageRecognizer::computeLinearSupportElement(const std::vector& examples, + int requiredNumber, int leftLimit, int rightLimit) const +{ + int sizeOfExamples = rightLimit - leftLimit + 1; + + if (sizeOfExamples <= 1) + { + return examples[leftLimit].distance; + } + + float minValue = examples[leftLimit].distance; + float maxValue = examples[leftLimit].distance; + + // Finding the maximum and minimum values + for (int i = leftLimit + 1; i <= rightLimit; ++i) + { + if (minValue > examples[i].distance) + { + minValue = examples[i].distance; + } + else if (maxValue < examples[i].distance) + { + maxValue = examples[i].distance; + } + } + + // Linear approximation. f(x) = k*x + b + // f(sizeOfExamples) = maxValue; f(1) = minValue; + const float b = (maxValue - minValue * sizeOfExamples) / (1 - sizeOfExamples); + const float k = minValue - b; + + // Calculation of the support element + return k * requiredNumber + b; +} + +bool ImageRecognizer::isPossibleQuadrangleCorners( + const cv::Point2f corners[NumberOfQuadrangleCorners]) +{ + static const float Epsilon = cv::TermCriteria::EPS; + static const float MinSizeOfDetectedArea = 30.f; + + const float firstSemiArea = getTriangleArea(corners[0], corners[2], corners[1]) + + getTriangleArea(corners[0], corners[2], corners[3]); + + const float secondSemiArea = getTriangleArea(corners[1], corners[3], corners[2]) + + getTriangleArea(corners[1], corners[3], corners[0]); + + if (Epsilon < fabs(firstSemiArea - secondSemiArea) || + MinSizeOfDetectedArea > (firstSemiArea + secondSemiArea)) + { + return false; + } + + return true; +} + +} /* Image */ +} /* MediaVision */ diff --git a/mv_image/image/src/ImageTracker.cpp b/mv_image/image/src/ImageTracker.cpp new file mode 100644 index 0000000..9c114f5 --- /dev/null +++ b/mv_image/image/src/ImageTracker.cpp @@ -0,0 +1,372 @@ +/** + * 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 "ImageTracker.h" + +#include "ImageMathUtil.h" +#include "ImageRecognizer.h" +#include "ImageTrackingModel.h" +#include "ImageContourStabilizator.h" + +#include "mv_private.h" + +#include + +namespace MediaVision +{ +namespace Image +{ + +ImageTracker::ImageTracker(const TrackingParams& trackingParams) : + m_trackingParams(trackingParams) +{ + ; /* NULL */ +} + +void ImageTracker::track(const cv::Mat& frame, ImageTrackingModel& target) +{ + ImageTrackingModel::State currentState = ImageTrackingModel::Undetected; + + while (pthread_mutex_trylock(&target.m_globalGuard) != 0) + { + pthread_spin_lock(&target.m_stateGuard); + currentState = target.m_state; + pthread_spin_unlock(&target.m_stateGuard); + + if (ImageTrackingModel::InProcess == currentState) + { + LOGI("[%s] Calling is skipped. Object is recognizing.", __FUNCTION__); + return; + } + } + + pthread_spin_lock(&target.m_stateGuard); + currentState = target.m_state; + pthread_spin_unlock(&target.m_stateGuard); + + if (ImageTrackingModel::Invalid == currentState) + { + pthread_mutex_unlock(&target.m_globalGuard); + LOGE("[%s] Tracking model is invalid.", __FUNCTION__); + return; + } + + switch (target.m_state) + { + case ImageTrackingModel::Appeared: + case ImageTrackingModel::Tracked: + { + pthread_spin_lock(&target.m_stateGuard); + target.m_state = ImageTrackingModel::InProcess; + pthread_spin_unlock(&target.m_stateGuard); + + trackDetectedObject(frame, target); + break; + } + case ImageTrackingModel::Undetected: + { + pthread_spin_lock(&target.m_stateGuard); + target.m_state = ImageTrackingModel::InProcess; + pthread_spin_unlock(&target.m_stateGuard); + + trackUndetectedObject(frame, target); + + // Recognition thread is started. Don't use target here, just exit! + return; + } + case ImageTrackingModel::InProcess: + default: + { + // Abnormal behaviour: + // tracking model state is InProcess but globalGuard is not locked + LOGE("[%s] Abnormal behaviour. Tracking model status is" + "\"InProgress\" but it is not in progress.", __FUNCTION__); + + pthread_spin_lock(&target.m_stateGuard); + if (target.m_recognitionObject.isEmpty()) + { + target.m_state = ImageTrackingModel::Invalid; + LOGI("[%s] Tracking model status is changed on \"Invalid\"", __FUNCTION__); + } + else + { + target.m_state = ImageTrackingModel::Undetected; + LOGI("[%s] Tracking model status is changed on \"Undetected\"", __FUNCTION__); + } + pthread_spin_unlock(&target.m_stateGuard); + + pthread_mutex_unlock(&target.m_globalGuard); + break; + } + } +} + +void ImageTracker::trackDetectedObject( + const cv::Mat& frame, + ImageTrackingModel& target) +{ + cv::Rect expectedArea = computeExpectedArea(target, frame.size()); + + std::vector resultContour; + + ImageRecognizer recognizer( + frame(expectedArea), + m_trackingParams.mFramesFeaturesExtractingParams); + + const bool isRecognized = recognizer.recognize( + target.m_recognitionObject, + m_trackingParams.mRecognitionParams, + resultContour); + + if (isRecognized) + { + for (size_t pointIdx = 0; pointIdx < resultContour.size(); ++pointIdx) + { + resultContour[pointIdx].x += expectedArea.x; + resultContour[pointIdx].y += expectedArea.y; + } + + if (m_trackingParams.mStabilizationParams.mHistoryAmount > 0) + { + target.m_stabilizator.stabilize( + resultContour, + m_trackingParams.mStabilizationParams); + } + + target.m_stabilizator.stabilize( + resultContour, + m_trackingParams.mStabilizationParams); + + pthread_spin_lock(&target.m_lastLocationGuard); + target.m_lastLocation = resultContour; + pthread_spin_unlock(&target.m_lastLocationGuard); + + pthread_spin_lock(&target.m_stateGuard); + target.m_state = ImageTrackingModel::Tracked; + pthread_spin_unlock(&target.m_stateGuard); + + LOGI("[%s] Object is successfully tracked.", __FUNCTION__); + } + else + { + target.m_stabilizator.reset(); + + pthread_spin_lock(&target.m_stateGuard); + target.m_state = ImageTrackingModel::Undetected; + pthread_spin_unlock(&target.m_stateGuard); + + LOGI("[%s] Object is lost.", __FUNCTION__); + } + + pthread_mutex_unlock(&target.m_globalGuard); +} + +void *ImageTracker::recognitionThreadFunc(void *recognitionInfo) +{ + if (NULL == recognitionInfo) + { + return NULL; + } + + RecognitionInfo *recogInfo = (RecognitionInfo*)recognitionInfo; + + std::vector resultContour; + + ImageRecognizer recognizer( + recogInfo->mFrame, + recogInfo->mSceneFeaturesExtractingParams); + + bool isRecognized = recognizer.recognize( + recogInfo->mpTarget->m_recognitionObject, + recogInfo->mRecognitionParams, + resultContour); + + if (isRecognized) + { + recogInfo->mpTarget->m_stabilizator.reset(); + + pthread_spin_lock(&(recogInfo->mpTarget->m_lastLocationGuard)); + recogInfo->mpTarget->m_lastLocation = resultContour; + pthread_spin_unlock(&(recogInfo->mpTarget->m_lastLocationGuard)); + + pthread_spin_lock(&(recogInfo->mpTarget->m_stateGuard)); + recogInfo->mpTarget->m_state = ImageTrackingModel::Appeared; + pthread_spin_unlock(&(recogInfo->mpTarget->m_stateGuard)); + } + else + { + pthread_spin_lock(&(recogInfo->mpTarget->m_stateGuard)); + recogInfo->mpTarget->m_state = ImageTrackingModel::Undetected; + pthread_spin_unlock(&(recogInfo->mpTarget->m_stateGuard)); + } + + recogInfo->mpTarget->m_recognitionThread = 0; + + pthread_mutex_unlock(&(recogInfo->mpTarget->m_globalGuard)); + + delete recogInfo; + + return NULL; +} + +void ImageTracker::trackUndetectedObject( + const cv::Mat& frame, + ImageTrackingModel& target) +{ + RecognitionInfo *recognitionInfo = new RecognitionInfo; + + recognitionInfo->mFrame = frame.clone(); + recognitionInfo->mpTarget = ⌖ + + recognitionInfo->mRecognitionParams = + m_trackingParams.mRecognitionParams; + recognitionInfo->mSceneFeaturesExtractingParams = + m_trackingParams.mFramesFeaturesExtractingParams; + + if (target.m_recognitionThread) + { + // Abnormal behaviour: + // Recognition thread isn't finished but guardian mutex is unlocked + LOGE("[%s] Abnormal behaviour. Recognition thread isn't finished but" + "guardian mutex is unlocked.", __FUNCTION__); + + LOGI("[%s] Try to wait recognition thread.", __FUNCTION__); + pthread_join(target.m_recognitionThread, NULL); + target.m_recognitionThread = 0; + LOGI("[%s] Recognition thread is finished.", __FUNCTION__); + } + + const int err = pthread_create( + &target.m_recognitionThread, + NULL, + recognitionThreadFunc, + recognitionInfo); + + if (0 == err) + { + LOGI("[%s] Recognition thread is started.", __FUNCTION__); + // Recognition thread is started. Don't use target here, just exit! + return; + } + LOGE("[%s] Recognition thread creation is failed.", __FUNCTION__); + + pthread_spin_lock(&target.m_stateGuard); + if (target.m_recognitionObject.isEmpty()) + { + target.m_state = ImageTrackingModel::Invalid; + LOGI("[%s] Tracking model status is changed on \"Invalid\"", __FUNCTION__); + } + else + { + target.m_state = ImageTrackingModel::Undetected; + LOGI("[%s] Tracking model status is changed on \"Undetected\"", __FUNCTION__); + } + pthread_spin_unlock(&target.m_stateGuard); + + pthread_mutex_unlock(&target.m_globalGuard); +} + +cv::Rect ImageTracker::computeExpectedArea( + const ImageTrackingModel& target, + const cv::Size& frameSize) +{ + if (target.m_state == ImageTrackingModel::Appeared) + { + LOGI("[%s] Expected area for appeared object is full frame.", __FUNCTION__); + return cv::Rect(0, 0, frameSize.width, frameSize.height); + } + + if (target.m_lastLocation.empty()) + { + LOGW("[%s] Can't compute expected area for object without last" + "location.",__FUNCTION__); + return cv::Rect(0, 0, 0, 0); + } + + cv::Point2f ltCorner(target.m_lastLocation[0]); + cv::Point2f rbCorner(target.m_lastLocation[0]); + + const size_t contourPointsNumber = target.m_lastLocation.size(); + + for (size_t pointNum = 1; pointNum < contourPointsNumber; ++pointNum) + { + if (ltCorner.x > target.m_lastLocation[pointNum].x) + { + ltCorner.x = target.m_lastLocation[pointNum].x; + } + else if (rbCorner.x < target.m_lastLocation[pointNum].x) + { + rbCorner.x = target.m_lastLocation[pointNum].x; + } + + if (ltCorner.y > target.m_lastLocation[pointNum].y) + { + ltCorner.y = target.m_lastLocation[pointNum].y; + } + else if (rbCorner.y < target.m_lastLocation[pointNum].y) + { + rbCorner.y = target.m_lastLocation[pointNum].y; + } + } + + cv::Point2f center( + (ltCorner.x + rbCorner.x) / 2.0f, + (ltCorner.y + rbCorner.y) / 2.0f); + + cv::Size2f halfSize( + (center.x - ltCorner.x) * (1 + m_trackingParams.mExpectedOffset), + (center.y - ltCorner.y) * (1 + m_trackingParams.mExpectedOffset)); + + + cv::Rect expectedArea( + center.x - halfSize.width, center.y - halfSize.height, + halfSize.width * 2, halfSize.height * 2); + + if (expectedArea.x < 0) + { + expectedArea.width += expectedArea.x; + expectedArea.x = 0; + } + + if (expectedArea.y < 0) + { + expectedArea.height += expectedArea.y; + expectedArea.y = 0; + } + + if (expectedArea.x + expectedArea.width > frameSize.width) + { + expectedArea.width = frameSize.width - expectedArea.x; + } + + if (expectedArea.y + expectedArea.height > frameSize.height) + { + expectedArea.height = frameSize.height - expectedArea.y; + } + + if (expectedArea.width <= 0 || expectedArea.height <= 0) + { + expectedArea.x = 0; + expectedArea.y = 0; + expectedArea.width = 0; + expectedArea.height = 0; + } + + return expectedArea; +} + +} /* Image */ +} /* MediaVision */ diff --git a/mv_image/image/src/ImageTrackingModel.cpp b/mv_image/image/src/ImageTrackingModel.cpp new file mode 100644 index 0000000..e0a75c9 --- /dev/null +++ b/mv_image/image/src/ImageTrackingModel.cpp @@ -0,0 +1,365 @@ +/** + * 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 "ImageTrackingModel.h" + +#include + +#include "mv_private.h" +#include "mv_common.h" + +#include +#include + +namespace MediaVision +{ +namespace Image +{ + +ImageTrackingModel::ImageTrackingModel() : + m_recognitionObject(), + m_lastLocation(0), + m_state(Invalid), + m_recognitionThread(0) +{ + pthread_mutex_init(&m_globalGuard, NULL); + pthread_spin_init(&m_lastLocationGuard, PTHREAD_PROCESS_SHARED); + pthread_spin_init(&m_stateGuard, PTHREAD_PROCESS_SHARED); +} + +ImageTrackingModel::ImageTrackingModel(const ImageObject& recognitionObject) : + m_recognitionObject(recognitionObject), + m_lastLocation(0), + m_state(Invalid), + m_recognitionThread(0) +{ + if (!recognitionObject.isEmpty()) + { + m_state = Undetected; + } + pthread_mutex_init(&m_globalGuard, NULL); + pthread_spin_init(&m_lastLocationGuard, PTHREAD_PROCESS_SHARED); + pthread_spin_init(&m_stateGuard, PTHREAD_PROCESS_SHARED); +} + +ImageTrackingModel::ImageTrackingModel(const ImageTrackingModel& copy) : + m_recognitionThread(0) +{ + pthread_mutex_init(&m_globalGuard, NULL); + pthread_spin_init(&m_lastLocationGuard, PTHREAD_PROCESS_SHARED); + pthread_spin_init(&m_stateGuard, PTHREAD_PROCESS_SHARED); + + *this = copy; +} + +ImageTrackingModel::~ImageTrackingModel() +{ + if (m_recognitionThread) + { + pthread_join(m_recognitionThread, NULL); + } + + pthread_mutex_destroy(&m_globalGuard); + pthread_spin_destroy(&m_lastLocationGuard); + pthread_spin_destroy(&m_stateGuard); +} + +void ImageTrackingModel::setTarget(const ImageObject& target) +{ + pthread_mutex_lock(&m_globalGuard); + + pthread_spin_lock(&m_stateGuard); + m_state = target.isEmpty() ? Invalid : Undetected; + pthread_spin_unlock(&m_stateGuard); + + pthread_spin_lock(&m_lastLocationGuard); + m_lastLocation.clear(); + pthread_spin_unlock(&m_lastLocationGuard); + + LOGI("[%s] Target is set into tracking model.", __FUNCTION__); + + m_recognitionObject = target; + + pthread_mutex_unlock(&m_globalGuard); +} + +void ImageTrackingModel::refresh(void) +{ + pthread_mutex_lock(&m_globalGuard); + + pthread_spin_lock(&m_stateGuard); + m_state = m_recognitionObject.isEmpty() ? Invalid : Undetected; + pthread_spin_unlock(&m_stateGuard); + + pthread_spin_lock(&m_lastLocationGuard); + m_lastLocation.clear(); + pthread_spin_unlock(&m_lastLocationGuard); + + LOGI("[%s] Image tracking model is refreshed.", __FUNCTION__); + + pthread_mutex_unlock(&m_globalGuard); +} + +bool ImageTrackingModel::isValid() const +{ + bool result = false; + + pthread_spin_lock(&m_stateGuard); + result = (m_state != Invalid); + pthread_spin_unlock(&m_stateGuard); + + return result; +} + +ImageTrackingModel& ImageTrackingModel::operator=(const ImageTrackingModel& copy) +{ + if (this != ©) + { + pthread_mutex_t *higherMutex = &m_globalGuard; + pthread_mutex_t *lowerMutex = ©.m_globalGuard; + + if (higherMutex < lowerMutex) + { + std::swap(higherMutex, lowerMutex); + } + + pthread_mutex_lock(higherMutex); + pthread_mutex_lock(lowerMutex); + + m_recognitionObject = copy.m_recognitionObject; + + pthread_spin_lock(&m_lastLocationGuard); + m_lastLocation = copy.m_lastLocation; + pthread_spin_unlock(&m_lastLocationGuard); + + if (copy.m_state == InProcess) + { + pthread_spin_lock(&m_stateGuard); + m_state = m_recognitionObject.isEmpty() ? Invalid : Undetected; + pthread_spin_unlock(&m_stateGuard); + } + else + { + pthread_spin_lock(&m_stateGuard); + m_state = copy.m_state; + pthread_spin_unlock(&m_stateGuard); + } + + pthread_mutex_unlock(lowerMutex); + pthread_mutex_unlock(higherMutex); + } + + return *this; +} + +int ImageTrackingModel::save(const char *fileName) const +{ + std::string prefix_path = std::string(app_get_data_path()); + LOGD("prefix_path: %s", prefix_path.c_str()); + + std::string filePath; + filePath += prefix_path; + filePath += fileName; + + /* check the directory is available */ + std::string prefix_path_check = filePath.substr(0, filePath.find_last_of('/')); + if (access(prefix_path_check.c_str(),F_OK)) + { + LOGE("Can't save tracking model. Path[%s] doesn't existed.", prefix_path_check.c_str()); + + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + std::ofstream out; + out.open(filePath.c_str()); + + if (!out.is_open()) + { + LOGE("[%s] Can't create/open file.", __FUNCTION__); + return MEDIA_VISION_ERROR_PERMISSION_DENIED; + } + + out<<(*this); + + out.close(); + LOGI("[%s] Image tracking model is saved.", __FUNCTION__); + + return MEDIA_VISION_ERROR_NONE; +} + +int ImageTrackingModel::load(const char *fileName) +{ + /* find directory */ + std::string prefix_path = std::string(app_get_data_path()); + LOGD("prefix_path: %s", prefix_path.c_str()); + + std::string filePath; + filePath += prefix_path; + filePath += fileName; + + if (access(filePath.c_str(),F_OK)) + { + LOGE("Can't load tracking model. Path[%s] doesn't existed.", filePath.c_str()); + + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + std::ifstream in; + in.open(filePath.c_str()); + + if (!in.is_open()) + { + LOGE("[%s] Can't open file.", __FUNCTION__); + return MEDIA_VISION_ERROR_PERMISSION_DENIED; + } + + in>>(*this); + + if (!in.good()) + { + LOGE("[%s] Unexpected end of file.", __FUNCTION__); + return MEDIA_VISION_ERROR_PERMISSION_DENIED; + } + + in.close(); + LOGI("[%s] Image tracking model is loaded.", __FUNCTION__); + + return MEDIA_VISION_ERROR_NONE; +} + +bool ImageTrackingModel::isDetected() const +{ + bool result = false; + + pthread_spin_lock(&m_stateGuard); + result = (m_state == Tracked); + pthread_spin_unlock(&m_stateGuard); + + return result; +} + +std::vector ImageTrackingModel::getLastlocation() const +{ + std::vector result; + + pthread_spin_lock(&m_lastLocationGuard); + result = m_lastLocation; + pthread_spin_unlock(&m_lastLocationGuard); + + return result; +} + +#define STATE_UNSEEN_IO_ID 0 +#define STATE_VISIBLE_IO_ID 1 + +std::ostream& operator << (std::ostream& os, const ImageTrackingModel::State& state) +{ + if (ImageTrackingModel::Tracked == state) + { + os<> (std::istream& is, ImageTrackingModel::State& state) +{ + int stateId = -1; + + is>>stateId; + + if (STATE_VISIBLE_IO_ID == stateId) + { + state = ImageTrackingModel::Tracked; + } + else + { + state = ImageTrackingModel::Undetected; + } + + return is; +} + +#undef STATE_UNSEEN_IO_ID +#undef STATE_VISIBLE_IO_ID + +std::ostream& operator << (std::ostream& os, const ImageTrackingModel& obj) +{ + os<> (std::istream& is, ImageTrackingModel& obj) +{ +#define MEDIA_VISION_CHECK_IFSTREAM \ + if (!is.good()) \ + { \ + return is; \ + } + + ImageTrackingModel temporal; + + is>>obj.m_recognitionObject; + MEDIA_VISION_CHECK_IFSTREAM + + size_t lastLocationAmount = 0u; + is>>lastLocationAmount; + MEDIA_VISION_CHECK_IFSTREAM + + temporal.m_lastLocation.resize(lastLocationAmount); + for (size_t pointNum = 0u; pointNum < lastLocationAmount; ++pointNum) + { + is>>temporal.m_lastLocation[pointNum].x; + MEDIA_VISION_CHECK_IFSTREAM + is>>temporal.m_lastLocation[pointNum].y; + MEDIA_VISION_CHECK_IFSTREAM + } + + is>>temporal.m_state; + MEDIA_VISION_CHECK_IFSTREAM + + if (temporal.m_recognitionObject.isEmpty()) + { + temporal.m_state = ImageTrackingModel::Invalid; + } + + obj = temporal; + + return is; +} + +} /* Image */ +} /* MediaVision */ diff --git a/mv_image/image/src/mv_image_open.cpp b/mv_image/image/src/mv_image_open.cpp new file mode 100644 index 0000000..1d351a4 --- /dev/null +++ b/mv_image/image/src/mv_image_open.cpp @@ -0,0 +1,784 @@ +/** + * 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_image_open.h" + +#include "mv_private.h" +#include "mv_common_c.h" + +#include "ImageObject.h" +#include "ImageRecognizer.h" +#include "ImageTrackingModel.h" +#include "ImageTracker.h" + +#include + +namespace +{ + +const MediaVision::Image::FeaturesExtractingParams + defaultObjectFeaturesExtractingParams(1.2, 1000); + +const MediaVision::Image::FeaturesExtractingParams + defaultSceneFeaturesExtractingParams(1.2, 5000); + +const MediaVision::Image::RecognitionParams + defaultRecognitionParams(15, 0.33, 0.1); + +const MediaVision::Image::StabilizationParams + defaultStabilizationParams(3, 0.006, 2, 0.001); + +const MediaVision::Image::TrackingParams + defaultTrackingParams( + defaultSceneFeaturesExtractingParams, + defaultRecognitionParams, + defaultStabilizationParams, + 0.0); + +void extractTargetFeaturesExtractingParams( + mv_engine_config_h engine_cfg, + MediaVision::Image::FeaturesExtractingParams& featuresExtractingParams) +{ + mv_engine_config_h working_cfg = NULL; + + if (NULL == engine_cfg) + { + mv_create_engine_config(&working_cfg); + } + else + { + working_cfg = engine_cfg; + } + + featuresExtractingParams = defaultObjectFeaturesExtractingParams; + + mv_engine_config_get_double_attribute_c( + working_cfg, + "MV_IMAGE_RECOGNITION_OBJECT_SCALE_FACTOR", + &featuresExtractingParams.mScaleFactor); + + mv_engine_config_get_int_attribute_c( + working_cfg, + "MV_IMAGE_RECOGNITION_OBJECT_MAX_KEYPOINTS_NUM", + &featuresExtractingParams.mMaximumFeaturesNumber); + + if (NULL == engine_cfg) + { + mv_destroy_engine_config(working_cfg); + } +} + +void extractSceneFeaturesExtractingParams( + mv_engine_config_h engine_cfg, + MediaVision::Image::FeaturesExtractingParams& featuresExtractingParams) +{ + mv_engine_config_h working_cfg = NULL; + + if (NULL == engine_cfg) + { + mv_create_engine_config(&working_cfg); + } + else + { + working_cfg = engine_cfg; + } + + featuresExtractingParams = defaultSceneFeaturesExtractingParams; + + mv_engine_config_get_double_attribute_c( + working_cfg, + "MV_IMAGE_RECOGNITION_SCENE_SCALE_FACTOR", + &featuresExtractingParams.mScaleFactor); + + mv_engine_config_get_int_attribute_c( + working_cfg, + "MV_IMAGE_RECOGNITION_SCENE_MAX_KEYPOINTS_NUM", + &featuresExtractingParams.mMaximumFeaturesNumber); + + if (NULL == engine_cfg) + { + mv_destroy_engine_config(working_cfg); + } +} + +void extractRecognitionParams( + mv_engine_config_h engine_cfg, + MediaVision::Image::RecognitionParams& recognitionParams) +{ + mv_engine_config_h working_cfg = NULL; + + if (NULL == engine_cfg) + { + mv_create_engine_config(&working_cfg); + } + else + { + working_cfg = engine_cfg; + } + + recognitionParams = defaultRecognitionParams; + + mv_engine_config_get_int_attribute_c( + working_cfg, + "MV_IMAGE_RECOGNITION_MIN_MATCH_NUM", + &recognitionParams.mMinMatchesNumber); + + mv_engine_config_get_double_attribute_c( + working_cfg, + "MV_IMAGE_RECOGNITION_REQ_MATCH_PART", + &recognitionParams.mRequiredMatchesPart); + + mv_engine_config_get_double_attribute_c( + working_cfg, + "MV_IMAGE_RECOGNITION_TOLERANT_MATCH_PART_ERR", + &recognitionParams.mAllowableMatchesPartError); + + if (NULL == engine_cfg) + { + mv_destroy_engine_config(working_cfg); + } +} + +void extractStabilizationParams( + mv_engine_config_h engine_cfg, + MediaVision::Image::StabilizationParams& stabilizationParams) +{ + mv_engine_config_h working_cfg = NULL; + + if (NULL == engine_cfg) + { + mv_create_engine_config(&working_cfg); + } + else + { + working_cfg = engine_cfg; + } + + stabilizationParams = defaultStabilizationParams; + + bool useStabilization = true; + mv_engine_config_get_bool_attribute_c( + working_cfg, + "MV_IMAGE_TRACKING_USE_STABLIZATION", + &useStabilization); + + if (!useStabilization) + { + stabilizationParams.mHistoryAmount = 0; + if (NULL == engine_cfg) + { + mv_destroy_engine_config(working_cfg); + } + return; + } + + mv_engine_config_get_int_attribute_c( + working_cfg, + "MV_IMAGE_TRACKING_HISTORY_AMOUNT", + &stabilizationParams.mHistoryAmount); + + mv_engine_config_get_double_attribute_c( + working_cfg, + "MV_IMAGE_TRACKING_STABLIZATION_TOLERANT_SHIFT", + &stabilizationParams.mAllowableShift); + + mv_engine_config_get_double_attribute_c( + working_cfg, + "MV_IMAGE_TRACKING_STABLIZATION_SPEED", + &stabilizationParams.mStabilizationSpeed); + + mv_engine_config_get_double_attribute_c( + working_cfg, + "MV_IMAGE_TRACKING_STABLIZATION_ACCELERATION", + &stabilizationParams.mStabilizationAcceleration); + + if (NULL == engine_cfg) + { + mv_destroy_engine_config(working_cfg); + } +} + +void extractTrackingParams( + mv_engine_config_h engine_cfg, + MediaVision::Image::TrackingParams& trackingParams) +{ + mv_engine_config_h working_cfg = NULL; + + if (NULL == engine_cfg) + { + mv_create_engine_config(&working_cfg); + } + else + { + working_cfg = engine_cfg; + } + + trackingParams = defaultTrackingParams; + + extractSceneFeaturesExtractingParams( + working_cfg, + trackingParams.mFramesFeaturesExtractingParams); + + extractRecognitionParams( + working_cfg, + trackingParams.mRecognitionParams); + + extractStabilizationParams( + working_cfg, + trackingParams.mStabilizationParams); + + mv_engine_config_get_double_attribute_c( + working_cfg, + "MV_IMAGE_TRACKING_EXPECTED_OFFSET", + &trackingParams.mExpectedOffset); + + if (NULL == engine_cfg) + { + mv_destroy_engine_config(working_cfg); + } +} + +int convertSourceMV2GrayCV(mv_source_h mvSource, cv::Mat& cvSource) +{ + MEDIA_VISION_INSTANCE_CHECK(mvSource); + + int depth = CV_8U; // Default depth. 1 byte for channel. + unsigned int channelsNumber = 0u; + unsigned int width = 0u, height = 0u; + unsigned int bufferSize = 0u; + 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; +} + +} /* anonymous namespace */ + +int mv_image_recognize_open( + mv_source_h source, + const mv_image_object_h *image_objects, + int number_of_objects, + mv_engine_config_h engine_cfg, + mv_image_recognized_cb recognized_cb, + void *user_data) +{ + MEDIA_VISION_INSTANCE_CHECK(source); + MEDIA_VISION_NULL_ARG_CHECK(image_objects); + for (int objectNum = 0; objectNum < number_of_objects; ++objectNum) + { + MEDIA_VISION_INSTANCE_CHECK(image_objects[objectNum]); + } + MEDIA_VISION_NULL_ARG_CHECK(recognized_cb); + + cv::Mat scene; + MEDIA_VISION_ASSERT( + convertSourceMV2GrayCV(source, scene), + "Failed to convert mv_source."); + + MediaVision::Image::FeaturesExtractingParams featuresExtractingParams; + extractSceneFeaturesExtractingParams(engine_cfg, featuresExtractingParams); + + MediaVision::Image::RecognitionParams recognitionParams; + extractRecognitionParams(engine_cfg, recognitionParams); + + MediaVision::Image::ImageRecognizer recognizer(scene, + featuresExtractingParams); + + mv_quadrangle_s *resultLocations[number_of_objects]; + + for (int objectNum = 0; objectNum < number_of_objects; ++objectNum) + { + std::vector resultContour; + bool isRecognized = recognizer.recognize( + *((MediaVision::Image::ImageObject*)image_objects[objectNum]), + recognitionParams, resultContour); + if (isRecognized && (resultContour.size() == + MediaVision::Image::NumberOfQuadrangleCorners)) + { + resultLocations[objectNum] = new mv_quadrangle_s; + for (size_t pointNum = 0u; + pointNum < MediaVision::Image::NumberOfQuadrangleCorners; + ++pointNum) + { + resultLocations[objectNum]->points[pointNum].x = + resultContour[pointNum].x; + resultLocations[objectNum]->points[pointNum].y = + resultContour[pointNum].y; + } + } + else + { + resultLocations[objectNum] = NULL; + } + } + + recognized_cb( + source, + engine_cfg, + image_objects, + resultLocations, + number_of_objects, + user_data); + + for (int objectNum = 0; objectNum < number_of_objects; ++objectNum) + { + if (resultLocations[objectNum] != NULL) + { + delete resultLocations[objectNum]; + resultLocations[objectNum] = NULL; + } + } + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_image_track_open( + mv_source_h source, + mv_image_tracking_model_h image_tracking_model, + mv_engine_config_h engine_cfg, + mv_image_tracked_cb tracked_cb, + void *user_data) +{ + MEDIA_VISION_INSTANCE_CHECK(source); + MEDIA_VISION_INSTANCE_CHECK(image_tracking_model); + MEDIA_VISION_NULL_ARG_CHECK(tracked_cb); + + if (!((MediaVision::Image::ImageTrackingModel*)image_tracking_model)->isValid()) + { + LOGE("[%s] Image tracking model is invalid.", __FUNCTION__); + return MEDIA_VISION_ERROR_INVALID_DATA; + } + + MediaVision::Image::TrackingParams trackingParams; + extractTrackingParams(engine_cfg, trackingParams); + + cv::Mat frame; + MEDIA_VISION_ASSERT( + convertSourceMV2GrayCV(source, frame), + "Failed to convert mv_source."); + + MediaVision::Image::ImageTracker tracker(trackingParams); + + MediaVision::Image::ImageTrackingModel *trackingModel = + (MediaVision::Image::ImageTrackingModel*)image_tracking_model; + + tracker.track(frame, *trackingModel); + + std::vector resultContour = trackingModel->getLastlocation(); + + if (trackingModel->isDetected() && + MediaVision::Image::NumberOfQuadrangleCorners == resultContour.size()) + { + mv_quadrangle_s result; + for (size_t pointNum = 0u; + pointNum < MediaVision::Image::NumberOfQuadrangleCorners; + ++pointNum) + { + result.points[pointNum].x = resultContour[pointNum].x; + result.points[pointNum].y = resultContour[pointNum].y; + } + tracked_cb(source, image_tracking_model, engine_cfg, &result, user_data); + } + else + { + tracked_cb(source, image_tracking_model, engine_cfg, NULL, user_data); + } + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_image_object_create_open( + mv_image_object_h *image_object) +{ + MEDIA_VISION_NULL_ARG_CHECK(image_object); + + (*image_object) = (mv_image_object_h)new (std::nothrow)MediaVision::Image::ImageObject(); + if (*image_object == NULL) + { + return MEDIA_VISION_ERROR_OUT_OF_MEMORY; + } + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_image_object_destroy_open( + mv_image_object_h image_object) +{ + MEDIA_VISION_INSTANCE_CHECK(image_object); + + delete (MediaVision::Image::ImageObject*)image_object; + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_image_object_fill_open( + mv_image_object_h image_object, + mv_engine_config_h engine_cfg, + mv_source_h source, + mv_rectangle_s *location) +{ + MEDIA_VISION_INSTANCE_CHECK(image_object); + MEDIA_VISION_INSTANCE_CHECK(source); + + cv::Mat image; + MEDIA_VISION_ASSERT( + convertSourceMV2GrayCV(source, image), + "Failed to convert mv_source."); + + MediaVision::Image::FeaturesExtractingParams featuresExtractingParams; + extractTargetFeaturesExtractingParams(engine_cfg, featuresExtractingParams); + + if (NULL == location) + { + ((MediaVision::Image::ImageObject*)image_object)->fill(image, + featuresExtractingParams); + } + else + { + if (!((MediaVision::Image::ImageObject*)image_object)->fill(image, + cv::Rect(location->point.x, location->point.y, + location->width, location->height), + featuresExtractingParams)) + { + // Wrong ROI (bounding box) + LOGE("[%s] Wrong ROI.", __FUNCTION__); + return MEDIA_VISION_ERROR_INVALID_DATA; + } + } + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_image_object_get_recognition_rate_open( + mv_image_object_h image_object, + double *recognition_rate) +{ + MEDIA_VISION_INSTANCE_CHECK(image_object); + MEDIA_VISION_NULL_ARG_CHECK(recognition_rate); + + (*recognition_rate) = + ((MediaVision::Image::ImageObject*)image_object)->getRecognitionRate(); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_image_object_set_label_open( + mv_image_object_h image_object, + int label) +{ + MEDIA_VISION_INSTANCE_CHECK(image_object); + + ((MediaVision::Image::ImageObject*)image_object)->setLabel(label); + + return MEDIA_VISION_ERROR_NONE; +} +int mv_image_object_get_label_open( + mv_image_object_h image_object, + int *label) +{ + MEDIA_VISION_INSTANCE_CHECK(image_object); + MEDIA_VISION_NULL_ARG_CHECK(label); + + if (!((MediaVision::Image::ImageObject*)image_object)->getLabel(*label)) + { + LOGW("[%s] Image object haven't a label.", __FUNCTION__); + return MEDIA_VISION_ERROR_NO_DATA; + } + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_image_object_clone_open( + mv_image_object_h src, + mv_image_object_h *dst) +{ + MEDIA_VISION_INSTANCE_CHECK(src); + MEDIA_VISION_NULL_ARG_CHECK(dst); + + (*dst) = (mv_image_object_h)new (std::nothrow)MediaVision::Image::ImageObject(); + if (*dst == NULL) + { + return MEDIA_VISION_ERROR_OUT_OF_MEMORY; + } + + *(MediaVision::Image::ImageObject*)(*dst) = + *(MediaVision::Image::ImageObject*)src; + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_image_object_save_open( + const char *file_name, mv_image_object_h image_object) +{ + MEDIA_VISION_INSTANCE_CHECK(image_object); + + if (file_name == NULL) + { + LOGE("File name is NULL. The file name has to be specified"); + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + int ret = ((MediaVision::Image::ImageObject*)image_object)->save(file_name); + if (ret != MEDIA_VISION_ERROR_NONE) + { + LOGE("Fail to save image object."); + return ret; + } + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_image_object_load_open( + const char *file_name, mv_image_object_h *image_object) +{ + MEDIA_VISION_NULL_ARG_CHECK(image_object); + + if (file_name == NULL) + { + LOGE("File name is NULL. The file name has to be specified"); + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + (*image_object) = (mv_image_object_h)new (std::nothrow)MediaVision::Image::ImageObject(); + if (*image_object == NULL) + { + return MEDIA_VISION_ERROR_OUT_OF_MEMORY; + } + + int ret = ((MediaVision::Image::ImageObject*)(*image_object))->load(file_name); + if (ret != MEDIA_VISION_ERROR_NONE) + { + LOGE("Fail to save image object."); + return ret; + } + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_image_tracking_model_create_open( + mv_image_tracking_model_h *image_tracking_model) +{ + MEDIA_VISION_NULL_ARG_CHECK(image_tracking_model); + + (*image_tracking_model) = (mv_image_tracking_model_h) + new (std::nothrow)MediaVision::Image::ImageTrackingModel(); + if (*image_tracking_model == NULL) + { + return MEDIA_VISION_ERROR_OUT_OF_MEMORY; + } + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_image_tracking_model_set_target_open( + mv_image_object_h image_object, + mv_image_tracking_model_h image_tracking_model) +{ + MEDIA_VISION_INSTANCE_CHECK(image_tracking_model); + MEDIA_VISION_INSTANCE_CHECK(image_object); + + if (((MediaVision::Image::ImageObject*)image_object)->isEmpty()) + { + LOGE("[%s] Target is empty and can't be set as target of tracking" + "model.", __FUNCTION__); + return MEDIA_VISION_ERROR_INVALID_DATA; + } + + ((MediaVision::Image::ImageTrackingModel*)image_tracking_model)->setTarget( + *(MediaVision::Image::ImageObject*)image_object); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_image_tracking_model_destroy_open( + mv_image_tracking_model_h image_tracking_model) +{ + MEDIA_VISION_INSTANCE_CHECK(image_tracking_model); + + delete (MediaVision::Image::ImageTrackingModel*)image_tracking_model; + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_image_tracking_model_refresh_open( + mv_image_tracking_model_h image_tracking_model, + mv_engine_config_h /*engine_cfg*/) +{ + MEDIA_VISION_INSTANCE_CHECK(image_tracking_model); + + if (!((MediaVision::Image::ImageTrackingModel*)image_tracking_model)->isValid()) + { + LOGE("[%s] Image tracking model is invalid.", __FUNCTION__); + return MEDIA_VISION_ERROR_INVALID_DATA; + } + + ((MediaVision::Image::ImageTrackingModel*)image_tracking_model)->refresh(); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_image_tracking_model_clone_open( + mv_image_tracking_model_h src, + mv_image_tracking_model_h *dst) +{ + MEDIA_VISION_INSTANCE_CHECK(src); + MEDIA_VISION_NULL_ARG_CHECK(dst); + + (*dst) = (mv_image_tracking_model_h)new (std::nothrow)MediaVision::Image::ImageTrackingModel(); + if (*dst == NULL) + { + return MEDIA_VISION_ERROR_OUT_OF_MEMORY; + } + + *(MediaVision::Image::ImageObject*)(*dst) = *(MediaVision::Image::ImageObject*)src; + + LOGD("Image tracking model has been successfully cloned"); + return MEDIA_VISION_ERROR_NONE; +} + +int mv_image_tracking_model_save_open( + const char *file_name, mv_image_tracking_model_h image_tracking_model) +{ + MEDIA_VISION_INSTANCE_CHECK(image_tracking_model); + + if (file_name == NULL) + { + LOGE("File name is NULL. The file name has to be specified"); + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + int ret = ((MediaVision::Image::ImageTrackingModel*)image_tracking_model)->save(file_name); + if (ret != MEDIA_VISION_ERROR_NONE) + { + LOGE("Failed to save image tracking model"); + return ret; + } + + LOGD("Image tracking model has been successfully saved"); + return MEDIA_VISION_ERROR_NONE; +} + +int mv_image_tracking_model_load_open( + const char *file_name, mv_image_tracking_model_h *image_tracking_model) +{ + MEDIA_VISION_NULL_ARG_CHECK(image_tracking_model); + + if (file_name == NULL) + { + LOGE("File path is NULL. The file name has to be specified"); + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + (*image_tracking_model) = + (mv_image_tracking_model_h) new (std::nothrow)MediaVision::Image::ImageTrackingModel(); + + if (*image_tracking_model == NULL) + { + return MEDIA_VISION_ERROR_OUT_OF_MEMORY; + } + + int ret = ((MediaVision::Image::ImageTrackingModel*)(*image_tracking_model))->load(file_name); + if (ret != MEDIA_VISION_ERROR_NONE) + { + LOGE("Failed to load image tracking model"); + return ret; + } + + LOGD("Image tracking model has been successfully loaded"); + return MEDIA_VISION_ERROR_NONE; +} diff --git a/mv_image/image_lic/CMakeLists.txt b/mv_image/image_lic/CMakeLists.txt new file mode 100644 index 0000000..b38e47b --- /dev/null +++ b/mv_image/image_lic/CMakeLists.txt @@ -0,0 +1,25 @@ +project(${MV_IMAGE_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_IMAGE_INC_LIST "${PROJECT_SOURCE_DIR}/include/*.h") +file(GLOB MV_IMAGE_SRC_LIST "${PROJECT_SOURCE_DIR}/src/*.c") + +if(FORCED_STATIC_BUILD) + add_library(${PROJECT_NAME} STATIC ${MV_IMAGE_INC_LIST} ${MV_IMAGE_SRC_LIST}) +else() + add_library(${PROJECT_NAME} SHARED ${MV_IMAGE_INC_LIST} ${MV_IMAGE_SRC_LIST}) +endif() + +target_link_libraries(${PROJECT_NAME} ${MV_COMMON_LIB_NAME}) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}) diff --git a/mv_image/image_lic/include/mv_image_lic.h b/mv_image/image_lic/include/mv_image_lic.h new file mode 100644 index 0000000..29e1c1d --- /dev/null +++ b/mv_image/image_lic/include/mv_image_lic.h @@ -0,0 +1,564 @@ +/** + * 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_IMAGE_LIC_H__ +#define __TIZEN_MEDIAVISION_IMAGE_LIC_H__ + +#include "mv_image.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file mv_image_lic.h + * @brief This file contains the Media Vision Image API for the licensed module. + * Working with images (like planar objects): recognition and tracking. + */ + +/****************************/ +/* Image object recognition */ +/****************************/ + +/** + * @brief Recognizes the given image objects on the source image. + * @details Use this function to launch image recognition algorithm configured + * by @a engine_conf configuration. + * + * @since_tizen 3.0 + * @param [in] source The handle to the source image on which image + * objects will be recognized + * @param [in] image_objects The set of handles to the image objects which + * will be processed as targets of recognition + * @param [in] number_of_objects The number of image objects + * @param [in] engine_cfg The handle to the configuration of engine + * which will be used for recognition. If NULL, + * then default settings will be used. + * @param [in] recognized_cb The callback which will be called in order to + * process recognition result + * @param [in] user_data The user data to be passed to the + * @a recognized_cb + * @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_FORMAT Source colorspace + * isn't supported + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create a set of image objects using @ref mv_image_object_create_lic() + * for each of them and construct (fill / load / clone) them on images that + * will be recognized + * @pre Create a source handle by calling @ref mv_create_source() and fill + * by the image for which recognition will be performed + * @post @a mv_image_recognized_cb will be called to process recognition result + * @post Release source image by using @ref mv_destroy_source() + * @post Release image objects by using @ref mv_image_object_destroy_lic() for + * each handle from @a image_objects set + * + * @see mv_image_recognized_cb + * @see mv_source_h + * @see mv_create_source() + * @see mv_destroy_source() + * @see mv_image_object_h + * @see mv_image_object_create_lic() + * @see mv_image_object_destroy_lic() + * @see mv_engine_config_h + */ +int mv_image_recognize_lic( + mv_source_h source, + const mv_image_object_h *image_objects, + int number_of_objects, + mv_engine_config_h engine_cfg, + mv_image_recognized_cb recognized_cb, + void *user_data); + +/*************************/ +/* Image object tracking */ +/*************************/ + +/** + * @brief Tracks the given image tracking model on the current frame + * @details Image tracking on a sequence of frames assumes calling this + * function for each frame in the correct order. + * @a tracked_cb will be called for result processing. + * + * @since_tizen 3.0 + * @remarks Tracking algorithm is usually using for recognition of image object + * on the sequence of images that are organized by time. For example, + * it may be the sequence of frames from a video stream. + * @remarks If object is lost during the tracking, system tries to find it + * further for the following frames. Therefore, tracking will be + * recovered when object appears again. + * @remarks Previous calls of @ref mv_image_track_lic() for this + * @a image_tracking_model will affect on current call + * @param [in] source The handle to the current image of + * sequence where image tracking model + * will be tracked + * @param [in,out] image_tracking_model The handle to the image tracking model + * which processed as target of tracking + * @param [in] engine_cfg The handle to the configuration of + * engine which will be used for tracking. + * If NULL, then default settings will be + * used. + * @param [in] tracked_cb The callback which will receive + * tracking results + * @param [in] user_data The user data to be passed to the + * @a tracked_cb + * @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_FORMAT Source colorspace + * isn't supported + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create image tracking model by calling + * @ref mv_image_tracking_model_create_lic() and set target by calling + * @ref mv_image_tracking_model_set_target_lic() + * @pre Create a source images by calling @ref mv_create_source() for each of + * them and construct them based on sequence of images for which will be + * held image tracking + * @post @a tracked_cb will be called to process tracking result + * @post Release image tracking model by using + * @ref mv_image_tracking_model_destroy_lic() + * + * @see mv_image_tracked_cb + * @see mv_source_h + * @see image_tracking_model_h + * @see mv_image_tracking_model_create_lic() + * @see mv_image_tracking_model_set_target_lic() + * @see mv_image_tracking_model_destroy_lic() + */ +int mv_image_track_lic( + mv_source_h source, + mv_image_tracking_model_h image_tracking_model, + mv_engine_config_h engine_cfg, + mv_image_tracked_cb tracked_cb, + void *user_data); + +/**************************/ +/* Image object behaviour */ +/**************************/ + +/** + * @brief Creates an image object. + * + * @since_tizen 3.0 + * @param [out] image_object A new handle to the image object + * @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 Release image object by using mv_image_object_destroy_lic() + * + * @see mv_image_object_destroy_lic() + */ +int mv_image_object_create_lic( + mv_image_object_h *image_object); + +/** + * @brief Destroys the image object. + * + * @since_tizen 3.0 + * @param [in] image_object The handle to the image object 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_image_object_create_lic() + */ +int mv_image_object_destroy_lic( + mv_image_object_h image_object); + +/** + * @brief Fills the image object. + * @details Extracts data from @a source image which will be needed for + * recognition of depicted object in @a location. + * + * @since_tizen 3.0 + * @remarks After filling the image object it can be evaluated by + * @ref mv_image_object_get_recognition_rate_lic(). If recognition rate + * is too low, try to use another image of object or change + * configuration parameters (see @ref mv_engine_config_h) and construct + * the image object again. + * @param [in,out] image_object The handle to the image object which will be + * filled and can be recognized in future + * @param [in] engine_cfg The handle to the configuration of engine + * which will be used for extract recognition + * data from @a source. If NULL, then default + * settings will be used. + * @param [in] source The source image where image object is depicted + * @param [in] location The pointer to location of the image object + * on the source image, or NULL if the object is + * shown in full + * @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_FORMAT Source colorspace + * isn't supported + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create image object by using @ref mv_image_object_create_lic() + * @post Release image object by using @ref mv_image_object_destroy_lic() + * + * @see mv_image_object_h + * @see mv_image_object_create_lic() + * @see mv_image_object_get_recognition_rate_lic() + * @see mv_image_recognize_lic() + * @see mv_image_object_destroy_lic() + * @see mv_engine_config_h + */ +int mv_image_object_fill_lic( + mv_image_object_h image_object, + mv_engine_config_h engine_cfg, + mv_source_h source, + mv_rectangle_s *location); + +/** + * @brief Gets a value that determines how well an image object can be recognized. + * @details Recognition rate determines how well an image object can be + * recognized. This value can be from 0 to 1. If the recognition rate + * is 0 object can not be recognized and the bigger it is the more + * likely to recognize the object. + * + * @since_tizen 3.0 + * @remarks If recognition rate is too low, try to use another image of object + * or change some configuration parameters (see @ref mv_engine_config_h) + * and fill the image object again + * (see @ref mv_image_object_fill_lic()). + * @param [in] image_object The handle to the image object which will be + * evaluated by this function + * @param [out] recognition_rate A value that determines how well an image + * object can be recognized, if 0 then object + * can not be recognized + * @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 Create image object by using @ref mv_image_object_create_lic() + * @post Release image object by using @ref mv_image_object_destroy_lic() + * + * @see mv_image_object_h + * @see mv_image_object_create_lic() + * @see mv_image_object_fill_lic() + * @see mv_image_object_destroy_lic() + * @see mv_engine_config_h + */ +int mv_image_object_get_recognition_rate_lic( + mv_image_object_h image_object, + double *recognition_rate); + +/** + * @brief Sets a label for the image object. + * + * @since_tizen 3.0 + * @param [in] image_object The handle to the image object for which the label + * will be assigned + * @param [in] label The label which will be assigned to the image + * object + * @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 Create image object by using @ref mv_image_object_create_lic() + * @post Label could be received by using + * @ref mv_image_object_get_label_lic() + * @post Release image object by using @ref mv_image_object_destroy_lic() + * + * @see mv_image_object_get_label_lic() + * @see mv_image_object_h + * @see mv_image_object_create_lic() + * @see mv_image_object_destroy_lic() + */ +int mv_image_object_set_label_lic( + mv_image_object_h image_object, + int label); + +/** + * @brief Gets a label of image object. + * + * @since_tizen 3.0 + * @remarks If @a image_object have not a label, this function return + * MEDIA_VISION_ERROR_NO_DATA value. + * @param [in] image_object The handle to the image object from which a + * label will be received + * @param [out] label The label of image object + * @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_NO_DATA Image object hasn't label + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create image object by using @ref mv_image_object_create_lic() + * @pre Set label for the image object by using + * @ref mv_image_object_set_label_lic() + * @post Release image object by using @ref mv_image_object_destroy_lic() + * + * @see mv_image_object_set_label_lic() + * @see mv_image_object_h + * @see mv_image_object_create_lic() + * @see mv_image_object_destroy_lic() + */ +int mv_image_object_get_label_lic( + mv_image_object_h image_object, + int *label); + +/** + * @brief Clones the image object. + * + * @since_tizen 3.0 + * @param [in] src The handle to the source image object + * @param [out] dst The handle to the destination image object + * @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 Create image object handles by calling mv_image_object_create_lic() + * + * @see mv_image_object_create_lic() + * @see mv_image_object_destroy_lic() + */ +int mv_image_object_clone_lic( + mv_image_object_h src, + mv_image_object_h *dst); + +/** + * @brief Saves the image object. + * + * @since_tizen 3.0 + * @remarks @a image_object is saved to the application's data directory. + * @param [in] file_name Name of the file to save the image object + * @param [in] image_object The handle to the image object which will be saved + * @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_image_object_create_lic() + * @see mv_image_object_load_lic() + * @see mv_image_object_destroy_lic() + */ +int mv_image_object_save_lic( + const char *file_name, mv_image_object_h image_object); + +/** + * @brief Loads an image object from the file. + * + * @since_tizen 3.0 + * @remarks @a image_object is loaded from the application's data directory. + * @a image_object must be destroyed using + * @ref mv_image_object_destroy(). + * @param [in] file_name Name of file to load the image object + * @param [out] image_object The handle to the image object which will be + * filled + * @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 Image object can be preliminary saved with mv_image_object_save() + * function + * + * @see mv_image_object_save_lic() + * @see mv_image_object_destroy_lic() + */ +int mv_image_object_load_lic( + const char *file_name, mv_image_object_h image_object); + +/**********************************/ +/* Image tracking model behaviour */ +/**********************************/ + +/** + * @brief Creates an image tracking model. + * + * @since_tizen 3.0 + * @param [out] image_tracking_model A new handle to the image tracking model + * @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 Release image tracking model by using mv_image_tracking_model_destroy_lic() + * + * @see mv_image_tracking_model_destroy_lic() + */ +int mv_image_tracking_model_create_lic( + mv_image_tracking_model_h *image_tracking_model); + +/** + * @brief Sets target of image tracking model. + * @details Sets image object which will be tracked by using tracking + * functionality with @a image_tracking_model. + * + * @since_tizen 3.0 + * @param [in] image_object Image object which will be set + * as target for tracking + * @param [in] image_tracking_model Handle to the image tracking model + * for which will be set a new target + * @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 Create image tracking model by calling + * @ref mv_image_tracking_model_create_lic() + * @pre Create an image object using @ref mv_image_object_create_lic() and + * construct (fill / load / clone) it on image that will be tracking + * @post Release image object by using @ref mv_image_object_destroy_lic() + * @post Release image tracking model by using + * @ref mv_image_tracking_model_destroy_lic() + * + * @see mv_image_object_h + * @see mv_image_tracking_model_h + * @see mv_image_object_create_lic() + * @see mv_image_object_destroy_lic() + * @see mv_image_tracking_model_create_lic() + * @see mv_image_track_lic() + * @see mv_image_tracking_model_destroy_lic() + */ +int mv_image_tracking_model_set_target_lic( + mv_image_object_h image_object, + mv_image_tracking_model_h image_tracking_model); + +/** + * @brief Destroys the image tracking model. + * + * @since_tizen 3.0 + * @param [in] image_tracking_model The handle to the image tracking model + * 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 + * + * @pre Create image tracking model by using mv_image_tracking_model_create() + * + * @see mv_image_tracking_model_create_lic() + */ +int mv_image_tracking_model_destroy_lic( + mv_image_tracking_model_h image_tracking_model); + +/** + * @brief Refreshes the state of image tracking model. + * @details Clears moving history and change state to undetected. This function + * is usually called each time before tracking is started for the new + * sequence of sources which is not the direct continuation of the + * sequence for which tracking has been performed before. Tracking + * algorithm will try to find image by itself. + * + * @since_tizen 3.0 + * @param [in] image_tracking_model The handle to the image tracking model + * which will be refreshed + * @param [in] engine_cfg The handle to the configuration of + * engine which will be used. If NULL, + * then default settings will be used. + * @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 Create image tracking model by calling + * @ref mv_image_tracking_model_create_lic() + * @post Release image tracking model by using + * @ref mv_image_tracking_model_destroy_lic() + * + * @see mv_image_tracking_model_h + * @see mv_image_tracking_model_create_lic() + * @see mv_image_track_lic() + * @see mv_image_tracking_model_destroy_lic() + */ +int mv_image_tracking_model_refresh_lic( + mv_image_tracking_model_h image_tracking_model, + mv_engine_config_h engine_cfg); + +/** + * @brief Clones the image tracking model. + * + * @since_tizen 3.0 + * @param [in] src The handle to the source image tracking model + * @param [out] dst The handle to the destination image tracking model + * @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_image_tracking_model_create_lic() + * @see mv_image_tracking_model_destroy_lic() + */ +int mv_image_tracking_model_clone_lic( + mv_image_tracking_model_h src, + mv_image_tracking_model_h *dst); + +/** + * @brief Saves the image tracking model. + * + * @since_tizen 3.0 + * @remarks @a image_tracking_model is saved to the application's data directory. + * @param [in] file_name Name of file to save the model + * @param [in] image_tracking_model The handle to the image tracking model + * to be saved + * @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_PERMISSION_DENIED Not permitted + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create image tracking model handle by calling + * mv_image_tracking_model_create() + * @post Saved model can be loaded later by calling + * mv_image_tracking_model_load() function + + * @see mv_image_tracking_model_create_lic() + * @see mv_image_tracking_model_load_lic() + * @see mv_image_tracking_model_destroy_lic() + */ +int mv_image_tracking_model_save_lic( + const char *file_name, mv_image_tracking_model_h image_tracking_model); + +/** + * @brief Loads an image tracking model from the file. + * + * @since_tizen 3.0 + * @remarks @a image_tracking_model is loaded from the application's data directory. + * @a image_tracking_model must be destroyed using + * @ref mv_image_tracking_model_destroy. + * @param [in] file_name Name of file to load model + * @param [out] image_tracking_model The handle to the image tracking + * model to be filled + * @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 Image tracking model handle can be preliminary saved with + * mv_image_tracking_model_save() function + * + * @see mv_image_tracking_model_save_lic() + * @see mv_image_tracking_model_destroy_lic() + */ +int mv_image_tracking_model_load_lic( + const char *file_name, mv_image_tracking_model_h *image_tracking_model); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIAVISION_IMAGE_LIC_H__ */ diff --git a/mv_image/image_lic/src/mv_image_lic.c b/mv_image/image_lic/src/mv_image_lic.c new file mode 100644 index 0000000..356e563 --- /dev/null +++ b/mv_image/image_lic/src/mv_image_lic.c @@ -0,0 +1,150 @@ +/** + * 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_image_lic.h" + +int mv_image_recognize_lic( + mv_source_h source, + const mv_image_object_h *image_objects, + int number_of_objects, + mv_engine_config_h engine_cfg, + mv_image_recognized_cb recognized_cb, + void *user_data) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_image_track_lic( + mv_source_h source, + mv_image_tracking_model_h image_tracking_model, + mv_engine_config_h engine_cfg, + mv_image_tracked_cb tracked_cb, + void *user_data) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_image_object_create_lic( + mv_image_object_h *image_object) + +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + + +int mv_image_object_destroy_lic( + mv_image_object_h image_object) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_image_object_fill_lic( + mv_image_object_h image_object, + mv_engine_config_h engine_cfg, + mv_source_h source, + mv_rectangle_s *location) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_image_object_get_recognition_rate_lic( + mv_image_object_h image_object, + double *recognition_rate) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_image_object_set_label_lic( + mv_image_object_h image_object, + int label) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_image_object_get_label_lic( + mv_image_object_h image_object, + int *label) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_image_object_clone_lic( + mv_image_object_h src, + mv_image_object_h *dst) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_image_object_save_lic( + mv_image_object_h image_object, + const char *file_name) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_image_object_load_lic( + mv_image_object_h image_object, + const char *file_name) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_image_tracking_model_create_lic( + mv_image_tracking_model_h *image_tracking_model) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_image_tracking_model_set_target_lic( + mv_image_object_h image_object, + mv_image_tracking_model_h image_tracking_model) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_image_tracking_model_destroy_lic( + mv_image_tracking_model_h image_tracking_model) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_image_tracking_model_refresh_lic( + mv_image_tracking_model_h image_tracking_model, + mv_engine_config_h engine_cfg) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_image_tracking_model_clone_lic( + mv_image_tracking_model_h src, + mv_image_tracking_model_h *dst) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_image_tracking_model_save_lic( + mv_image_tracking_model_h image_tracking_model, + const char *file_name) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int mv_image_tracking_model_load_lic( + mv_image_tracking_model_h image_tracking_model, + const char *file_name) +{ + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} diff --git a/packaging/capi-media-vision.spec b/packaging/capi-media-vision.spec new file mode 100644 index 0000000..a786d8e --- /dev/null +++ b/packaging/capi-media-vision.spec @@ -0,0 +1,82 @@ +Name: capi-media-vision +Summary: Media Vision library for Tizen Native API +Version: 0.2.1 +Release: 0 +Group: Multimedia/Framework +License: Apache-2.0 and BSD-2.0 +Source0: %{name}-%{version}.tar.gz +BuildRequires: cmake +BuildRequires: pkgconfig(capi-media-tool) +BuildRequires: pkgconfig(capi-appfw-application) +BuildRequires: pkgconfig(libtbm) +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(capi-system-info) +BuildRequires: pkgconfig(opencv) +BuildRequires: pkgconfig(zbar) +BuildRequires: pkgconfig(glib-2.0) +# Change to the pkgconfig(zint) after zint package refactor +BuildRequires: zint +BuildRequires: zint-devel +BuildRequires: libjson +BuildRequires: libjson-devel +BuildRequires: dlogutil +BuildRequires: libjpeg-turbo +BuildRequires: libjpeg-turbo-devel +BuildRequires: pkgconfig(libavcodec) +BuildRequires: pkgconfig(libavformat) +BuildRequires: pkgconfig(libswscale) +BuildRequires: libavutil-devel +BuildRequires: pkgconfig(gstreamer-1.0) +BuildRequires: pkgconfig(gstreamer-base-1.0) +BuildRequires: pkgconfig(gstreamer-app-1.0) + +%description +Media Vision library for Tizen Native API. Includes barcode detecting, barcode generating, face and image modules. + +%package devel +Summary: Multimedia Vision Library (DEV) +Group: Multimedia/Framework +Requires: %{name} = %{version}-%{release} + +%description devel +Media Vision library for Tizen Native API (DEV). Includes barcode detecting, barcode generating, face and image modules. + +%prep +%setup -q + +%build +%if 0%{?sec_build_binary_debug_enable} +export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE" +export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE" +export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE" +%endif +MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'` +%cmake . -DFULLVER=%{version} -DMAJORVER=${MAJORVER} + +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +mkdir -p %{buildroot}/usr/share/license/ +mkdir -p %{buildroot}/usr/share/config/%{name} +cp LICENSE.APLv2 %{buildroot}/usr/share/license/%{name} +cp media-vision-config.json %{buildroot}/usr/share/config/%{name}/ + +%make_install + +%post -p /sbin/ldconfig +%postun -p /sbin/ldconfig + +%files +%manifest capi-media-vision.manifest +%{_datadir}/license/%{name} +%{_datadir}/config/%{name}/media-vision-config.json +%{_libdir}/libcapi-media-vision.so.* +%{_libdir}/libmv*.so + +%files devel +#%{_datadir}/config/%{name}/media-vision-config.json +%{_includedir}/media/*.h +%{_libdir}/pkgconfig/*.pc +%{_libdir}/lib%{name}.so +/opt/usr/devel/media/testsuites/* diff --git a/src/mv_barcode.c b/src/mv_barcode.c new file mode 100644 index 0000000..5d323fe --- /dev/null +++ b/src/mv_barcode.c @@ -0,0 +1,252 @@ +/** + * 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 + +#include "mv_private.h" +#include "mv_barcode_detect.h" +#include "mv_barcode_generate.h" + +#ifdef MEDIA_VISION_BARCODE_DETECTOR_LICENSE_PORT + +/* Include headers of licensed barcode detect module here. */ +#include "mv_barcode_detect_lic.h" + +#else + +/* Include headers of open barcode detect module here. */ +#include "mv_barcode_detect_open.h" + +#endif /* MEDIA_VISION_BARCODE_DETECTOR_LICENSE_PORT */ + +#ifdef MEDIA_VISION_BARCODE_GENERATOR_LICENSE_PORT + +/* Include headers of licensed barcode generate module here. */ +#include "mv_barcode_generate_lic.h" + +#else + +/* Include headers of open barcode generate module here. */ +#include "mv_barcode_generate_open.h" + +#endif /* MEDIA_VISION_BARCODE_GENERATOR_LICENSE_PORT */ + +/** + * @file mv_barcode.c + * @brief This file contains the porting layer for Media Vision barcode module. + */ + +int mv_barcode_detect( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s roi, + mv_barcode_detected_cb detect_cb, + void *user_data) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_barcode_detect_check_system_info_feature_supported()); + MEDIA_VISION_INSTANCE_CHECK(source); + MEDIA_VISION_NULL_ARG_CHECK(detect_cb); + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = MEDIA_VISION_ERROR_NONE; + unsigned int src_w = 0; + unsigned int src_h = 0; + + ret = mv_source_get_width(source, &src_w); + if (ret != MEDIA_VISION_ERROR_NONE) + { + LOGE("mv_source_get_width fail"); + return ret; + } + + ret = mv_source_get_height(source, &src_h); + if (ret != MEDIA_VISION_ERROR_NONE) + { + LOGE("mv_source_get_height fail"); + return ret; + } + + if (roi.point.x < 0 || roi.point.y < 0 || + (roi.point.x + roi.width) > src_w || + (roi.point.y + roi.height) > src_h) + { + LOGE("roi is out of area on source"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + +#ifdef MEDIA_VISION_BARCODE_DETECTOR_LICENSE_PORT + + /* Use licensed barcode detect functionality here. */ + ret = mv_barcode_detect_lic( + source, engine_cfg, roi, detect_cb, user_data); + +#else + + /* Use open barcode detect functionality here. */ + ret = mv_barcode_detect_open( + source, engine_cfg, roi, detect_cb, user_data); + +#endif /* MEDIA_VISION_BARCODE_DETECTOR_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_barcode_generate_source( + mv_engine_config_h engine_cfg, + const char *message, + mv_barcode_type_e type, + mv_barcode_qr_mode_e qr_enc_mode, + mv_barcode_qr_ecc_e qr_ecc, + int qr_version, + mv_source_h image) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_barcode_generate_check_system_info_feature_supported()); + MEDIA_VISION_NULL_ARG_CHECK(message); + MEDIA_VISION_INSTANCE_CHECK(image); + + MEDIA_VISION_FUNCTION_ENTER(); + + if (type < MV_BARCODE_QR || + type >= MV_BARCODE_UNDEFINED) + { + LOGE("Not supported barcode type [%d]", type); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (type == MV_BARCODE_QR) + { + if (qr_enc_mode < MV_BARCODE_QR_MODE_NUMERIC || + qr_enc_mode >= MV_BARCODE_QR_MODE_UNAVAILABLE) + { + LOGE("Not supported QR encoding mode[%d]", qr_enc_mode); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (qr_ecc < MV_BARCODE_QR_ECC_LOW || + qr_ecc >= MV_BARCODE_QR_ECC_UNAVAILABLE) + { + LOGE("Not supported QR ECC level [%d]", qr_ecc); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (qr_version < 1 || qr_version > 40) + { + LOGE("Not supported QR version [%d]", qr_version); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + } + +#ifdef MEDIA_VISION_BARCODE_GENERATOR_LICENSE_PORT + + /* Use licensed barcode generate functionality here. */ + int ret = mv_barcode_generate_source_lic( + engine_cfg, message, type, qr_enc_mode, qr_ecc, qr_version, + image); + +#else + + /* Use open barcode generate functionality here. */ + int ret = mv_barcode_generate_source_open( + engine_cfg, message, type, qr_enc_mode, qr_ecc, qr_version, + image); + +#endif /* MEDIA_VISION_BARCODE_GENERATOR_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_barcode_generate_image( + mv_engine_config_h engine_cfg, + const char *message, + int image_width, + int image_height, + mv_barcode_type_e type, + mv_barcode_qr_mode_e qr_enc_mode, + mv_barcode_qr_ecc_e qr_ecc, + int qr_version, + const char *image_path, + mv_barcode_image_format_e image_format) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_barcode_generate_check_system_info_feature_supported()); + MEDIA_VISION_NULL_ARG_CHECK(message); + + MEDIA_VISION_FUNCTION_ENTER(); + + if (image_path == NULL) + { + LOGE("image_path is NULL\n"); + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + if (type < MV_BARCODE_QR || + type >= MV_BARCODE_UNDEFINED) + { + LOGE("Not supported barcode type [%d]", type); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (type == MV_BARCODE_QR) + { + if (qr_enc_mode < MV_BARCODE_QR_MODE_NUMERIC || + qr_enc_mode >= MV_BARCODE_QR_MODE_UNAVAILABLE) + { + LOGE("Not supported QR encoding mode[%d]", qr_enc_mode); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (qr_ecc < MV_BARCODE_QR_ECC_LOW || + qr_ecc >= MV_BARCODE_QR_ECC_UNAVAILABLE) + { + LOGE("Not supported QR ECC level [%d]", qr_ecc); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (qr_version < 1 || qr_version > 40) + { + LOGE("Not supported QR version [%d]", qr_version); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + } + + if (image_format < MV_BARCODE_IMAGE_FORMAT_BMP || + image_format >= MV_BARCODE_IMAGE_FORMAT_NUM) + { + LOGE("Not supported image format [%d]", image_format); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + +#ifdef MEDIA_VISION_BARCODE_GENERATOR_LICENSE_PORT + + /* Use licensed barcode generate functionality here. */ + int ret = mv_barcode_generate_image_lic( + engine_cfg, message, image_width, image_height, type, + qr_enc_mode, qr_ecc, qr_version, image_path, image_format); + +#else + + /* Use open barcode generate functionality here. */ + int ret = mv_barcode_generate_image_open( + engine_cfg, message, image_width, image_height, type, + qr_enc_mode, qr_ecc, qr_version, image_path, image_format); + +#endif /* MEDIA_VISION_BARCODE_GENERATOR_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} diff --git a/src/mv_common.c b/src/mv_common.c new file mode 100644 index 0000000..d11ca6b --- /dev/null +++ b/src/mv_common.c @@ -0,0 +1,338 @@ +/** + * 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_private.h" +#include "mv_common.h" +#include "mv_common_c.h" + +int mv_create_source( + mv_source_h *source) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_check_system_info_feature_supported); + MEDIA_VISION_NULL_ARG_CHECK(source); + + MEDIA_VISION_FUNCTION_ENTER(); + int ret = mv_create_source_c(source); + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int mv_destroy_source( + mv_source_h source) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(source); + + MEDIA_VISION_FUNCTION_ENTER(); + int ret = mv_destroy_source_c(source); + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int mv_source_fill_by_media_packet( + mv_source_h source, + media_packet_h media_packet) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(source); + MEDIA_VISION_INSTANCE_CHECK(media_packet); + + MEDIA_VISION_FUNCTION_ENTER(); + int ret = mv_source_fill_by_media_packet_c(source, media_packet); + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int mv_source_fill_by_buffer( + mv_source_h source, + unsigned char *data_buffer, + unsigned int buffer_size, + unsigned int image_width, + unsigned int image_height, + mv_colorspace_e image_colorspace) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(source); + MEDIA_VISION_NULL_ARG_CHECK(data_buffer); + + MEDIA_VISION_FUNCTION_ENTER(); + int ret = mv_source_fill_by_buffer_c( + source, data_buffer, buffer_size, image_width, image_height, + image_colorspace); + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int mv_source_clear( + mv_source_h source) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(source); + + MEDIA_VISION_FUNCTION_ENTER(); + int ret = mv_source_clear_c(source); + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int mv_source_get_buffer( + mv_source_h source, + unsigned char **data_buffer, + unsigned int *buffer_size) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(source); + MEDIA_VISION_NULL_ARG_CHECK(data_buffer); + MEDIA_VISION_NULL_ARG_CHECK(buffer_size); + + MEDIA_VISION_FUNCTION_ENTER(); + int ret = mv_source_get_buffer_c(source, data_buffer, buffer_size); + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int mv_source_get_height( + mv_source_h source, + unsigned int *image_height) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(source); + MEDIA_VISION_NULL_ARG_CHECK(image_height); + + MEDIA_VISION_FUNCTION_ENTER(); + int ret = mv_source_get_height_c(source, image_height); + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int mv_source_get_width( + mv_source_h source, + unsigned int *image_width) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(source); + MEDIA_VISION_NULL_ARG_CHECK(image_width); + + MEDIA_VISION_FUNCTION_ENTER(); + int ret = mv_source_get_width_c(source, image_width); + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int mv_source_get_colorspace( + mv_source_h source, + mv_colorspace_e *image_colorspace) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(source); + MEDIA_VISION_NULL_ARG_CHECK(image_colorspace); + + MEDIA_VISION_FUNCTION_ENTER(); + int ret = mv_source_get_colorspace_c(source, image_colorspace); + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int mv_create_engine_config( + mv_engine_config_h *engine_cfg) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_check_system_info_feature_supported); + MEDIA_VISION_NULL_ARG_CHECK(engine_cfg); + + MEDIA_VISION_FUNCTION_ENTER(); + int ret = mv_create_engine_config_c(engine_cfg); + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int mv_destroy_engine_config( + mv_engine_config_h engine_cfg) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(engine_cfg); + + MEDIA_VISION_FUNCTION_ENTER(); + int ret = mv_destroy_engine_config_c(engine_cfg); + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int mv_engine_config_set_double_attribute( + mv_engine_config_h engine_cfg, + const char *name, + double value) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(engine_cfg); + MEDIA_VISION_NULL_ARG_CHECK(name); + + MEDIA_VISION_FUNCTION_ENTER(); + int ret = mv_engine_config_set_double_attribute_c( + engine_cfg, name, value); + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int mv_engine_config_set_int_attribute( + mv_engine_config_h engine_cfg, + const char *name, + int value) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(engine_cfg); + MEDIA_VISION_NULL_ARG_CHECK(name); + + MEDIA_VISION_FUNCTION_ENTER(); + int ret = mv_engine_config_set_int_attribute_c( + engine_cfg, name, value); + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int mv_engine_config_set_bool_attribute( + mv_engine_config_h engine_cfg, + const char *name, + bool value) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(engine_cfg); + MEDIA_VISION_NULL_ARG_CHECK(name); + + MEDIA_VISION_FUNCTION_ENTER(); + int ret = mv_engine_config_set_bool_attribute_c( + engine_cfg, name, value); + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int mv_engine_config_set_string_attribute( + mv_engine_config_h engine_cfg, + const char *name, + const char *value) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(engine_cfg); + MEDIA_VISION_NULL_ARG_CHECK(name); + MEDIA_VISION_NULL_ARG_CHECK(value); + + MEDIA_VISION_FUNCTION_ENTER(); + int ret = mv_engine_config_set_string_attribute_c( + engine_cfg, name, value); + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int mv_engine_config_get_double_attribute( + mv_engine_config_h engine_cfg, + const char *name, + double *value) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(engine_cfg); + MEDIA_VISION_NULL_ARG_CHECK(name); + MEDIA_VISION_NULL_ARG_CHECK(value); + + MEDIA_VISION_FUNCTION_ENTER(); + int ret = mv_engine_config_get_double_attribute_c( + engine_cfg, name, value); + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int mv_engine_config_get_int_attribute( + mv_engine_config_h engine_cfg, + const char *name, + int *value) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(engine_cfg); + MEDIA_VISION_NULL_ARG_CHECK(name); + MEDIA_VISION_NULL_ARG_CHECK(value); + + MEDIA_VISION_FUNCTION_ENTER(); + int ret = mv_engine_config_get_int_attribute_c( + engine_cfg, name, value); + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int mv_engine_config_get_bool_attribute( + mv_engine_config_h engine_cfg, + const char *name, + bool *value) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(engine_cfg); + MEDIA_VISION_NULL_ARG_CHECK(name); + MEDIA_VISION_NULL_ARG_CHECK(value); + + MEDIA_VISION_FUNCTION_ENTER(); + int ret = mv_engine_config_get_bool_attribute_c( + engine_cfg, name, value); + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int mv_engine_config_get_string_attribute( + mv_engine_config_h engine_cfg, + const char *name, + char **value) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(engine_cfg); + MEDIA_VISION_NULL_ARG_CHECK(name); + MEDIA_VISION_NULL_ARG_CHECK(value); + + MEDIA_VISION_FUNCTION_ENTER(); + int ret = mv_engine_config_get_string_attribute_c( + engine_cfg, name, value); + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int mv_engine_config_foreach_supported_attribute( + mv_supported_attribute_cb callback, + void *user_data) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_check_system_info_feature_supported); + MEDIA_VISION_NULL_ARG_CHECK(callback); + + MEDIA_VISION_FUNCTION_ENTER(); + int ret = + mv_engine_config_foreach_supported_attribute_c(callback, user_data); + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} diff --git a/src/mv_face.c b/src/mv_face.c new file mode 100644 index 0000000..bf229a9 --- /dev/null +++ b/src/mv_face.c @@ -0,0 +1,762 @@ +/** + * 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_private.h" +#include "mv_face.h" + +#ifdef MEDIA_VISION_FACE_LICENSE_PORT + +/* Include headers of licensed face module here. */ +#include "mv_face_lic.h" + +#else + +/* Include headers of open face module here. */ +#include "mv_face_open.h" + +#endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + +/** + * @file mv_face.c + * @brief This file contains the porting layer for Media Vision face module. + */ + +static const int check_source_roi_quadrangle(mv_quadrangle_s *roi, mv_source_h source) +{ + int ret = MEDIA_VISION_ERROR_NONE; + + if (roi) + { + int src_w = 0; + int src_h = 0; + + ret = mv_source_get_width(source, &src_w); + if (ret != MEDIA_VISION_ERROR_NONE) + { + LOGE("mv_source_get_width fail"); + return ret; + } + + ret = mv_source_get_height(source, &src_h); + if (ret != MEDIA_VISION_ERROR_NONE) + { + LOGE("mv_source_get_height fail"); + return ret; + } + + int idx = 0; + while (idx < 4) + { + if (roi->points[idx].x < 0 || roi->points[idx].y < 0 || + roi->points[idx].x > src_w || roi->points[idx].y > src_h) + { + LOGE("roi is out of area on source"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + ++idx; + } + } + + return ret; +} + +static const int check_source_roi(mv_rectangle_s *roi, mv_source_h source) +{ + int ret = MEDIA_VISION_ERROR_NONE; + + if (roi) + { + int src_w = 0; + int src_h = 0; + + ret = mv_source_get_width(source, &src_w); + if (ret != MEDIA_VISION_ERROR_NONE) + { + LOGE("mv_source_get_width fail"); + return ret; + } + + ret = mv_source_get_height(source, &src_h); + if (ret != MEDIA_VISION_ERROR_NONE) + { + LOGE("mv_source_get_height fail"); + return ret; + } + + if (roi->width <= 0 || roi->height <= 0) + { + LOGE("roi has negative width or height"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (roi->point.x < 0 || roi->point.y < 0 || + (roi->point.x + roi->width) > src_w || + (roi->point.y + roi->height) > src_h) + { + LOGE("roi is out of area on source"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + } + + return ret; +} + +int mv_face_detect( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_face_detected_cb detected_cb, + void *user_data) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(source); + MEDIA_VISION_NULL_ARG_CHECK(detected_cb); + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = MEDIA_VISION_ERROR_NONE; + + #ifdef MEDIA_VISION_FACE_LICENSE_PORT + + ret = mv_face_detect_lic(source, engine_cfg, detected_cb, user_data); + + #else + + ret = mv_face_detect_open(source, engine_cfg, detected_cb, user_data); + + #endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_face_recognize( + mv_source_h source, + mv_face_recognition_model_h recognition_model, + mv_engine_config_h engine_cfg, + mv_rectangle_s *face_location, + mv_face_recognized_cb recognized_cb, + void *user_data) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(source); + MEDIA_VISION_INSTANCE_CHECK(recognition_model); + MEDIA_VISION_NULL_ARG_CHECK(recognized_cb); + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = check_source_roi(face_location, source); + if (MEDIA_VISION_ERROR_NONE != ret) + { + LOGE("Errors occured when check source and ROI"); + return ret; + } + + #ifdef MEDIA_VISION_FACE_LICENSE_PORT + + ret = mv_face_recognize_lic( + source, + recognition_model, + engine_cfg, + face_location, + recognized_cb, + user_data); + + #else + + ret = mv_face_recognize_open( + source, + recognition_model, + engine_cfg, + face_location, + recognized_cb, + user_data); + + #endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_face_track( + mv_source_h source, + mv_face_tracking_model_h tracking_model, + mv_engine_config_h engine_cfg, + mv_face_tracked_cb tracked_cb, + bool do_learn, + void *user_data) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(source); + MEDIA_VISION_INSTANCE_CHECK(tracking_model); + MEDIA_VISION_NULL_ARG_CHECK(tracked_cb); + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = MEDIA_VISION_ERROR_NONE; + + #ifdef MEDIA_VISION_FACE_LICENSE_PORT + + ret = mv_face_track_lic( + source, + tracking_model, + engine_cfg, + tracked_cb, + do_learn, + user_data); + + #else + + ret = mv_face_track_open( + source, + tracking_model, + engine_cfg, + tracked_cb, + do_learn, + user_data); + + #endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_face_eye_condition_recognize( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s face_location, + mv_face_eye_condition_recognized_cb eye_condition_recognized_cb, + void *user_data) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(source); + MEDIA_VISION_NULL_ARG_CHECK(eye_condition_recognized_cb); + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = MEDIA_VISION_ERROR_NONE; + + #ifdef MEDIA_VISION_FACE_LICENSE_PORT + + ret = mv_face_eye_condition_recognize_lic( + source, + engine_cfg, + face_location, + eye_condition_recognized_cb, + user_data); + + #else + + ret = mv_face_eye_condition_recognize_open( + source, + engine_cfg, + face_location, + eye_condition_recognized_cb, + user_data); + + #endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_face_facial_expression_recognize( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s face_location, + mv_face_facial_expression_recognized_cb expression_recognized_cb, + void *user_data) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(source); + MEDIA_VISION_NULL_ARG_CHECK(expression_recognized_cb); + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = check_source_roi(&face_location, source); + if (MEDIA_VISION_ERROR_NONE != ret) + { + LOGE("Errors occurred when check source and ROI"); + return ret; + } + + #ifdef MEDIA_VISION_FACE_LICENSE_PORT + + ret = mv_face_facial_expression_recognize_lic( + source, + engine_cfg, + face_location, + expression_recognized_cb, + user_data); + + #else + + ret = mv_face_facial_expression_recognize_open( + source, + engine_cfg, + face_location, + expression_recognized_cb, + user_data); + + #endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_face_recognition_model_create( + mv_face_recognition_model_h *recognition_model) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported); + MEDIA_VISION_NULL_ARG_CHECK(recognition_model); + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = MEDIA_VISION_ERROR_NONE; + + #ifdef MEDIA_VISION_FACE_LICENSE_PORT + + ret = mv_face_recognition_model_create_lic(recognition_model); + + #else + + ret = mv_face_recognition_model_create_open(recognition_model); + + #endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_face_recognition_model_destroy( + mv_face_recognition_model_h recognition_model) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(recognition_model); + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = MEDIA_VISION_ERROR_NONE; + + #ifdef MEDIA_VISION_FACE_LICENSE_PORT + + ret = mv_face_recognition_model_destroy_lic(recognition_model); + + #else + + ret = mv_face_recognition_model_destroy_open(recognition_model); + + #endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_face_recognition_model_clone( + mv_face_recognition_model_h src, + mv_face_recognition_model_h *dst) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(src); + MEDIA_VISION_NULL_ARG_CHECK(dst); + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = MEDIA_VISION_ERROR_NONE; + + #ifdef MEDIA_VISION_FACE_LICENSE_PORT + + ret = mv_face_recognition_model_clone_lic(src, dst); + + #else + + ret = mv_face_recognition_model_clone_open(src, dst); + + #endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_face_recognition_model_save( + const char *file_name, + mv_face_recognition_model_h recognition_model) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(recognition_model); + + if (file_name == NULL) + { + LOGE("File name is NULL. The file name has to be specified"); + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = MEDIA_VISION_ERROR_NONE; + + #ifdef MEDIA_VISION_FACE_LICENSE_PORT + + ret = mv_face_recognition_model_save_lic( + file_name, + recognition_model); + + #else + + ret = mv_face_recognition_model_save_open( + file_name, + recognition_model); + + #endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_face_recognition_model_load( + const char *file_name, + mv_face_recognition_model_h *recognition_model) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported); + MEDIA_VISION_NULL_ARG_CHECK(recognition_model); + + if (file_name == NULL) + { + LOGE("File name is NULL. The file name has to be specified"); + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = MEDIA_VISION_ERROR_NONE; + + #ifdef MEDIA_VISION_FACE_LICENSE_PORT + + ret = mv_face_recognition_model_load_lic( + file_name, + recognition_model); + + #else + + ret = mv_face_recognition_model_load_open( + file_name, + recognition_model); + + #endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_face_recognition_model_add( + const mv_source_h source, + mv_face_recognition_model_h recognition_model, + const mv_rectangle_s *example_location, + int face_label) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(source); + MEDIA_VISION_INSTANCE_CHECK(recognition_model); + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = check_source_roi(example_location, source); + if (MEDIA_VISION_ERROR_NONE != ret) + { + LOGE("Errors occured when check source and ROI"); + return ret; + } + + #ifdef MEDIA_VISION_FACE_LICENSE_PORT + + ret = mv_face_recognition_model_add_lic( + source, + recognition_model, + example_location, + face_label); + #else + + ret = mv_face_recognition_model_add_open( + source, + recognition_model, + example_location, + face_label); + + #endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_face_recognition_model_reset( + mv_face_recognition_model_h recognition_model, + int *face_label) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(recognition_model); + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = MEDIA_VISION_ERROR_NONE; + + #ifdef MEDIA_VISION_FACE_LICENSE_PORT + + ret = mv_face_recognition_model_reset_lic( + recognition_model, + face_label); + + #else + + ret = mv_face_recognition_model_reset_open( + recognition_model, + face_label); + + #endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_face_recognition_model_learn( + mv_engine_config_h engine_cfg, + mv_face_recognition_model_h recognition_model) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(recognition_model); + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = MEDIA_VISION_ERROR_NONE; + + #ifdef MEDIA_VISION_FACE_LICENSE_PORT + + ret = mv_face_recognition_model_learn_lic(engine_cfg, recognition_model); + + #else + + ret = mv_face_recognition_model_learn_open(engine_cfg, recognition_model); + + #endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_face_recognition_model_query_labels( + mv_face_recognition_model_h recognition_model, + int **labels, + unsigned int *number_of_labels) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(recognition_model); + MEDIA_VISION_NULL_ARG_CHECK(labels); + MEDIA_VISION_NULL_ARG_CHECK(number_of_labels); + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = MEDIA_VISION_ERROR_NONE; + + #ifdef MEDIA_VISION_FACE_LICENSE_PORT + + ret = mv_face_recognition_model_query_labels_lic(recognition_model, labels, number_of_labels); + + #else + + ret = mv_face_recognition_model_query_labels_open(recognition_model, labels, number_of_labels); + + #endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_face_tracking_model_create( + mv_face_tracking_model_h *tracking_model) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported); + MEDIA_VISION_NULL_ARG_CHECK(tracking_model); + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = MEDIA_VISION_ERROR_NONE; + + #ifdef MEDIA_VISION_FACE_LICENSE_PORT + + ret = mv_face_tracking_model_create_lic(tracking_model); + + #else + + ret = mv_face_tracking_model_create_open(tracking_model); + + #endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_face_tracking_model_destroy( + mv_face_tracking_model_h tracking_model) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(tracking_model); + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = MEDIA_VISION_ERROR_NONE; + + #ifdef MEDIA_VISION_FACE_LICENSE_PORT + + ret = mv_face_tracking_model_destroy_lic(tracking_model); + + #else + + ret = mv_face_tracking_model_destroy_open(tracking_model); + + #endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_face_tracking_model_prepare( + mv_face_tracking_model_h tracking_model, + mv_engine_config_h engine_cfg, + mv_source_h source, + mv_quadrangle_s *location) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(tracking_model); + MEDIA_VISION_INSTANCE_CHECK(source); + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = check_source_roi_quadrangle(location, source); + if (MEDIA_VISION_ERROR_NONE != ret) + { + LOGE("Errors occured when check source and tracking start location"); + return ret; + } + + #ifdef MEDIA_VISION_FACE_LICENSE_PORT + + ret = mv_face_tracking_model_prepare_lic( + tracking_model, engine_cfg, source, location); + + #else + + ret = mv_face_tracking_model_prepare_open( + tracking_model, engine_cfg, source, location); + + #endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_face_tracking_model_clone( + mv_face_tracking_model_h src, + mv_face_tracking_model_h *dst) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(src); + MEDIA_VISION_NULL_ARG_CHECK(dst); + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = MEDIA_VISION_ERROR_NONE; + + #ifdef MEDIA_VISION_FACE_LICENSE_PORT + + ret = mv_face_tracking_model_clone_lic(src, dst); + + #else + + ret = mv_face_tracking_model_clone_open(src, dst); + + #endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_face_tracking_model_save( + const char *file_name, + mv_face_tracking_model_h tracking_model) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(tracking_model); + + if (file_name == NULL) + { + LOGE("File name is NULL. The file name has to be specified"); + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = MEDIA_VISION_ERROR_NONE; + + #ifdef MEDIA_VISION_FACE_LICENSE_PORT + + ret = mv_face_tracking_model_save_lic( + file_name, + tracking_model); + + #else + + ret = mv_face_tracking_model_save_open( + file_name, + tracking_model); + + #endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_face_tracking_model_load( + const char *file_name, + mv_face_tracking_model_h *tracking_model) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported); + MEDIA_VISION_NULL_ARG_CHECK(tracking_model); + + if (file_name == NULL) + { + LOGE("File name is NULL. The file name has to be specifiled"); + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + MEDIA_VISION_FUNCTION_ENTER(); + + int ret = MEDIA_VISION_ERROR_NONE; + + #ifdef MEDIA_VISION_FACE_LICENSE_PORT + + ret = mv_face_tracking_model_load_lic( + file_name, + tracking_model); + + #else + + ret = mv_face_tracking_model_load_open( + file_name, + tracking_model); + + #endif /* MEDIA_VISION_FACE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} diff --git a/src/mv_image.c b/src/mv_image.c new file mode 100644 index 0000000..f041924 --- /dev/null +++ b/src/mv_image.c @@ -0,0 +1,529 @@ +/** + * 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_private.h" +#include "mv_image.h" + +#ifdef MEDIA_VISION_IMAGE_LICENSE_PORT + +/* Include headers of licensed image module here. */ +#include "mv_image_lic.h" + +#else + +/* Include headers of open image module here. */ +#include "mv_image_open.h" + +#endif /* MEDIA_VISION_IMAGE_LICENSE_PORT */ + +/** + * @file mv_image.c + * @brief This file contains the porting layer for Media Vision image module. + */ + +int mv_image_recognize( + mv_source_h source, + const mv_image_object_h *image_objects, + int number_of_objects, + mv_engine_config_h engine_cfg, + mv_image_recognized_cb recognized_cb, + void *user_data) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(source); + MEDIA_VISION_NULL_ARG_CHECK(image_objects); + int object_num = 0; + for (; object_num < number_of_objects; ++object_num) + { + MEDIA_VISION_INSTANCE_CHECK(image_objects[object_num]); + } + MEDIA_VISION_NULL_ARG_CHECK(recognized_cb); + + MEDIA_VISION_FUNCTION_ENTER(); + +#ifdef MEDIA_VISION_IMAGE_LICENSE_PORT + + /* Use licensed image functionality here. */ + int ret = mv_image_recognize_lic(source, image_objects, + number_of_objects, engine_cfg, recognized_cb, user_data); + +#else + + /* Use open image functionality here. */ + int ret = mv_image_recognize_open(source, image_objects, + number_of_objects, engine_cfg, recognized_cb, user_data); + +#endif /* MEDIA_VISION_IMAGE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_image_track( + mv_source_h source, + mv_image_tracking_model_h image_tracking_model, + mv_engine_config_h engine_cfg, + mv_image_tracked_cb tracked_cb, + void *user_data) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(source); + MEDIA_VISION_INSTANCE_CHECK(image_tracking_model); + MEDIA_VISION_NULL_ARG_CHECK(tracked_cb); + + MEDIA_VISION_FUNCTION_ENTER(); + +#ifdef MEDIA_VISION_IMAGE_LICENSE_PORT + + /* Use licensed image functionality here. */ + int ret = mv_image_track_lic(source, image_tracking_model, engine_cfg, tracked_cb, user_data); + +#else + + /* Use open image functionality here. */ + int ret = mv_image_track_open(source, image_tracking_model, engine_cfg, tracked_cb, user_data); + +#endif /* MEDIA_VISION_IMAGE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_image_object_create( + mv_image_object_h *image_object) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported); + MEDIA_VISION_NULL_ARG_CHECK(image_object); + MEDIA_VISION_FUNCTION_ENTER(); + +#ifdef MEDIA_VISION_IMAGE_LICENSE_PORT + + /* Use licensed image functionality here. */ + int ret = mv_image_object_create_lic(image_object); + +#else + + /* Use open image functionality here. */ + int ret = mv_image_object_create_open(image_object); + +#endif /* MEDIA_VISION_IMAGE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_image_object_destroy( + mv_image_object_h image_object) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(image_object); + MEDIA_VISION_FUNCTION_ENTER(); + +#ifdef MEDIA_VISION_IMAGE_LICENSE_PORT + + /* Use licensed image functionality here. */ + int ret = mv_image_object_destroy_lic(image_object); + +#else + + /* Use open image functionality here. */ + int ret = mv_image_object_destroy_open(image_object); + +#endif /* MEDIA_VISION_IMAGE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_image_object_fill( + mv_image_object_h image_object, + mv_engine_config_h engine_cfg, + mv_source_h source, + mv_rectangle_s *location) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(image_object); + MEDIA_VISION_INSTANCE_CHECK(source); + + MEDIA_VISION_FUNCTION_ENTER(); + +#ifdef MEDIA_VISION_IMAGE_LICENSE_PORT + + /* Use licensed image functionality here. */ + int ret = mv_image_object_fill_lic(image_object, engine_cfg, source, location); + +#else + + /* Use open image functionality here. */ + int ret = mv_image_object_fill_open(image_object, engine_cfg, source, location); + +#endif /* MEDIA_VISION_IMAGE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_image_object_get_recognition_rate( + mv_image_object_h image_object, + double *recognition_rate) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(image_object); + MEDIA_VISION_NULL_ARG_CHECK(recognition_rate); + + MEDIA_VISION_FUNCTION_ENTER(); + +#ifdef MEDIA_VISION_IMAGE_LICENSE_PORT + + /* Use licensed image functionality here. */ + int ret = mv_image_object_get_recognition_rate_lic(image_object, recognition_rate); + +#else + + /* Use open image functionality here. */ + int ret = mv_image_object_get_recognition_rate_open(image_object, recognition_rate); + +#endif /* MEDIA_VISION_IMAGE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_image_object_set_label( + mv_image_object_h image_object, + int label) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(image_object); + + MEDIA_VISION_FUNCTION_ENTER(); + +#ifdef MEDIA_VISION_IMAGE_LICENSE_PORT + + /* Use licensed image functionality here. */ + int ret = mv_image_object_set_label_lic(image_object, label); + +#else + + /* Use open image functionality here. */ + int ret = mv_image_object_set_label_open(image_object, label); + +#endif /* MEDIA_VISION_IMAGE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_image_object_get_label( + mv_image_object_h image_object, + int *label) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(image_object); + MEDIA_VISION_NULL_ARG_CHECK(label); + + MEDIA_VISION_FUNCTION_ENTER(); + +#ifdef MEDIA_VISION_IMAGE_LICENSE_PORT + + /* Use licensed image functionality here. */ + int ret = mv_image_object_get_label_lic(image_object, label); + +#else + + /* Use open image functionality here. */ + int ret = mv_image_object_get_label_open(image_object, label); + +#endif /* MEDIA_VISION_IMAGE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_image_object_clone( + mv_image_object_h src, + mv_image_object_h *dst) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(src); + MEDIA_VISION_NULL_ARG_CHECK(dst); + + MEDIA_VISION_FUNCTION_ENTER(); + +#ifdef MEDIA_VISION_IMAGE_LICENSE_PORT + + /* Use licensed image functionality here. */ + int ret = mv_image_object_clone_lic(src, dst); + +#else + + /* Use open image functionality here. */ + int ret = mv_image_object_clone_open(src, dst); + +#endif /* MEDIA_VISION_IMAGE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_image_object_save( + const char *file_name, mv_image_object_h image_object) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(image_object); + + if (file_name == NULL) + { + LOGE("File name is NULL. The file name has to be specified"); + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + MEDIA_VISION_FUNCTION_ENTER(); + +#ifdef MEDIA_VISION_IMAGE_LICENSE_PORT + + /* Use licensed image functionality here. */ + int ret = mv_image_object_save_lic(file_name, image_object); + +#else + + /* Use open image functionality here. */ + int ret = mv_image_object_save_open(file_name, image_object); + +#endif /* MEDIA_VISION_IMAGE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_image_object_load( + const char *file_name, mv_image_object_h *image_object) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported); + MEDIA_VISION_NULL_ARG_CHECK(image_object); + + if (file_name == NULL) + { + LOGE("file name is NULL. The file name has to be specified"); + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + MEDIA_VISION_FUNCTION_ENTER(); + +#ifdef MEDIA_VISION_IMAGE_LICENSE_PORT + + /* Use licensed image functionality here. */ + int ret = mv_image_object_load_lic(file_name, image_object); + +#else + + /* Use open image functionality here. */ + int ret = mv_image_object_load_open(file_name, image_object); + +#endif /* MEDIA_VISION_IMAGE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_image_tracking_model_create( + mv_image_tracking_model_h *image_tracking_model) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported); + MEDIA_VISION_NULL_ARG_CHECK(image_tracking_model); + + MEDIA_VISION_FUNCTION_ENTER(); + +#ifdef MEDIA_VISION_IMAGE_LICENSE_PORT + + /* Use licensed image functionality here. */ + int ret = mv_image_tracking_model_create_lic(image_tracking_model); + +#else + + /* Use open image functionality here. */ + int ret = mv_image_tracking_model_create_open(image_tracking_model); + +#endif /* MEDIA_VISION_IMAGE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_image_tracking_model_set_target( + mv_image_object_h image_object, + mv_image_tracking_model_h image_tracking_model) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(image_tracking_model); + MEDIA_VISION_INSTANCE_CHECK(image_object); + + MEDIA_VISION_FUNCTION_ENTER(); + +#ifdef MEDIA_VISION_IMAGE_LICENSE_PORT + + /* Use licensed image functionality here. */ + int ret = mv_image_tracking_model_set_target_lic(image_object, image_tracking_model); + +#else + + /* Use open image functionality here. */ + int ret = mv_image_tracking_model_set_target_open(image_object, image_tracking_model); + +#endif /* MEDIA_VISION_IMAGE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_image_tracking_model_destroy( + mv_image_tracking_model_h image_tracking_model) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(image_tracking_model); + + MEDIA_VISION_FUNCTION_ENTER(); + +#ifdef MEDIA_VISION_IMAGE_LICENSE_PORT + + /* Use licensed image functionality here. */ + int ret = mv_image_tracking_model_destroy_lic(image_tracking_model); + +#else + + /* Use open image functionality here. */ + int ret = mv_image_tracking_model_destroy_open(image_tracking_model); + +#endif /* MEDIA_VISION_IMAGE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_image_tracking_model_refresh( + mv_image_tracking_model_h image_tracking_model, + mv_engine_config_h engine_cfg) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(image_tracking_model); + + MEDIA_VISION_FUNCTION_ENTER(); + +#ifdef MEDIA_VISION_IMAGE_LICENSE_PORT + + /* Use licensed image functionality here. */ + int ret = mv_image_tracking_model_refresh_lic( + image_tracking_model, + engine_cfg); + +#else + + /* Use open image functionality here. */ + int ret = mv_image_tracking_model_refresh_open( + image_tracking_model, + engine_cfg); + +#endif /* MEDIA_VISION_IMAGE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_image_tracking_model_clone( + mv_image_tracking_model_h src, + mv_image_tracking_model_h *dst) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(src); + MEDIA_VISION_NULL_ARG_CHECK(dst); + + MEDIA_VISION_FUNCTION_ENTER(); + +#ifdef MEDIA_VISION_IMAGE_LICENSE_PORT + + /* Use licensed image functionality here. */ + int ret = mv_image_tracking_model_clone_lic(src, dst); + +#else + + /* Use open image functionality here. */ + int ret = mv_image_tracking_model_clone_open(src, dst); + +#endif /* MEDIA_VISION_IMAGE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_image_tracking_model_save( + const char *file_name, mv_image_tracking_model_h image_tracking_model) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported); + MEDIA_VISION_INSTANCE_CHECK(image_tracking_model); + + if (file_name == NULL) + { + LOGE("File name is NULL. The file name has to be specified"); + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + MEDIA_VISION_FUNCTION_ENTER(); + +#ifdef MEDIA_VISION_IMAGE_LICENSE_PORT + + /* Use licensed image functionality here. */ + int ret = mv_image_tracking_model_save_lic(file_name, image_tracking_model); + +#else + + /* Use open image functionality here. */ + int ret = mv_image_tracking_model_save_open(file_name, image_tracking_model); + +#endif /* MEDIA_VISION_IMAGE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} + +int mv_image_tracking_model_load( + const char *file_name, mv_image_tracking_model_h *image_tracking_model) +{ + MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported); + MEDIA_VISION_NULL_ARG_CHECK(image_tracking_model); + + if (file_name == NULL) + { + LOGE("File name is NULL. The file name has to be specified"); + return MEDIA_VISION_ERROR_INVALID_PATH; + } + + MEDIA_VISION_FUNCTION_ENTER(); + +#ifdef MEDIA_VISION_IMAGE_LICENSE_PORT + + /* Use licensed image functionality here. */ + int ret = mv_image_tracking_model_load_lic(file_name, image_tracking_model); + +#else + + /* Use open image functionality here. */ + int ret = mv_image_tracking_model_load_open(file_name, image_tracking_model); + +#endif /* MEDIA_VISION_IMAGE_LICENSE_PORT */ + + MEDIA_VISION_FUNCTION_LEAVE(); + return ret; +} diff --git a/src/mv_private.c b/src/mv_private.c new file mode 100644 index 0000000..af4e7df --- /dev/null +++ b/src/mv_private.c @@ -0,0 +1,175 @@ +/** + * 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 + +#include "mv_private.h" + +bool __mv_check_system_info_feature_supported() +{ + // return true is temporary added to allow correct flow for UTC + // todo: remove when vision.barcode_detection and vision.barcode_generation + // will be added + return true; + + bool isBarcodeDetectionSupported = false; + bool isBarcodeGenerationSupported = false; + bool isFaceRecognitionSupported = false; + bool isImageRecognitionSupported = false; + + const int nRetVal1 = system_info_get_platform_bool("http://tizen.org/feature/vision.barcode_detection", &isBarcodeDetectionSupported); + + if (nRetVal1 != SYSTEM_INFO_ERROR_NONE) + { + LOGE("[%s] SYSTEM_INFO_ERROR: __FUNCTION__"); + return false; + } + + const int nRetVal2 = system_info_get_platform_bool("http://tizen.org/feature/vision.barcode_generation", &isBarcodeGenerationSupported); + + if (nRetVal2 != SYSTEM_INFO_ERROR_NONE) + { + LOGE("[%s] SYSTEM_INFO_ERROR: __FUNCTION__"); + return false; + } + + const int nRetVal3 = system_info_get_platform_bool("http://tizen.org/feature/vision.face_recognition", &isFaceRecognitionSupported); + + if (nRetVal3 != SYSTEM_INFO_ERROR_NONE) + { + LOGE("[%s] SYSTEM_INFO_ERROR: __FUNCTION__"); + return false; + } + + const int nRetVal4 = system_info_get_platform_bool("http://tizen.org/feature/vision.image_recognition", &isImageRecognitionSupported); + + if (nRetVal2 != SYSTEM_INFO_ERROR_NONE) + { + LOGE("[%s] SYSTEM_INFO_ERROR: __FUNCTION__"); + return false; + } + (isBarcodeDetectionSupported || isBarcodeGenerationSupported || + isFaceRecognitionSupported || isImageRecognitionSupported) ? + LOGI("system_info_get_platform_bool returned" + "Supported one feature among barcode detection, " + "barcode generation, face recognition, " + "and image recognition capability\n") : + LOGE("system_info_get_platform_bool returned" + "Unsupported all features of barcode detection, " + "barcode generation, face recognition, " + "and image recognition capability\n") ; + + return (isBarcodeDetectionSupported || isBarcodeGenerationSupported || + isFaceRecognitionSupported || isImageRecognitionSupported); +} + +bool __mv_barcode_detect_check_system_info_feature_supported() +{ + // return true is temporary added to allow correct flow for UTC + // todo: remove when vision.barcode_detection feature will be added + return true; + + bool isBarcodeDetectionSupported = false; + + const int nRetVal = system_info_get_platform_bool("http://tizen.org/feature/vision.barcode_detection", &isBarcodeDetectionSupported); + + if (nRetVal != SYSTEM_INFO_ERROR_NONE) + { + LOGE("[%s] SYSTEM_INFO_ERROR: __FUNCTION__"); + return false; + } + + isBarcodeDetectionSupported ? + LOGI("system_info_get_platform_bool returned " + "Supported barcode detection feature capability\n") : + LOGE("system_info_get_platform_bool returned " + "Unsupported barcode detection feature capability\n"); + + return isBarcodeDetectionSupported; +} + +bool __mv_barcode_generate_check_system_info_feature_supported() +{ + // return true is temporary added to allow correct flow for UTC + // todo: remove when vision.barcode_generation feature will be added + return true; + + bool isBarcodeGenerationSupported = false; + + const int nRetVal = system_info_get_platform_bool("http://tizen.org/feature/vision.barcode_generation", &isBarcodeGenerationSupported); + + if (nRetVal != SYSTEM_INFO_ERROR_NONE) + { + LOGE("[%s] SYSTEM_INFO_ERROR: __FUNCTION__"); + return false; + } + + isBarcodeGenerationSupported ? + LOGI("system_info_get_platform_bool returned " + "Supported barcode generation feature capability\n") : + LOGE("system_info_get_platform_bool returned " + "Unsupported barcode generation feature capability\n"); + + return isBarcodeGenerationSupported; +} + +bool __mv_face_check_system_info_feature_supported() +{ + // return true is temporary added to allow correct flow for UTC + // todo: remove when vision.face_recognition feature will be added + return true; + + bool isFaceRecognitionSupported = false; + + const int nRetVal = system_info_get_platform_bool("http://tizen.org/feature/vision.face_recognition", &isFaceRecognitionSupported); + + if (nRetVal != SYSTEM_INFO_ERROR_NONE) { + LOGE("[%s] SYSTEM_INFO_ERROR: __FUNCTION__"); + return false; + } + + isFaceRecognitionSupported ? + LOGI("system_info_get_platform_bool returned " + "Supported face recognition feature capability\n") : + LOGE("system_info_get_platform_bool returned " + "Unsupported face recognition feature capability\n"); + + return isFaceRecognitionSupported; +} + +bool __mv_image_check_system_info_feature_supported() +{ + // return true is temporary added to allow correct flow for UTC + // todo: remove when vision.image_recognition feature will be added + return true; + + bool isImageRecognitionSupported = false; + + const int nRetVal = system_info_get_platform_bool("http://tizen.org/feature/vision.image_recognition", &isImageRecognitionSupported); + + if (nRetVal != SYSTEM_INFO_ERROR_NONE) { + LOGE("[%s] SYSTEM_INFO_ERROR: __FUNCTION__"); + return false; + } + + isImageRecognitionSupported ? + LOGI("system_info_get_platform_bool returned " + "Supported image recognition feature capability\n") : + LOGE("system_info_get_platform_bool returned " + "Unsupported image recognition feature capability\n"); + + return isImageRecognitionSupported; +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..b61a2b3 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,5 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +SET(testbin_dir /opt/usr/devel/media/) + +ADD_SUBDIRECTORY(${PROJECT_SOURCE_DIR}/test/testsuites) diff --git a/test/testsuites/CMakeLists.txt b/test/testsuites/CMakeLists.txt new file mode 100644 index 0000000..16a2eb6 --- /dev/null +++ b/test/testsuites/CMakeLists.txt @@ -0,0 +1,13 @@ +project(mv_testsuites) +cmake_minimum_required(VERSION 2.6) + +set(testsuites_dir "${testbin_dir}/testsuites") + +SET(INC_IMAGE_HELPER "${PROJECT_SOURCE_DIR}/common/image_helper/include") +SET(INC_VIDEO_HELPER "${PROJECT_SOURCE_DIR}/common/video_helper") +SET(INC_TS_COMMON "${PROJECT_SOURCE_DIR}/common/testsuite_common") + +add_subdirectory(${PROJECT_SOURCE_DIR}/common) +add_subdirectory(${PROJECT_SOURCE_DIR}/barcode) +add_subdirectory(${PROJECT_SOURCE_DIR}/face) +add_subdirectory(${PROJECT_SOURCE_DIR}/image) diff --git a/test/testsuites/barcode/CMakeLists.txt b/test/testsuites/barcode/CMakeLists.txt new file mode 100644 index 0000000..880da5e --- /dev/null +++ b/test/testsuites/barcode/CMakeLists.txt @@ -0,0 +1,27 @@ +project(mv_barcode_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_CXX_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_IMAGE_HELPER}) + +file(GLOB MV_TEST_SUITE_INC_LIST "${PROJECT_SOURCE_DIR}/*.h") +file(GLOB MV_TEST_SUITE_SRC_LIST "${PROJECT_SOURCE_DIR}/*.c") + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE") + +add_executable(${PROJECT_NAME} ${MV_TEST_SUITE_SRC_LIST} ${MV_TEST_SUITE_INC_LIST} ${MV_CAPI_MEDIA_VISION_INC_LIST}) + +target_link_libraries(${PROJECT_NAME} capi-media-vision dlog avcodec avformat avutil swscale mv_image_helper) + +install(TARGETS ${PROJECT_NAME} DESTINATION ${testsuites_dir}) diff --git a/test/testsuites/barcode/barcode_test_suite.c b/test/testsuites/barcode/barcode_test_suite.c new file mode 100644 index 0000000..c9d2980 --- /dev/null +++ b/test/testsuites/barcode/barcode_test_suite.c @@ -0,0 +1,1279 @@ +/** + * 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 + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +typedef struct +{ + mv_barcode_type_e type; + mv_barcode_qr_ecc_e ecc; + mv_barcode_qr_mode_e mode; + int version; + size_t width; + size_t height; + mv_barcode_image_format_e out_image_format; + mv_colorspace_e colorspace; + char *message; + char *file_name; + char *out_file_name; + unsigned char *out_buffer_ptr; +} barcode_model_s; + +typedef enum +{ + MV_TS_GENERATE_TO_IMAGE_FCN, + MV_TS_GENERATE_TO_SOURCE_FCN +} generation_fcn_e; + +int convert_rgb_to(unsigned char *src_buffer, unsigned char **dst_buffer, + image_data_s image_data, mv_colorspace_e dst_colorspace, + unsigned long *cvt_buffer_size) +{ + enum PixelFormat pixel_format = PIX_FMT_NONE; + + MEDIA_VISION_FUNCTION_ENTER(); + + switch (dst_colorspace) + { + case MEDIA_VISION_COLORSPACE_Y800: + pixel_format = PIX_FMT_GRAY8; + break; + case MEDIA_VISION_COLORSPACE_I420: + pixel_format = PIX_FMT_YUV420P; + break; + case MEDIA_VISION_COLORSPACE_NV12: + pixel_format = PIX_FMT_NV12; + break; + case MEDIA_VISION_COLORSPACE_YV12: + pixel_format = PIX_FMT_YUV420P; // the same as I420 with inversed U and V + break; + case MEDIA_VISION_COLORSPACE_NV21: + pixel_format = PIX_FMT_NV21; + break; + case MEDIA_VISION_COLORSPACE_YUYV: + pixel_format = PIX_FMT_YUYV422; + break; + case MEDIA_VISION_COLORSPACE_UYVY: + pixel_format = PIX_FMT_UYVY422; + break; + case MEDIA_VISION_COLORSPACE_422P: + pixel_format = PIX_FMT_YUV422P; + break; + case MEDIA_VISION_COLORSPACE_RGB565: + pixel_format = PIX_FMT_RGB565BE; + break; + case MEDIA_VISION_COLORSPACE_RGBA: + pixel_format = PIX_FMT_RGBA; + break; + case MEDIA_VISION_COLORSPACE_RGB888: + *cvt_buffer_size = image_data.image_width * image_data.image_height * 3; + (*dst_buffer) = (unsigned char*)malloc(*cvt_buffer_size); + memcpy(*dst_buffer, src_buffer, *cvt_buffer_size); + + MEDIA_VISION_FUNCTION_LEAVE(); + return MEDIA_VISION_ERROR_NONE; + default: + MEDIA_VISION_FUNCTION_LEAVE(); + return MEDIA_VISION_ERROR_NOT_SUPPORTED; + } + + AVPicture src_picture; + AVPicture dst_picture; + + avpicture_fill(&src_picture, (uint8_t*)src_buffer, PIX_FMT_RGB24, + image_data.image_width, image_data.image_height); + + avpicture_alloc(&dst_picture, pixel_format, + image_data.image_width, image_data.image_height); + + struct SwsContext *context = sws_getContext( + image_data.image_width, image_data.image_height, PIX_FMT_RGB24, + image_data.image_width, image_data.image_height, pixel_format, + SWS_FAST_BILINEAR, 0, 0, 0); + + sws_scale(context, (const uint8_t* const*)src_picture.data, + src_picture.linesize, 0, image_data.image_height, + dst_picture.data, dst_picture.linesize); + + *cvt_buffer_size = avpicture_get_size(pixel_format, + image_data.image_width, image_data.image_height); + (*dst_buffer) = (unsigned char*)malloc(*cvt_buffer_size); + memcpy(*dst_buffer, dst_picture.data[0], *cvt_buffer_size); + + avpicture_free(&dst_picture); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return MEDIA_VISION_ERROR_NONE; +} + +int find_min_x(const mv_quadrangle_s *quadrangle, int *minX) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + if (NULL == quadrangle) + { + MEDIA_VISION_FUNCTION_LEAVE(); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + *minX = quadrangle->points[0].x; + *minX = quadrangle->points[1].x < *minX ? quadrangle->points[1].x : *minX; + *minX = quadrangle->points[2].x < *minX ? quadrangle->points[2].x : *minX; + *minX = quadrangle->points[3].x < *minX ? quadrangle->points[3].x : *minX; + + MEDIA_VISION_FUNCTION_LEAVE(); + + return MEDIA_VISION_ERROR_NONE; +} + +int find_min_y(const mv_quadrangle_s *quadrangle, int *minY) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + if (NULL == quadrangle) + { + MEDIA_VISION_FUNCTION_LEAVE(); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + *minY = quadrangle->points[0].y; + *minY = quadrangle->points[1].y < *minY ? quadrangle->points[1].y : *minY; + *minY = quadrangle->points[2].y < *minY ? quadrangle->points[2].y : *minY; + *minY = quadrangle->points[3].y < *minY ? quadrangle->points[3].y : *minY; + + MEDIA_VISION_FUNCTION_LEAVE(); + + return MEDIA_VISION_ERROR_NONE; +} + +int find_max_x(const mv_quadrangle_s *quadrangle, int *maxX) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + if (NULL == quadrangle) + { + MEDIA_VISION_FUNCTION_LEAVE(); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + *maxX = quadrangle->points[0].x; + *maxX = quadrangle->points[1].x > *maxX ? quadrangle->points[1].x : *maxX; + *maxX = quadrangle->points[2].x > *maxX ? quadrangle->points[2].x : *maxX; + *maxX = quadrangle->points[3].x > *maxX ? quadrangle->points[3].x : *maxX; + + MEDIA_VISION_FUNCTION_LEAVE(); + + return MEDIA_VISION_ERROR_NONE; +} + +int find_max_y(const mv_quadrangle_s *quadrangle, int *maxY) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + if (NULL == quadrangle) + { + MEDIA_VISION_FUNCTION_LEAVE(); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + *maxY = quadrangle->points[0].y; + *maxY = quadrangle->points[1].y > *maxY ? quadrangle->points[1].y : *maxY; + *maxY = quadrangle->points[2].y > *maxY ? quadrangle->points[2].y : *maxY; + *maxY = quadrangle->points[3].y > *maxY ? quadrangle->points[3].y : *maxY; + + MEDIA_VISION_FUNCTION_LEAVE(); + + return MEDIA_VISION_ERROR_NONE; +} + +bool _mv_engine_config_supported_attribute(mv_config_attribute_type_e attribute_type, + const char *attribute_name, void *user_data) +{ + printf("Callback call for engine configuration attribute\n"); + + if (user_data == NULL) + { + return false; + } + + mv_engine_config_h mv_engine_config = (mv_engine_config_h *)user_data; + + int int_value = 0; + double double_value = 0.0; + bool bool_value = false; + char str_value[1024]; + switch (attribute_type) + { + case MV_ENGINE_CONFIG_ATTR_TYPE_DOUBLE: + if (MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE == + mv_engine_config_get_double_attribute( + mv_engine_config, attribute_name, &double_value)) + { + printf("Default double attribute %s wasn't set in engine\n", + attribute_name); + return false; + } + printf("Default double attribute %s was set to %f in engine\n", + attribute_name, double_value); + break; + case MV_ENGINE_CONFIG_ATTR_TYPE_INTEGER: + if (MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE == + mv_engine_config_get_int_attribute( + mv_engine_config, attribute_name, &int_value)) + { + printf("Default integer attribute %s wasn't set in engine\n", + attribute_name); + return false; + } + printf("Default interget attribute %s was set to %d in engine\n", + attribute_name, int_value); + break; + case MV_ENGINE_CONFIG_ATTR_TYPE_BOOLEAN: + if (MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE == + mv_engine_config_get_bool_attribute( + mv_engine_config, attribute_name, &bool_value)) + { + printf("Default bool attribute %s wasn't set in engine\n", + attribute_name); + return false; + } + printf("Default bool attribute %s was set to %s in engine\n", + attribute_name, bool_value ? "TRUE" : "FALSE"); + break; + case MV_ENGINE_CONFIG_ATTR_TYPE_STRING: + if (MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE == + mv_engine_config_get_string_attribute( + mv_engine_config, attribute_name, &str_value)) + { + printf("Default string ttribute %s wasn't set in engine\n", + attribute_name); + return false; + } + printf("Default string attribute %s was set to %s in engine\n", + attribute_name, str_value); + break; + default: + printf("Not supported attribute type\n"); + return false; + } + + + return true; +} + +void barcode_detected_cb( + mv_source_h source, + mv_engine_config_h engine_cfg, + const mv_quadrangle_s *barcodes_locations, + const char *messages[], + const mv_barcode_type_e *types, + int number_of_barcodes, + void *user_data) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + printf("%i barcodes were detected on the image.\n", number_of_barcodes); + if (number_of_barcodes > 0) + { + int is_source_data_loaded = 0; + + char *file_name = NULL; + unsigned char *out_buffer = NULL; + unsigned char *draw_buffer = NULL; + unsigned int buf_size = 0; + image_data_s image_data = { 0, 0, MEDIA_VISION_COLORSPACE_INVALID }; + // Check Media Vision source: + if (MEDIA_VISION_ERROR_NONE != mv_source_get_buffer(source, &out_buffer, &buf_size) || + MEDIA_VISION_ERROR_NONE != mv_source_get_width(source, &(image_data.image_width)) || + MEDIA_VISION_ERROR_NONE != mv_source_get_height(source, &(image_data.image_height)) || + MEDIA_VISION_ERROR_NONE != mv_source_get_colorspace(source, &(image_data.image_colorspace)) || + user_data == NULL) + { + printf("ERROR: Creating out image is impossible.\n"); + } + else + { + file_name = ((barcode_model_s *)user_data)->out_file_name; + draw_buffer = ((barcode_model_s *)user_data)->out_buffer_ptr; + image_data.image_colorspace = MEDIA_VISION_COLORSPACE_RGB888; + is_source_data_loaded = 1; + } + + int i = 0; + for (i = 0; i < number_of_barcodes; ++i) + { + const char *cur_message = messages[i]; + mv_barcode_type_e cur_type = types[i]; + const char *str_type = NULL; + switch (cur_type) + { + case MV_BARCODE_QR: + str_type = "QR"; + break; + case MV_BARCODE_UPC_A: + str_type = "UPC-A"; + break; + case MV_BARCODE_UPC_E: + str_type = "UPC-E"; + break; + case MV_BARCODE_EAN_8: + case MV_BARCODE_EAN_13: + str_type = "EAN-8/13"; + break; + case MV_BARCODE_CODE128: + str_type = "CODE128"; + break; + case MV_BARCODE_CODE39: + str_type = "CODE39"; + break; + case MV_BARCODE_I2_5: + str_type = "I25"; + break; + default: + str_type = "Undetected"; + break; + } + printf("\tBarcode %i : type is %s\n", i, str_type); + if (cur_message != NULL) + { + printf("\t message is %s\n", cur_message); + } + else + { + printf("\t message wasn't detected\n"); + } + + if (is_source_data_loaded == 1) + { + int minX = 0; + int minY = 0; + int maxX = 0; + int maxY = 0; + if (MEDIA_VISION_ERROR_NONE != find_min_x(&barcodes_locations[i], &minX) || + MEDIA_VISION_ERROR_NONE != find_min_y(&barcodes_locations[i], &minY) || + MEDIA_VISION_ERROR_NONE != find_max_x(&barcodes_locations[i], &maxX) || + MEDIA_VISION_ERROR_NONE != find_max_y(&barcodes_locations[i], &maxY)) + { + continue; + } + + const int rectangle_thickness = 6; + const int drawing_color[] = {255, 0, 0}; + if (MEDIA_VISION_ERROR_NONE != draw_rectangle_on_buffer( + minX, + minY, + maxX, + maxY, + drawing_color, + rectangle_thickness, + &image_data, + draw_buffer)) + { + continue; + } + } + } + + if (file_name != NULL && + MEDIA_VISION_ERROR_NONE == save_image_from_buffer(file_name, draw_buffer, &image_data, 100)) + { + printf("Image was generated as %s\n", file_name); + } + else + { + printf("ERROR: Failed to generate output file. Check file name and permissions. \n"); + } + + printf("\n"); + } + + MEDIA_VISION_FUNCTION_LEAVE(); +} + +int generate_barcode_to_image(barcode_model_s model) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + if (model.message == NULL || + model.file_name == NULL) + { + MEDIA_VISION_FUNCTION_LEAVE(); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + LOGI("Call the mv_barcode_generate_image() function"); + + const int err = mv_barcode_generate_image( + NULL, + model.message, + model.width, + model.height, + model.type, + model.mode, + model.ecc, + model.version, + model.file_name, + model.out_image_format); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; +} + +int generate_barcode_to_source(barcode_model_s model) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + if (model.message == NULL || + model.file_name == NULL) + { + MEDIA_VISION_FUNCTION_LEAVE(); + + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + LOGI("mv_source_h creation started"); + + mv_source_h source = NULL; + int err = mv_create_source(&source); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Error occurred when trying to create Media Vision " + "source. Error code: %i\n", err); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; + } + + LOGI("mv_source_h creation finished"); + + LOGI("Call the mv_barcode_generate_source() function"); + + err = mv_barcode_generate_source( + NULL, + model.message, + model.type, + model.mode, + model.ecc, + model.version, + source); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Error occurred during generation barcode to the " + "Media Vision source. Error code: %i\n", err); + + const int err2 = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf("ERROR: Error occurred when try to destroy Media Vision source." + "Error code: %i\n", err2); + } + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; + } + + unsigned char *data_buffer = NULL; + unsigned int buffer_size = 0; + unsigned int image_width = 0; + unsigned int image_height = 0; + mv_colorspace_e image_colorspace = MEDIA_VISION_COLORSPACE_INVALID; + + bool is_source_corrupted = false; + err = mv_source_get_buffer(source, &data_buffer, &buffer_size); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Error occurred when trying to get buffer from " + "Media Vision source. Error code: %i\n", err); + is_source_corrupted = true; + } + + err = mv_source_get_width(source, &image_width); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Error occurred when trying to get width of " + "Media Vision source. Error code: %i\n", err); + is_source_corrupted = true; + } + + err = mv_source_get_height(source, &image_height); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Error occurred when trying to get height of " + "Media Vision source. Error code: %i\n", err); + is_source_corrupted = true; + } + + err = mv_source_get_colorspace(source, &image_colorspace); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Error occurred when trying to get colorspace of " + "Media Vision source. Error code: %i\n", err); + is_source_corrupted = true; + } + + if (is_source_corrupted) + { + err = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Error occurred when trying to destroy Media Vision " + "source. Error code: %i\n", err); + } + + MEDIA_VISION_FUNCTION_LEAVE(); + + return MEDIA_VISION_ERROR_INTERNAL; + } + + const image_data_s image_data = { image_width, image_height, image_colorspace }; + + char *jpeg_file_name = ""; + if (0 == strcmp(model.file_name + strlen(model.file_name) - 4, ".jpg") || + 0 == strcmp(model.file_name + strlen(model.file_name) - 5, ".jpeg")) + { + jpeg_file_name = (char*)malloc(strlen(model.file_name) + 1); + strcpy(jpeg_file_name, model.file_name); + jpeg_file_name[strlen(model.file_name)] = '\0'; + } + else + { + jpeg_file_name = (char*)malloc(strlen(model.file_name) + 5); + strcpy(jpeg_file_name, model.file_name); + strcpy(jpeg_file_name + strlen(model.file_name), ".jpg"); + jpeg_file_name[strlen(model.file_name) + 4] = '\0'; + } + + save_image_from_buffer(jpeg_file_name, data_buffer, &image_data, 100); + + free(jpeg_file_name); + + const int err2 = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf("ERROR: Error occurred when try to destroy Media Vision source." + "Error code: %i\n", err2); + } + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; +} + +int detect_barcode(barcode_model_s model, mv_rectangle_s roi) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + unsigned char *data_buffer = NULL; + unsigned long buffer_size = 0; + image_data_s image_data; + + int err = load_image_to_buffer( + model.file_name, &data_buffer, &buffer_size, &image_data); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Errors were occurred during opening the file!!! code: %i\n", err); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; + } + + unsigned char *converted_buffer = NULL; + unsigned long converted_buffer_size = 0; + err = convert_rgb_to(data_buffer, &converted_buffer, image_data, model.colorspace, &converted_buffer_size); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Can't convert to the selected colorspace!!! code: %i\n", err); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; + } + + model.out_buffer_ptr = data_buffer; + + mv_engine_config_h mv_engine_config; + err = mv_create_engine_config(&mv_engine_config); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Errors were occurred during creating the media engine config: %i\n", err); + } + + mv_engine_config_foreach_supported_attribute(_mv_engine_config_supported_attribute, mv_engine_config); + + mv_engine_config_set_int_attribute(mv_engine_config, MV_BARCODE_DETECT_ATTR_TARGET, MV_BARCODE_DETECT_ATTR_TARGET_2D_BARCODE); + + mv_source_h source; + err = mv_create_source(&source); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Errors were occurred during creating the source!!! code: %i\n", err); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; + } + + err = mv_source_fill_by_buffer(source, converted_buffer, converted_buffer_size, + image_data.image_width, image_data.image_height, model.colorspace); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Errors were occurred during filling the source!!! code: %i\n", err); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; + } + + if (converted_buffer != NULL) + { + free(converted_buffer); + } + + err = mv_barcode_detect(source, mv_engine_config, roi, barcode_detected_cb, &model); + + if (data_buffer != NULL) + { + free(data_buffer); + } + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Errors were occurred during barcode detection!!! code: %i\n", err); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; + } + + err = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Errors were occurred during destroying the source!!! code: %i\n", err); + } + + err = mv_destroy_engine_config(mv_engine_config); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Error were occurred during destroying the source!!! code: %i\n", err); + } + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; +} + +int input_string(const char *prompt, size_t max_len, char **string) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + printf("\n"); + printf("%s ", prompt); + + if (scanf("\n") != 0) + { + MEDIA_VISION_FUNCTION_LEAVE(); + return -1; + } + + char buffer[max_len]; + int last_char = 0; + buffer[last_char] = '\0'; + buffer[sizeof(buffer) - 1] = ~'\0'; + if (fgets(buffer, sizeof(buffer), stdin) == NULL) + { + MEDIA_VISION_FUNCTION_LEAVE(); + return -1; + } + size_t real_string_len = strlen(buffer); + buffer[real_string_len - 1] = '\0'; + *string = (char*)malloc(real_string_len * sizeof(char)); + strcpy(*string, buffer); + + size_t str_len = strlen(*string); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return str_len; +} + +int input_size(const char *prompt, size_t max_size, size_t *size) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + printf("\n"); + printf("%s ", prompt); + + if (scanf("%20zu", size) == 0) + { + if (scanf("%*[^\n]%*c") != 0) + { + printf("ERROR: Reading the input line error.\n"); + MEDIA_VISION_FUNCTION_LEAVE(); + return -1; + } + printf("ERROR: Incorrect input.\n"); + MEDIA_VISION_FUNCTION_LEAVE(); + return -1; + } + + int ret = (*size > max_size ? -1 : 0); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int input_int(const char *prompt, int min_value, int max_value, int *value) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + printf("\n"); + printf("%s ", prompt); + + if (scanf("%20i", value) == 0) + { + if (scanf("%*[^\n]%*c") != 0) + { + printf("ERROR: Reading the input line error.\n"); + MEDIA_VISION_FUNCTION_LEAVE(); + return -1; + } + printf("ERROR: Incorrect input.\n"); + MEDIA_VISION_FUNCTION_LEAVE(); + return -1; + } + + int ret = (*value < min_value || *value > max_value ? -1 : 0); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret; +} + +int show_menu(const char *title, const int *options, const char **names, int cnt) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + printf("***************************\n"); + printf("* %23s *\n", title); + printf("*-------------------------*\n"); + int i = 0; + for (i = 0; i < cnt; ++i) + { + printf("* %2i. %19s *\n", options[i], names[i]); + } + printf("***************************\n\n"); + int selection = 0; + printf("Your choise: "); + if (scanf("%20i", &selection) == 0) + { + if (scanf("%*[^\n]%*c") != 0) + { + printf("ERROR: Reading the input line error.\n"); + MEDIA_VISION_FUNCTION_LEAVE(); + return -1; + } + printf("ERROR: Incorrect input.\n"); + } + + MEDIA_VISION_FUNCTION_LEAVE(); + + return selection; +} + +mv_barcode_type_e select_type(void) +{ + mv_barcode_type_e selected_type = MV_BARCODE_UNDEFINED; + int sel_opt = 0; + const int options[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + const char *names[8] = { "qr", "upca", "upce", "ean8", "ean13", "code39", "code128", "interleave25" }; + + MEDIA_VISION_FUNCTION_ENTER(); + + while (sel_opt == 0) + { + sel_opt = show_menu("Select barcode type:", options, names, 8); + + switch (sel_opt) + { + case 1: + selected_type = MV_BARCODE_QR; + break; + case 2: + selected_type = MV_BARCODE_UPC_A; + break; + case 3: + selected_type = MV_BARCODE_UPC_E; + break; + case 4: + selected_type = MV_BARCODE_EAN_8; + break; + case 5: + selected_type = MV_BARCODE_EAN_13; + break; + case 6: + selected_type = MV_BARCODE_CODE39; + break; + case 7: + selected_type = MV_BARCODE_CODE128; + break; + case 8: + selected_type = MV_BARCODE_I2_5; + break; + default: + sel_opt = 0; + break; + } + } + + MEDIA_VISION_FUNCTION_LEAVE(); + + return selected_type; +} + +mv_barcode_qr_mode_e select_mode(void) +{ + mv_barcode_qr_mode_e selected_mode = MV_BARCODE_QR_MODE_UNAVAILABLE; + int sel_opt = 0; + const int options[4] = { 1, 2, 3, 4 }; + const char *names[4] = { "numeric", "alphanumeric", "byte", "utf8" }; + + MEDIA_VISION_FUNCTION_ENTER(); + + while (sel_opt == 0) + { + sel_opt = show_menu("Select encoding mode:", options, names, 4); + switch (sel_opt) + { + case 1: + selected_mode = MV_BARCODE_QR_MODE_NUMERIC; + break; + case 2: + selected_mode = MV_BARCODE_QR_MODE_ALPHANUMERIC; + break; + case 3: + selected_mode = MV_BARCODE_QR_MODE_BYTE; + break; + case 4: + selected_mode = MV_BARCODE_QR_MODE_UTF8; + break; + default: + sel_opt = 0; + break; + } + } + + MEDIA_VISION_FUNCTION_LEAVE(); + + return selected_mode; +} + +mv_barcode_qr_ecc_e select_ecc(void) +{ + mv_barcode_qr_ecc_e selected_ecc = MV_BARCODE_QR_ECC_UNAVAILABLE; + int sel_opt = 0; + const int options[4] = { 1, 2, 3, 4 }; + const char *names[4] = { "low", "medium", "quartile", "high" }; + + MEDIA_VISION_FUNCTION_ENTER(); + + while (sel_opt == 0) + { + sel_opt = show_menu("Select ECC level:", options, names, 4); + switch (sel_opt) + { + case 1: + selected_ecc = MV_BARCODE_QR_ECC_LOW; + break; + case 2: + selected_ecc = MV_BARCODE_QR_ECC_MEDIUM; + break; + case 3: + selected_ecc = MV_BARCODE_QR_ECC_QUARTILE; + break; + case 4: + selected_ecc = MV_BARCODE_QR_ECC_HIGH; + break; + default: + sel_opt = 0; + break; + } + } + + MEDIA_VISION_FUNCTION_LEAVE(); + + return selected_ecc; +} + +int select_version(void) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + int sel_opt = 0; + while (sel_opt == 0) + { + const int options[2] = {1, 40}; + const char *names[2] = { "1..", "..40" }; + sel_opt = show_menu("Select QR version:", options, names, 2); + if (sel_opt < 1 || sel_opt > 40) + { + sel_opt = 0; + } + } + + MEDIA_VISION_FUNCTION_LEAVE(); + + return sel_opt; +} + +generation_fcn_e select_gen_function(void) +{ + generation_fcn_e ret_fcn_type = MV_TS_GENERATE_TO_IMAGE_FCN; + int sel_opt = 0; + const int options[2] = { 1, 2 }; + const char *names[2] = { "Generate to file", "Generate to source" }; + + MEDIA_VISION_FUNCTION_ENTER(); + + while (sel_opt == 0) + { + sel_opt = show_menu("Select API function:", options, names, 2); + switch (sel_opt) + { + case 1: + ret_fcn_type = MV_TS_GENERATE_TO_IMAGE_FCN; + break; + case 2: + ret_fcn_type = MV_TS_GENERATE_TO_SOURCE_FCN; + break; + default: + sel_opt = 0; + break; + } + } + + MEDIA_VISION_FUNCTION_LEAVE(); + + return ret_fcn_type; +} + +mv_barcode_image_format_e select_file_format(void) +{ + mv_barcode_image_format_e image_format = MV_BARCODE_IMAGE_FORMAT_JPG; + int sel_opt = 0; + const int options[3] = { 1, 2, 3 }; + const char *names[3] = { "BMP", "JPG", "PNG" }; + + MEDIA_VISION_FUNCTION_ENTER(); + + while (sel_opt == 0) + { + sel_opt = show_menu("Select file format:", options, names, 3); + switch (sel_opt) + { + case 1: + image_format = MV_BARCODE_IMAGE_FORMAT_BMP; + break; + case 2: + image_format = MV_BARCODE_IMAGE_FORMAT_JPG; + break; + case 3: + image_format = MV_BARCODE_IMAGE_FORMAT_PNG; + break; + default: + sel_opt = 0; + break; + } + } + + MEDIA_VISION_FUNCTION_LEAVE(); + + return image_format; +} + +int perform_detect() +{ + MEDIA_VISION_FUNCTION_ENTER(); + + barcode_model_s detect_model = { + MV_BARCODE_UNDEFINED, + MV_BARCODE_QR_ECC_UNAVAILABLE, + MV_BARCODE_QR_MODE_UNAVAILABLE, + 0, 0, 0, + MV_BARCODE_IMAGE_FORMAT_PNG, + MEDIA_VISION_COLORSPACE_INVALID, + NULL, NULL, NULL, NULL }; + + while (input_string("Input file name to be analyzed:", 1024, &(detect_model.file_name)) == -1) + { + printf("Incorrect input! Try again.\n"); + } + LOGI("Barcode input image has been specified"); + + mv_rectangle_s roi = { {0, 0}, 0, 0 }; + + while (input_int("Input x coordinate for ROI top left vertex:", 0, 10000, &(roi.point.x)) == -1) + { + printf("Incorrect input! Try again.\n"); + } + + while (input_int("Input y coordinate for ROI top left vertex:", 0, 10000, &(roi.point.y)) == -1) + { + printf("Incorrect input! Try again.\n"); + } + + while (input_int("Input ROI width:", 0, 10000, &(roi.width)) == -1) + { + printf("Incorrect input! Try again.\n"); + } + + while (input_int("Input ROI height:", 0, 10000, &(roi.height)) == -1) + { + printf("Incorrect input! Try again.\n"); + } + LOGI("Region of interest (ROI) to detect barcode into has been specified"); + + while (input_string("Input file name to be generated:", 1024, &(detect_model.out_file_name)) == -1) + { + printf("Incorrect input! Try again.\n"); + } + LOGI("Barcode output image has been specified"); + + const int options[11] = { MEDIA_VISION_COLORSPACE_Y800, + MEDIA_VISION_COLORSPACE_I420, + MEDIA_VISION_COLORSPACE_NV12, + MEDIA_VISION_COLORSPACE_YV12, + MEDIA_VISION_COLORSPACE_NV21, + MEDIA_VISION_COLORSPACE_YUYV, + MEDIA_VISION_COLORSPACE_UYVY, + MEDIA_VISION_COLORSPACE_422P, + MEDIA_VISION_COLORSPACE_RGB565, + MEDIA_VISION_COLORSPACE_RGB888, + MEDIA_VISION_COLORSPACE_RGBA }; + const char *names[11] = { "Y800", "I420", "NV12", "YV12", "NV21", + "YUYV", "UYVY", "422P", "RGB565", + "RGB888", "RGBA" }; + + while (true) + { + int sel_opt = show_menu("Select colorspace to test detector on:", options, names, 11); + if (sel_opt < MEDIA_VISION_COLORSPACE_Y800 || + sel_opt > MEDIA_VISION_COLORSPACE_RGBA) + { + continue; + } + detect_model.colorspace = (mv_colorspace_e)sel_opt; + LOGI("User selection is %i", sel_opt); + break; + } + + int err = detect_barcode(detect_model, roi); + + if (detect_model.file_name != NULL) + { + free(detect_model.file_name); + } + + if (detect_model.out_file_name != NULL) + { + free(detect_model.out_file_name); + } + + if (err != MEDIA_VISION_ERROR_NONE) + { + LOGE("Barcode detection failed with error code (0x%08x)", err); + } + + + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; +} + +int perform_generate(void) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + barcode_model_s generate_model = { + MV_BARCODE_UNDEFINED, + MV_BARCODE_QR_ECC_UNAVAILABLE, + MV_BARCODE_QR_MODE_UNAVAILABLE, + 0, 0, 0, + MV_BARCODE_IMAGE_FORMAT_PNG, + MEDIA_VISION_COLORSPACE_INVALID, + NULL, NULL, NULL, NULL }; + + generation_fcn_e gen_fcn = select_gen_function(); + generate_model.type = select_type(); + LOGI("Barcode type has been selected"); + + if (generate_model.type == MV_BARCODE_QR) + { + generate_model.mode = select_mode(); + LOGI("Barcode encoding mode has been selected"); + generate_model.ecc = select_ecc(); + LOGI("Barcode ecc level has been selected"); + generate_model.version = select_version(); + LOGI("Barcode version has been selected"); + } + + if (gen_fcn == MV_TS_GENERATE_TO_IMAGE_FCN) + { + generate_model.out_image_format = select_file_format(); + LOGI("Barcode output image format has been selected"); + } + + while (input_string("Input message:", 7089, &generate_model.message) == -1) + { + printf("Incorrect input! Try again.\n"); + } + LOGI("Barcode message has been specified"); + + while (input_string("Input file name:", 1024, &generate_model.file_name) == -1) + { + printf("Incorrect input! Try again.\n"); + } + LOGI("Barcode output file name has been specified"); + + if (gen_fcn == MV_TS_GENERATE_TO_IMAGE_FCN) + { + while (input_size("Input image width:", 10000, &generate_model.width) == -1) + { + printf("Incorrect input! Try again.\n"); + } + LOGI("Barcode output file width has been specified"); + + while (input_size("Input image height:", 10000, &generate_model.height) == -1) + { + printf("Incorrect input! Try again.\n"); + } + LOGI("Barcode output file height has been specified"); + } + + const int err = + gen_fcn == MV_TS_GENERATE_TO_IMAGE_FCN ? + generate_barcode_to_image(generate_model) : + generate_barcode_to_source(generate_model); + + if (generate_model.message != NULL) + { + free(generate_model.message); + } + + if (generate_model.file_name != NULL) + { + free(generate_model.file_name); + } + + if (err != MEDIA_VISION_ERROR_NONE) + { + LOGE("Barcode generation failed with error code (0x%08x)", err); + printf("ERROR: Errors were occurred during barcode generation!!!\n"); + MEDIA_VISION_FUNCTION_LEAVE(); + return err; + } + + LOGI("Barcode output file has been generated"); + printf("\nBarcode image was successfully generated.\n"); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return 0; +} + +int main(void) +{ + LOGI("Media Vision Testsuite is launched."); + + int err = MEDIA_VISION_ERROR_NONE; + + int sel_opt = 0; + const int options[2] = { 1, 2 }; + const char *names[2] = { "Generate", "Detect" }; + + while (sel_opt == 0) + { + sel_opt = show_menu("Select action:", options, names, 2); + switch (sel_opt) + { + case 1: + LOGI("Start the barcode generation flow"); + err = perform_generate(); + break; + case 2: + LOGI("Start the barcode detection flow"); + err = perform_detect(); + break; + default: + sel_opt = 0; + continue; + } + + int do_another = 0; + + if (err != MEDIA_VISION_ERROR_NONE) + { + printf("ERROR: Action is finished with error code: %i\n", err); + } + + sel_opt = 0; + const int options_last[2] = { 1, 2 }; + const char *names_last[2] = { "YES", "NO" }; + + while (sel_opt == 0) + { + sel_opt = show_menu("Perform another action?", options_last, names_last, 2); + switch (sel_opt) + { + case 1: + do_another = 1; + break; + case 2: + do_another = 0; + break; + default: + sel_opt = 0; + break; + } + } + LOGI("User selection is %i", sel_opt); + + sel_opt = (do_another == 1 ? 0 : sel_opt); + } + + LOGI("Media Vision Testsuite is closed."); + + return err; +} diff --git a/test/testsuites/common/CMakeLists.txt b/test/testsuites/common/CMakeLists.txt new file mode 100644 index 0000000..e62cc2a --- /dev/null +++ b/test/testsuites/common/CMakeLists.txt @@ -0,0 +1,6 @@ +project(mv_testsuites_common) +cmake_minimum_required(VERSION 2.6) + +add_subdirectory(${PROJECT_SOURCE_DIR}/image_helper) +add_subdirectory(${PROJECT_SOURCE_DIR}/video_helper) +add_subdirectory(${PROJECT_SOURCE_DIR}/testsuite_common) diff --git a/test/testsuites/common/image_helper/CMakeLists.txt b/test/testsuites/common/image_helper/CMakeLists.txt new file mode 100644 index 0000000..a89a88a --- /dev/null +++ b/test/testsuites/common/image_helper/CMakeLists.txt @@ -0,0 +1,37 @@ +project(mv_image_helper) +cmake_minimum_required(VERSION 2.6) + +set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG _DEBUG) + +if(NOT SKIP_WARNINGS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_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") + +file(GLOB MV_IMAGE_HELPER_INCLUDE_LIST "${PROJECT_SOURCE_DIR}/include/*.h") +file(GLOB MV_IMAGE_HELPER_SRC_LIST "${PROJECT_SOURCE_DIR}/src/*.c" + "${PROJECT_SOURCE_DIR}/src/*.cpp") + +find_package(OpenCV REQUIRED core highgui imgproc) + +if(NOT OpenCV_FOUND) + message(SEND_ERROR "Failed to find OpenCV") + return() +else() + include_directories(${OpenCV_INCLUDE_DIRS}) +endif() + +if(FORCED_STATIC_BUILD) + add_library(${PROJECT_NAME} STATIC ${MV_IMAGE_HELPER_INCLUDE_LIST} ${MV_IMAGE_HELPER_SRC_LIST}) +else() + add_library(${PROJECT_NAME} SHARED ${MV_IMAGE_HELPER_INCLUDE_LIST} ${MV_IMAGE_HELPER_SRC_LIST}) +endif() + +TARGET_LINK_LIBRARIES(${PROJECT_NAME} jpeg ${OpenCV_LIBS}) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}) diff --git a/test/testsuites/common/image_helper/include/ImageHelper.h b/test/testsuites/common/image_helper/include/ImageHelper.h new file mode 100644 index 0000000..e9eabcc --- /dev/null +++ b/test/testsuites/common/image_helper/include/ImageHelper.h @@ -0,0 +1,247 @@ +/** + * 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 __IMAGEHELPER_H__ +#define __IMAGEHELPER_H__ + +#include "mv_common.h" + +#include +#include + +#include + +/** + * @file ImageHelper.h + * @brief ImageHelper class definition. + */ + +namespace cv +{ + template class Scalar_; + typedef Scalar_ Scalar; + + class VideoCapture; + class VideoWriter; +} + +namespace MediaVision +{ +namespace Common +{ + +/** + * @class ImageHelper + * @brief Helper class that provides set of useful methods + * for image management. + */ +class ImageHelper +{ +public: + /** + * @brief Structure to keep information about width, height and colorspace of an image. + */ + struct ImageData + { + unsigned int imageWidth; /**< Image width */ + unsigned int imageHeight; /**< Image height */ + mv_colorspace_e imageColorspace; /**< Image colorspace */ + }; + + /** + * @brief Loads image from file to the buffer of unsigned chars. + * + * @since_tizen 3.0 + * @param [in] filePath Path to the image file to be loaded to the + * @a pDataBuffer + * @param [out] pDataBuffer The buffer of unsigned chars where image data + * will be stored + * @param [out] pBufferSize The size of the @a pDataBuffer + * @param [out] pImageData The image data (structure that keeps + * information about image width, height, + * and colorspace) + * @return @c 0 on success, otherwise a negative error value + * + * @see ImageHelper::saveImageFromBuffer() + */ + static int loadImageToBuffer( + const char *filePath, + unsigned char **pDataBuffer, + unsigned long *pBufferSize, + ImageData *pImageData); + + /** + * @brief Saves image stored into @a pDataBuffer to the file in jpeg format. + * + * @since_tizen 3.0 + * @param [in] filePath The path to the file where image will be saved + * @param [in] pDataBuffer Data buffer that contains image data + * @param [in] imageData The image data (structure that keeps + * information about image width, height, + * and colorspace) + * @param [in] quality Quality for the output jpeg file (0..100) + * @return @c 0 on success, otherwise a negative error value + * + * @see ImageHelper::loadImageToBuffer() + */ + static int saveImageFromBuffer( + const char *filePath, + unsigned char *pDataBuffer, + const ImageData& imageData, + int quality = 100); + + /** + * @brief Draws the rectangle of specified size on the image data buffer. + * + * @since_tizen 3.0 + * @param [in] topLeftVertexX The rectangle top left corner + * x coordinate + * @param [in] topLeftVertexY The rectangle top left corner + * y coordinate + * @param [in] bottomRightVertexX The rectangle bottom right corner + * x coordinate + * @param [in] bottomRightVertexY The rectangle bottom right corner + * y coordinate + * @param [in] thickness The thickness of the rectangle border + * (negative value to draw filled rectangle) + * @param [in] color The color of the rectangle border + * @param [in] imageData The image data (structure that keeps + * information about image width, height, + * and colorspace). Colorspace has to be + * @c MEDIA_VISION_COLORSPACE_RGB888 + * @param [in, out] pDataBuffer The pointer to the image data buffer + * which will be used for rectangle drawing + * @return @c 0 on success, otherwise a negative error value + */ + static int drawRectangleOnBuffer( + int topLeftVertexX, + int topLeftVertexY, + int bottomRightVertexX, + int bottomRightVertexY, + int thickness, + const cv::Scalar& color, + const ImageData& imageData, + unsigned char *pDataBuffer); + + /** + * @brief Draws the quadrangle of specified size on the image data buffer. + * + * @since_tizen 3.0 + * @param [in] location The quadrangle structure + * @param [in] thickness The thickness of the quadrangle border + * @param [in] color The color of the quadrangle border + * @param [in] imageData The image data (structure that keeps + * information about image width, height, + * and colorspace). Colorspace has to be + * @c MEDIA_VISION_COLORSPACE_RGB888 + * @param [in, out] pDataBuffer The pointer to the image data buffer + * which will be used for quadrangle drawing + * @return @c 0 on success, otherwise a negative error value + */ + static int drawQuadrangleOnBuffer( + mv_quadrangle_s location, + int thickness, + const cv::Scalar& color, + const ImageData& imageData, + unsigned char *pDataBuffer); + + /** + * @brief Convers libjpeg colorspace to the Tizen 'image util' colorspace. + * + * @since_tizen 3.0 + * @param [in] inColorspace The libjpeg colorspace to be converted. + * @param [out] pOutColorspace The Tizen 'image util' colorspace that + * will be obtained after conversion + * @return @c 0 on success, otherwise a negative error value + * + * @see ImageHelper::convertMVColorspaceToJpeglibColorspace() + */ + static int convertJpeglibColorspaceToMVColorspace( + J_COLOR_SPACE inColorspace, + mv_colorspace_e *pOutColorspace); + + /** + * @brief Convers libjpeg colorspace to the Tizen image util colorspace. + * + * @since_tizen 3.0 + * @param [in] inColorspace The Tizen 'image util' colorspace to be + * converted + * @param [out] pOutColorspace The libjpeg colorspace that will be + * obtained after conversion + * @return @c 0 on success, otherwise a negative error value + * + * @see ImageHelper::convertJpeglibColorspaceToMVColorspace() + */ + static int convertMVColorspaceToJpeglibColorspace( + mv_colorspace_e inColorspace, + J_COLOR_SPACE *pOutColorspace); + + /** + * @brief Converts image data to the image data of RGB888 colorspace. + * + * @since_tizen 3.0 + * @param [in] pInBuffer Buffer with image data to be converted to + * RGB888 colorspace + * @param [in] imageData The image data (structure that keeps + * information about image width, height, + * and colorspace) for source image + * @param [out] pOutBuffer Buffer with image data to be generated as + * a result of the conversion + * @return @c 0 on success, otherwise a negative error value + */ + static int convertBufferToRGB888( + const unsigned char *pInBuffer, + const ImageData& imageData, + unsigned char **pOutBuffer); + + /** + * @brief Determines number of channels (components) for the colorspace. + * + * @since_tizen 3.0 + * @param [in] colorspace Colorspace for which number of + * components will be determined + * @param [out] pComponentsNumber Number of components to be determined + * @return @c 0 on success, otherwise a negative error value + */ + static int getNumberOfComponents( + mv_colorspace_e colorspace, + int *pComponentsNumber); + +private: + /** + * @brief Converts buffer with image data in Y800 colorspace format + * to the buffer with image data in RGB888 colorspace format. + * + * @since_tizen 3.0 + * @param [in] pInBuffer The buffer with data in Y800 colorspace format + * @param [in] imageData The image data (structure that keeps + * information about image width, height, and + * colorspace) for source buffer + * @param [out] pOutBuffer The buffer that will contain converted image + * data in RGB888 colorspace format + * @return @c 0 on success, otherwise a negative error value + */ + static int convertY800ToRGB( + const unsigned char *pInBuffer, + const ImageData& imageData, + unsigned char **pOutBuffer); + +}; + +} /* namespace Common */ +} /* namespace MediaVision */ + +#endif /* __IMAGEHELPER_H__ */ diff --git a/test/testsuites/common/image_helper/include/image_helper.h b/test/testsuites/common/image_helper/include/image_helper.h new file mode 100644 index 0000000..bef34be --- /dev/null +++ b/test/testsuites/common/image_helper/include/image_helper.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 __IMAGE_HELPER_H__ +#define __IMAGE_HELPER_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "mv_common.h" + +#ifdef __cplusplus +#include +#include +#else +#include +#include +#endif + +#include + +/** + * @file image_helper.h + * @brief Helper functions that provides set of useful methods for image management + * (c wrapper of ImageHelper class). + */ + +/** + * @brief Structure to keep information about width, height and colorspace of an image. + * + * @since_tizen 3.0 + */ +typedef struct +{ + unsigned int image_width; /**< Image width */ + unsigned int image_height; /**< Image height */ + mv_colorspace_e image_colorspace; /**< Image colorspace */ +} image_data_s; + +/** + * @brief Loads image from file to the buffer of unsigned chars. + * + * @since_tizen 3.0 + * @param [in] file_path Path to the image file to be loaded to the + * @a pDataBuffer + * @param [out] data_buffer The buffer of unsigned chars where image data + * will be stored + * @param [out] buffer_size The size of the @a pDataBuffer + * @param [out] image_data The image data (structure that keeps + * information about image width, height, + * and colorspace) + * @return @c 0 on success, otherwise a negative error value + * + * @see save_image_from_buffer() + */ +int load_image_to_buffer( + const char *file_path, + unsigned char **data_buffer, + unsigned long *buffer_size, + image_data_s *image_data); + +/** + * @brief Saves image stored into @a pDataBuffer to the file in jpeg format. + * + * @since_tizen 3.0 + * @param [in] file_path The path to the file where image will be saved + * @param [in] data_buffer Data buffer that contains image data + * @param [in] image_data The image data (structure that keeps + * information about image width, height, + * and colorspace) + * @param [in] quality Quality for the output jpeg file (0..100) + * @return @c 0 on success, otherwise a negative error value + * + * @see load_image_to_buffer() + */ +int save_image_from_buffer( + const char *file_path, + unsigned char *data_buffer, + const image_data_s *image_data, + int quality); + +/** + * @brief Draws the rectangle of specified size on the image data buffer. + * + * @since_tizen 3.0 + * @param [in] tl_vertex_x The rectangle top left corner x coordinate + * @param [in] tl_vertex_y The rectangle top left corner y coordinate + * @param [in] br_vertex_x The rectangle bottom right corner x coordinate + * @param [in] br_vertex_y The rectangle bottom right corner y coordinate + * @param [in] thickness The thickness of the rectangle border (negative + * value to draw filled rectangle) + * @param [in] rgb_color The color of the rectangle border + * @param [in] image_data The image data (structure that keeps information + * about image width, height, and colorspace). + * Colorspace has to be @c MEDIA_VISION_COLORSPACE_RGB888 + * @param [in, out] data_buffer The pointer to the image data buffer which will + * be used for rectangle drawing + * @return @c 0 on success, otherwise a negative error value + */ +int draw_rectangle_on_buffer( + int tl_vertex_x, + int tl_vertex_y, + int br_vertex_x, + int br_vertex_y, + int thickness, + const int rgb_color[3], + const image_data_s *image_data, + unsigned char *data_buffer); + +/** + * @brief Draws the quadrangle of specified size on the image data buffer. + * + * @since_tizen 3.0 + * @param [in] location The quadrangle structure + * @param [in] thickness The thickness of the quadrangle border + * @param [in] rgb_color The color of the quadrangle border + * @param [in] image_data The image data (structure that keeps information + * about image width, height, and colorspace). + * Colorspace has to be @c MEDIA_VISION_COLORSPACE_RGB888 + * @param [in, out] data_buffer The pointer to the image data buffer which will + * be used for quadrangle drawing + * @return @c 0 on success, otherwise a negative error value + */ +int draw_quadrangle_on_buffer( + mv_quadrangle_s location, + int thickness, + const int rgb_color[3], + const image_data_s *image_data, + unsigned char *data_buffer); + +/** + * @brief Converts libjpeg colorspace to the Tizen 'image util' colorspace. + * + * @since_tizen 3.0 + * @param [in] in_colorspace The libjpeg colorspace to be converted. + * @param [out] out_colorspace The Tizen 'image util' colorspace that + * will be obtained after conversion + * @return @c 0 on success, otherwise a negative error value + * + * @see convert_mv_colorspace_to_jpeglib_colorspace() + */ +int convert_jpeglib_colorspace_to_mv_colorspace( + J_COLOR_SPACE in_colorspace, + mv_colorspace_e *out_colorspace); + +/** + * @brief Converts libjpeg colorspace to the Tizen image util colorspace. + * + * @since_tizen 3.0 + * @param [in] in_colorspace The Tizen 'image util' colorspace to be + * converted + * @param [out] out_colorspace The libjpeg colorspace that will be + * obtained after conversion + * @return @c 0 on success, otherwise a negative error value + * + * @see convert_jpeglib_colorspace_to_mv_colorspace() + */ +int convert_mv_colorspace_to_jpeglib_colorspace( + mv_colorspace_e in_colorspace, + J_COLOR_SPACE *out_colorspace); + +/** + * @brief Converts image data to the image data of RGB888 colorspace. + * + * @since_tizen 3.0 + * @param [in] in_buffer Buffer with image data to be converted to + * RGB888 colorspace + * @param [in] image_data The image data (structure that keeps + * information about image width, height, + * and colorspace) for source image + * @param [out] out_buffer Buffer with image data to be generated as + * a result of the conversion + * @return @c 0 on success, otherwise a negative error value + */ +int convert_buffer_to_RGB888( + const unsigned char *in_buffer, + const image_data_s *image_data, + unsigned char **out_buffer); + +/** + * @brief Determines number of channels (components) for the colorspace. + * + * @since_tizen 3.0 + * @param [in] colorspace Colorspace for which number of + * components will be determined + * @param [out] components_number Number of components to be determined + * @return @c 0 on success, otherwise a negative error value + */ +int get_number_of_components( + mv_colorspace_e colorspace, + int *components_number); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __IMAGE_HELPER_H__*/ diff --git a/test/testsuites/common/image_helper/src/ImageHelper.cpp b/test/testsuites/common/image_helper/src/ImageHelper.cpp new file mode 100644 index 0000000..e6b0a54 --- /dev/null +++ b/test/testsuites/common/image_helper/src/ImageHelper.cpp @@ -0,0 +1,392 @@ +/** + * 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 "ImageHelper.h" +#include "mv_private.h" + +#include + +#include + +#include + +#include +#include +#include + +/** + * @file ImageHelper.cpp + * @brief The ImageHelper class methods implementation. + */ + +namespace MediaVision +{ +namespace Common +{ + +namespace +{ + +static const int OpenCVChannels = 3; +static const mv_colorspace_e OpenCVColor = MEDIA_VISION_COLORSPACE_RGB888; +static const int QuadrangleVertices = 4; + +std::vector getJPGExtensions() +{ + std::vector extensions; + extensions.push_back(".jpg"); + extensions.push_back(".jpe"); + extensions.push_back(".jpeg"); + return extensions; +} + +} /* anonymous namespace */ + +int ImageHelper::loadImageToBuffer( + const char *filePath, + unsigned char **pDataBuffer, + unsigned long *pBufferSize, + ImageData *pImageData) +{ + if (filePath == NULL || pDataBuffer == NULL || + pBufferSize == NULL || pImageData == NULL) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + cv::Mat image; + image = cv::imread(filePath); + + if (!image.data) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + cv::cvtColor(image, image, CV_BGR2RGB); + + *pBufferSize = image.total() * image.elemSize(); + (*pDataBuffer) = new unsigned char[*pBufferSize]; + std::memcpy(*pDataBuffer, image.data, *pBufferSize); + + pImageData->imageWidth = image.cols; + pImageData->imageHeight = image.rows; + pImageData->imageColorspace = OpenCVColor; + + return MEDIA_VISION_ERROR_NONE; +} + +int ImageHelper::saveImageFromBuffer( + const char *filePath, + unsigned char *pDataBuffer, + const ImageData& imageData, + int quality) +{ + if (filePath == NULL || pDataBuffer == NULL) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + static const std::string defaultFilePath = "out"; + static const std::vector jpgExtensions = getJPGExtensions(); + + bool rightExtensionFlag = false; + + std::string resultFilePath(filePath); + if (resultFilePath.empty()) + { + resultFilePath = defaultFilePath; + } + else + { + for (size_t extNum = 0; extNum < jpgExtensions.size(); ++extNum) + { + if (resultFilePath.size() >= jpgExtensions[extNum].size()) + { + std::string givenExtension = resultFilePath.substr( + resultFilePath.length() - jpgExtensions[extNum].size(), + jpgExtensions[extNum].size()); + + std::transform( + givenExtension.begin(), givenExtension.end(), + givenExtension.begin(), ::tolower); + + if (givenExtension == jpgExtensions[extNum]) + { + rightExtensionFlag = true; + break; + } + } + } + } + if (!rightExtensionFlag) + { + resultFilePath += jpgExtensions[0]; + } + + if (quality <= 0 || quality > 100) + { + quality = 100; + } + + unsigned int width = imageData.imageWidth; + unsigned int height = imageData.imageHeight; + + int conversionType = -1; // Type of conversion from given colorspace to BGR + unsigned int channelsNumber = 0; + switch (imageData.imageColorspace) + { + case MEDIA_VISION_COLORSPACE_INVALID: + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + case MEDIA_VISION_COLORSPACE_Y800: + channelsNumber = 1; + conversionType = CV_GRAY2BGR; + break; + case MEDIA_VISION_COLORSPACE_I420: + channelsNumber = 1; + height *= 1.5; + conversionType = CV_YUV2BGR_I420; + break; + case MEDIA_VISION_COLORSPACE_NV12: + channelsNumber = 1; + height *= 1.5; + conversionType = CV_YUV2BGR_NV12; + break; + case MEDIA_VISION_COLORSPACE_YV12: + channelsNumber = 1; + height *= 1.5; + conversionType = CV_YUV2BGR_YV12; + break; + case MEDIA_VISION_COLORSPACE_NV21: + channelsNumber = 1; + height *= 1.5; + conversionType = CV_YUV2BGR_NV21; + break; + case MEDIA_VISION_COLORSPACE_YUYV: + channelsNumber = 2; + conversionType = CV_YUV2BGR_YUYV; + break; + case MEDIA_VISION_COLORSPACE_UYVY: + channelsNumber = 2; + conversionType = CV_YUV2BGR_UYVY; + break; + case MEDIA_VISION_COLORSPACE_422P: + channelsNumber = 2; + conversionType = CV_YUV2BGR_Y422; + break; + case MEDIA_VISION_COLORSPACE_RGB565: + channelsNumber = 2; + conversionType = CV_BGR5652BGR; + break; + case MEDIA_VISION_COLORSPACE_RGB888: + channelsNumber = 3; + conversionType = CV_RGB2BGR; + break; + case MEDIA_VISION_COLORSPACE_RGBA: + channelsNumber = 4; + conversionType = CV_RGBA2BGR; + break; + default: + return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT; + } + + const int depth = CV_8U; + cv::Mat cvImage(cv::Size(width, height), + CV_MAKETYPE(depth, channelsNumber), pDataBuffer); + cv::Mat cvBGRImage; + cv::cvtColor(cvImage, cvBGRImage, conversionType); + + std::vector compression_params(2); + compression_params[0] = CV_IMWRITE_JPEG_QUALITY; + compression_params[1] = quality; + + if (!cv::imwrite(resultFilePath, cvBGRImage, compression_params)) + { + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + return MEDIA_VISION_ERROR_NONE; +} + +int ImageHelper::drawRectangleOnBuffer( + int topLeftVertexX, + int topLeftVertexY, + int bottomRightVertexX, + int bottomRightVertexY, + int thickness, + const cv::Scalar& color, + const ImageData& imageData, + unsigned char *pDataBuffer) +{ + if (NULL == pDataBuffer) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + cv::Mat cvImage(imageData.imageHeight, imageData.imageWidth, CV_8UC(OpenCVChannels), pDataBuffer); + cv::rectangle( + cvImage, + cv::Point(topLeftVertexX, topLeftVertexY), + cv::Point(bottomRightVertexX, bottomRightVertexY), + color, + thickness); + + return MEDIA_VISION_ERROR_NONE; +} + +int ImageHelper::drawQuadrangleOnBuffer( + mv_quadrangle_s location, + int thickness, + const cv::Scalar& color, + const ImageData& imageData, + unsigned char *pDataBuffer) +{ + if (NULL == pDataBuffer) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + cv::Mat cvImage(imageData.imageHeight, imageData.imageWidth, CV_8UC(OpenCVChannels), pDataBuffer); + for (int i = 0; i < QuadrangleVertices; ++i) + { + cv::line( + cvImage, + cv::Point(location.points[i].x, location.points[i].y), + cv::Point(location.points[(i + 1) % QuadrangleVertices].x, + location.points[(i + 1) % QuadrangleVertices].y), + color, + thickness); + } + return MEDIA_VISION_ERROR_NONE; +} + +int ImageHelper::convertJpeglibColorspaceToMVColorspace( + J_COLOR_SPACE inColorspace, + mv_colorspace_e *pOutColorspace) +{ + if (pOutColorspace == NULL) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + switch(inColorspace) + { + case JCS_GRAYSCALE: + (*pOutColorspace) = MEDIA_VISION_COLORSPACE_Y800; + return MEDIA_VISION_ERROR_NONE; + case JCS_RGB: + (*pOutColorspace) = MEDIA_VISION_COLORSPACE_RGB888; + return MEDIA_VISION_ERROR_NONE; + default: + return MEDIA_VISION_ERROR_NOT_SUPPORTED; + } + + return MEDIA_VISION_ERROR_NONE; +} + +int ImageHelper::convertMVColorspaceToJpeglibColorspace( + mv_colorspace_e inColorspace, + J_COLOR_SPACE *pOutColorspace) +{ + // todo: support more colorspaces: + switch (inColorspace) + { + case MEDIA_VISION_COLORSPACE_Y800: + (*pOutColorspace) = JCS_GRAYSCALE; + return MEDIA_VISION_ERROR_NONE; + case MEDIA_VISION_COLORSPACE_RGB888: + (*pOutColorspace) = JCS_RGB; + return MEDIA_VISION_ERROR_NONE; + default: + return MEDIA_VISION_ERROR_NOT_SUPPORTED; + } + + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int ImageHelper::convertBufferToRGB888( + const unsigned char *pInBuffer, + const ImageData& imageData, + unsigned char **pOutBuffer) +{ + // todo: support more colorspaces: + switch(imageData.imageColorspace) + { + case MEDIA_VISION_COLORSPACE_Y800: + return convertY800ToRGB(pInBuffer, imageData, pOutBuffer); + case MEDIA_VISION_COLORSPACE_RGB888: + { + int numberOfComponents = 0; + getNumberOfComponents( + MEDIA_VISION_COLORSPACE_RGB888, &numberOfComponents); + const int dataSize = + imageData.imageHeight * imageData.imageWidth * numberOfComponents; + (*pOutBuffer) = new unsigned char[dataSize]; + std::memcpy(*pOutBuffer, pInBuffer, dataSize); + return MEDIA_VISION_ERROR_NONE; + } + default: + return MEDIA_VISION_ERROR_NOT_SUPPORTED; + } + + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int ImageHelper::getNumberOfComponents( + mv_colorspace_e colorspace, + int *pComponentsNumber) +{ + // todo: support more colorspaces: + switch (colorspace) + { + case MEDIA_VISION_COLORSPACE_Y800: + (*pComponentsNumber) = 1; + return MEDIA_VISION_ERROR_NONE; + case MEDIA_VISION_COLORSPACE_RGB888: + (*pComponentsNumber) = 3; + return MEDIA_VISION_ERROR_NONE; + default: + return MEDIA_VISION_ERROR_NOT_SUPPORTED; + } + + return MEDIA_VISION_ERROR_NOT_SUPPORTED; +} + +int ImageHelper::convertY800ToRGB( + const unsigned char *pInBuffer, + const ImageData& imageData, + unsigned char **pOutBuffer) +{ + if (imageData.imageColorspace != MEDIA_VISION_COLORSPACE_Y800) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + const int inDataSize = imageData.imageHeight * imageData.imageWidth; + int numberOfComponents = 0; + getNumberOfComponents(MEDIA_VISION_COLORSPACE_RGB888, &numberOfComponents); + const int dataSize = inDataSize * numberOfComponents; + (*pOutBuffer) = new unsigned char[dataSize]; + for (int i = 0; i < inDataSize; ++i) + { + int pixelStartIndex = i*numberOfComponents; + (*pOutBuffer)[pixelStartIndex] = pInBuffer[i]; + (*pOutBuffer)[pixelStartIndex+1] = pInBuffer[i]; + (*pOutBuffer)[pixelStartIndex+2] = pInBuffer[i]; + } + return MEDIA_VISION_ERROR_NONE; +} + +} /* namespace Common */ +} /* namespace MediaVision */ diff --git a/test/testsuites/common/image_helper/src/image_helper.cpp b/test/testsuites/common/image_helper/src/image_helper.cpp new file mode 100644 index 0000000..369f703 --- /dev/null +++ b/test/testsuites/common/image_helper/src/image_helper.cpp @@ -0,0 +1,172 @@ +/** + * 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 "image_helper.h" + +#include "mv_private.h" +#include "ImageHelper.h" + +#include + +/** + * @file image_helper.cpp + * @brief image_helper.h functions implementation. + */ + +using namespace MediaVision::Common; + +image_data_s convertToCData(ImageHelper::ImageData data) +{ + image_data_s ret; + ret.image_width = data.imageWidth; + ret.image_height = data.imageHeight; + ret.image_colorspace = data.imageColorspace; + return ret; +} + +ImageHelper::ImageData convertToCppData(image_data_s data) +{ + ImageHelper::ImageData ret; + ret.imageWidth = data.image_width; + ret.imageHeight = data.image_height; + ret.imageColorspace = data.image_colorspace; + return ret; +} + + +int load_image_to_buffer( + const char *file_path, + unsigned char **data_buffer, + unsigned long *buffer_size, + image_data_s *image_data) +{ + if (image_data == NULL) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + int err; + ImageHelper::ImageData imageData; + err = ImageHelper::loadImageToBuffer(file_path, data_buffer, buffer_size, &imageData); + + if (err == MEDIA_VISION_ERROR_NONE) + { + *image_data = convertToCData(imageData); + } + + return err; +} + +int save_image_from_buffer( + const char *file_path, + unsigned char *data_buffer, + const image_data_s *image_data, + int quality) +{ + if (image_data == NULL) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + ImageHelper::ImageData imageData = convertToCppData(*image_data); + return ImageHelper::saveImageFromBuffer(file_path, data_buffer, imageData, quality); +} + +int draw_rectangle_on_buffer( + int tl_vertex_x, + int tl_vertex_y, + int br_vertex_x, + int br_vertex_y, + int thickness, + const int rgb_color[3], + const image_data_s *image_data, + unsigned char *data_buffer) +{ + if (image_data == NULL) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + ImageHelper::ImageData imageData = convertToCppData(*image_data); + + cv::Scalar color(rgb_color[2], rgb_color[1], rgb_color[0]); + + return ImageHelper::drawRectangleOnBuffer( + tl_vertex_x, tl_vertex_y, + br_vertex_x, br_vertex_y, + thickness, + color, + imageData, data_buffer); +} + +int draw_quadrangle_on_buffer( + mv_quadrangle_s location, + int thickness, + const int rgb_color[3], + const image_data_s *image_data, + unsigned char *data_buffer) +{ + if (image_data == NULL) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + ImageHelper::ImageData imageData = convertToCppData(*image_data); + + cv::Scalar color(rgb_color[2], rgb_color[1], rgb_color[0]); + + return ImageHelper::drawQuadrangleOnBuffer( + location, + thickness, + color, + imageData, + data_buffer); +} + +int convert_jpeglib_colorspace_to_mv_colorspace( + J_COLOR_SPACE in_colorspace, + mv_colorspace_e *out_colorspace) +{ + return ImageHelper::convertJpeglibColorspaceToMVColorspace(in_colorspace, out_colorspace); +} + +int convert_mv_colorspace_to_jpeglib_colorspace( + mv_colorspace_e in_colorspace, + J_COLOR_SPACE *out_colorspace) +{ + return ImageHelper::convertMVColorspaceToJpeglibColorspace(in_colorspace, out_colorspace); +} + +int convert_buffer_to_RGB888( + const unsigned char *in_buffer, + const image_data_s *image_data, + unsigned char **out_buffer) +{ + if (image_data == NULL) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + ImageHelper::ImageData imageData = convertToCppData(*image_data); + return ImageHelper::convertBufferToRGB888(in_buffer, imageData, out_buffer); +} + +int get_number_of_components( + mv_colorspace_e colorspace, + int *components_number) +{ + return ImageHelper::getNumberOfComponents(colorspace, components_number); +} diff --git a/test/testsuites/common/testsuite_common/CMakeLists.txt b/test/testsuites/common/testsuite_common/CMakeLists.txt new file mode 100644 index 0000000..b111347 --- /dev/null +++ b/test/testsuites/common/testsuite_common/CMakeLists.txt @@ -0,0 +1,18 @@ +SET (pkgname mv_testsuite_common) +PROJECT(${pkgname}) + +cmake_minimum_required(VERSION 2.6) + +SET(INC_DIR include) +INCLUDE_DIRECTORIES(${INC_DIR}) +include_directories(${INC_IMAGE_HELPER}) +include_directories(${INC_VIDEO_HELPER}) + +SET(CMAKE_C_FLAGS "-I./include -I./include/headers ${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") + +ADD_LIBRARY(${pkgname} SHARED "mv_testsuite_common.c" "mv_testsuite_common.h") + +TARGET_LINK_LIBRARIES(${pkgname} ${MV_COMMON_LIB_NAME} mv_image_helper) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}) diff --git a/test/testsuites/common/testsuite_common/mv_testsuite_common.c b/test/testsuites/common/testsuite_common/mv_testsuite_common.c new file mode 100644 index 0000000..bf02a2a --- /dev/null +++ b/test/testsuites/common/testsuite_common/mv_testsuite_common.c @@ -0,0 +1,323 @@ +/** + * 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 +#include + + +void print_fail_result( + const char *action_name, + int action_return_value) +{ + printf(TEXT_RED + "Error with code %i was occurred during action '%s'" + TEXT_RESET "\n", + action_return_value, + action_name); +} + +void print_done_result(const char *action_name) +{ + printf(TEXT_YELLOW + "Action '%s' was finished" + TEXT_RESET "\n", + action_name); +} + +void print_success_result(const char *action_name) +{ + printf(TEXT_GREEN + "Action '%s' was finished successfully" + TEXT_RESET + "\n", action_name); +} + +void print_action_result( + const char *action_name, + int action_return_value, + notification_type_e notification_type_e) +{ + switch(notification_type_e) + { + case FAIL_OR_SUCCESSS: + if (MEDIA_VISION_ERROR_NONE != action_return_value) + { + print_fail_result(action_name, action_return_value); + } + else + { + print_success_result(action_name); + } + break; + case FAIL_OR_DONE: + if (MEDIA_VISION_ERROR_NONE != action_return_value) + { + print_fail_result(action_name, action_return_value); + } + else + { + print_done_result(action_name); + } + break; + default: + print_done_result(action_name); + } +} + +int input_string(const char *prompt, size_t max_len, char **string) +{ + printf("\n"); + printf("%s ", prompt); + + if (scanf("\n") != 0) + { + return -1; + } + + char buffer[max_len]; + int last_char = 0; + buffer[last_char] = '\0'; + buffer[sizeof(buffer) - 1] = ~'\0'; + if (NULL == fgets(buffer, sizeof(buffer), stdin)) + { + return -1; + } + size_t real_string_len = strlen(buffer); + buffer[real_string_len - 1] = '\0'; + *string = (char*)malloc(real_string_len * sizeof(char)); + strcpy(*string, buffer); + + return strlen(*string); +} + +int input_size(const char *prompt, size_t max_size, size_t *size) +{ + printf("\n"); + printf("%s ", prompt); + + if (scanf("%20zu", size) == 0) + { + if (scanf("%*[^\n]%*c") != 0) + { + printf("ERROR: Reading the input line error.\n"); + return -1; + } + printf("ERROR: Incorrect input.\n"); + return -1; + } + scanf("%*[^\n]%*c"); + + return (*size > max_size ? -1 : 0); +} + +int input_int(const char *prompt, int min_value, int max_value, int *value) +{ + printf("\n"); + printf("%s ", prompt); + + if (scanf("%20i", value) == 0) + { + if (scanf("%*[^\n]%*c") != 0) + { + printf("ERROR: Reading the input line error.\n"); + return -1; + } + printf("ERROR: Incorrect input.\n"); + return -1; + } + scanf("%*[^\n]%*c"); + + return (*value < min_value || *value > max_value ? -1 : 0); +} + +int input_double( + const char *prompt, + double min_value, + double max_value, + double *value) +{ + printf("\n"); + printf("%s ", prompt); + + if (scanf("%20lf", value) == 0) + { + if (scanf("%*[^\n]%*c") != 0) + { + printf("ERROR: Reading the input line error.\n"); + return -1; + } + printf("ERROR: Incorrect input.\n"); + return -1; + } + scanf("%*[^\n]%*c"); + + return (*value < min_value || *value > max_value ? -1 : 0); +} + +bool show_confirm_dialog(const char *title) +{ + const int options[2] = {1, 2}; + const char *names[2] = { "No", "Yes" }; + + bool answer = false; + + int sel = -1; + while (sel == -1) + { + sel = show_menu(title, options, names, 2); + switch (sel) + { + case 1: + answer = false; + break; + case 2: + answer = true; + break; + default: + sel = -1; + printf("ERROR: Incorrect input.\n"); + continue; + } + } + + return answer; +} + +int show_menu( + const char *title, + const int *options, + const char **names, + int number_of_option) +{ + if (NULL == title || NULL == options || NULL == names || 0 >= number_of_option) + { + return -1; + } + + int number_size = 1; + + int tn_counter = number_of_option; + while(tn_counter/=10) + { + ++number_size; + } + + int max_len = strlen(title) - number_size - 2; + + int i = 0; + for (i = 0; i < number_of_option; ++i) + { + const int temp_len = strlen(names[i]); + if (max_len < temp_len) + { + max_len = temp_len; + } + } + + const int full_size = number_size + 2 + max_len; + + printf("\n**"); + for (i = 0; i < full_size; ++i) + { + printf("*"); + } + printf("**\n"); + + printf("* %-*s *\n", full_size, title); + + printf("*-"); + for (i = 0; i < full_size; ++i) + { + printf("-"); + } + printf("-*\n"); + + for (i = 0; i < number_of_option; ++i) + { + printf("* %0*i. %-*s *\n", number_size, options[i], max_len, names[i]); + } + + printf("**"); + for (i = 0; i < full_size; ++i) + { + printf("*"); + } + printf("**\n\n"); + + int selection = 0; + printf("Your choice: "); + if (scanf("%25i", &selection) == 0) + { + if (scanf("%*[^\n]%*c") != 0) + { + printf("ERROR: Reading the input line error.\n"); + } + + printf("ERROR: Incorrect input.\n"); + return -1; + } + scanf("%*[^\n]%*c"); + + return selection; +} + +int load_mv_source_from_file( + const char *path_to_image, + mv_source_h source) +{ + unsigned char *data_buffer = NULL; + unsigned long buffer_size = 0; + image_data_s image_data; + + int err = load_image_to_buffer(path_to_image, &data_buffer, + &buffer_size, &image_data); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Errors were occurred during opening file!!! code: %i\n", + err); + if (NULL != data_buffer) + { + free(data_buffer); + } + + return err; + } + + err = mv_source_fill_by_buffer( + source, data_buffer, + buffer_size, + image_data.image_width, + image_data.image_height, + image_data.image_colorspace); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Errors were occurred during filling source!!! code %i\n", + err); + } + + if (NULL != data_buffer) + { + free(data_buffer); + } + + return err; +} diff --git a/test/testsuites/common/testsuite_common/mv_testsuite_common.h b/test/testsuites/common/testsuite_common/mv_testsuite_common.h new file mode 100644 index 0000000..f159dd0 --- /dev/null +++ b/test/testsuites/common/testsuite_common/mv_testsuite_common.h @@ -0,0 +1,158 @@ +/** + * 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 __MV_TESTSUITE_COMMON_H__ +#define __MV_TESTSUITE_COMMON_H__ + +#include "mv_common.h" + +#include + +typedef enum +{ + FAIL_OR_SUCCESSS, + FAIL_OR_DONE +} notification_type_e; + +/** + * @brief Prints success result of action. + * + * @since_tizen 3.0 + * @param [in] action_name Name of action which result will be printed + * @param [in] action_return_value Return value of action + */ +void print_fail_result( + const char *action_name, + int action_return_value); + +/** + * @brief Prints success result of action. + * + * @since_tizen 3.0 + * @param [in] action_name Name of action which result will be printed + */ +void print_done_result(const char *action_name); + +/** + * @brief Prints success result of action. + * + * @since_tizen 3.0 + * @param [in] action_name Name of action which result will be printed + */ +void print_success_result(const char *action_name); + +/** + * @brief Prints action result. + * + * @since_tizen 3.0 + * @param [in] action_name Name of action which result will be printed + * @param [in] action_return_value Return value of action + * @param [in] notification_type_e Type of notification + */ +void print_action_result( + const char *action_name, + int action_return_value, + notification_type_e notification_type_e); + +/** + * @brief Gets srting from console. + * + * @since_tizen 3.0 + * @param [in] prompt The prompt before getting string value + * @param [in] max_len Maximum length of the string which will be got + * @param [out] string Output string which was got from console + * @return Length of the output string on success, otherwise a negative error value + */ +int input_string(const char *prompt, size_t max_len, char **string); + +/** + * @brief Gets unsigned integer from console. + * + * @since_tizen 3.0 + * @param [in] prompt The prompt before getting unsigned integer value + * @param [in] max_size The thresold for maximum possible value + * @param [out] size The output unsigned integer which was got from console + * @return @c 0 on success, otherwise a negative error value + */ +int input_size(const char *prompt, size_t max_size, size_t *size); + +/** + * @brief Gets integer from console. + * + * @since_tizen 3.0 + * @param [in] prompt The prompt before getting integer value + * @param [in] min_value The thresold for minimum possible value + * @param [in] max_value The thresold for maximum possible value + * @param [out] value The output integer which was got from console + * @return @c 0 on success, otherwise a negative error value + */ +int input_int(const char *prompt, int min_value, int max_value, int *value); + +/** + * @brief Gets double from console. + * + * @since_tizen 3.0 + * @param [in] prompt The prompt before getting double value + * @param [in] min_value The thresold for minimum possible value + * @param [in] max_value The thresold for maximum possible value + * @param [out] value The output double which was got from console + * @return @c 0 on success, otherwise a negative error value + */ +int input_double(const char *prompt, double min_value, double max_value, double *value); + +/** + * @brief Shows confirm dialog in console and gets answer (Yes/No). + * + * @since_tizen 3.0 + * @param [in] title The title for confirm dialog which will be printed + * before input of the answer + * @return false if answer is "No" and true if answer is "Yes" + */ +bool show_confirm_dialog(const char *title); + +/** + * @brief Shows menu in console and allows to get item from the array of options. + * + * @since_tizen 3.0 + * @param [in] title The title for show menu which will be printed + * before options + * @param [in] options The array with integer numbers of options + * which will be shown + * @param [in] names The array with names of options which will + * be shown + * @param [in] number_of_option The number of options which will be shown + * @return The selected item positive number from options array on success, + * otherwise a negative error value + */ +int show_menu( + const char *title, + const int *options, + const char **names, + int number_of_option); + +/** + * @brief Loads media source from JPEG image. + * + * @since_tizen 3.0 + * @param [in] path_to_image The path to JPEG image which will be loaded + * @param [in/out] source The hadler to media source which will be filled + * @return @c 0 on success, otherwise a negative error value + */ +int load_mv_source_from_file( + const char *path_to_image, + mv_source_h source); + +#endif /* __MV_TESTSUITE_COMMON_H__ */ diff --git a/test/testsuites/common/video_helper/CMakeLists.txt b/test/testsuites/common/video_helper/CMakeLists.txt new file mode 100644 index 0000000..9eaa1e7 --- /dev/null +++ b/test/testsuites/common/video_helper/CMakeLists.txt @@ -0,0 +1,25 @@ +SET (pkgname mv_video_helper) +PROJECT(${pkgname}) + +cmake_minimum_required(VERSION 2.6) + +SET(INC_DIR include) +INCLUDE_DIRECTORIES(${INC_DIR}) +include_directories(${INC_IMAGE_HELPER}) + +SET(dependents "gstreamer-1.0 gstreamer-app-1.0 dlog") + +INCLUDE(FindPkgConfig) +pkg_check_modules(${pkgname} REQUIRED ${dependents}) +FOREACH(flag ${${pkgname}_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "-I./include -I./include/headers ${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") + +ADD_LIBRARY(${pkgname} SHARED "mv_video_helper.c" "mv_video_helper.h") + +TARGET_LINK_LIBRARIES(${pkgname} ${${pkgname}_LDFLAGS} gstvideo-1.0) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}) diff --git a/test/testsuites/common/video_helper/mv_log_cfg.h b/test/testsuites/common/video_helper/mv_log_cfg.h new file mode 100644 index 0000000..cb6e0a3 --- /dev/null +++ b/test/testsuites/common/video_helper/mv_log_cfg.h @@ -0,0 +1,72 @@ +/** + * 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 __MV_LOG_CFG_H__ +#define __MV_LOG_CFG_H__ + +#include + +//#define ROOTSTRAP_OUT // enables logs to console + +#define TEXT_RED "\x1b[31m" +#define TEXT_GREEN "\x1b[32m" +#define TEXT_YELLOW "\x1b[33m" +#define TEXT_BLUE "\x1b[34m" +#define TEXT_MAGENTA "\x1b[35m" +#define TEXT_CYAN "\x1b[36m" +#define TEXT_RESET "\x1b[0m" + +#ifdef ROOTSTRAP_OUT + +#define LOGD(...) \ +do \ +{ \ + printf("<%s:%d>", __FUNCTION__, __LINE__); \ + printf(TEXT_CYAN); \ + printf(__VA_ARGS__); \ + printf(TEXT_RESET "\n"); \ +} while(0) + +#define LOGI(...) \ +do \ +{ \ + printf("<%s:%d>", __FUNCTION__, __LINE__); \ + printf(TEXT_GREEN); \ + printf(__VA_ARGS__); \ + printf(TEXT_RESET "\n"); \ +} while(0) + +#define LOGW(...) \ +do \ +{ \ + printf("<%s:%d>", __FUNCTION__, __LINE__); \ + printf(TEXT_YELLOW); \ + printf(__VA_ARGS__); \ + printf(TEXT_RESET "\n"); \ +} while(0) + +#define LOGE(...) \ +do \ +{ \ + printf("<%s:%d>", __FUNCTION__, __LINE__); \ + printf(TEXT_RED); \ + printf(__VA_ARGS__); \ + printf(TEXT_RESET "\n"); \ +} while(0) + +#endif + +#endif /* __MV_LOG_CFG_H__ */ diff --git a/test/testsuites/common/video_helper/mv_video_helper.c b/test/testsuites/common/video_helper/mv_video_helper.c new file mode 100644 index 0000000..7674d91 --- /dev/null +++ b/test/testsuites/common/video_helper/mv_video_helper.c @@ -0,0 +1,926 @@ +/** + * 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_common.h" +#include "mv_video_helper.h" + +#include "mv_log_cfg.h" + +#include +#include + +#include +#include +#include + +#include + +typedef struct _mv_video_reader_s +{ + /* Main bin */ + GstElement *pl; + + /* Pipeline structure */ + GstElement *filesrc; + GstElement *decodebin; + GstElement *videoconvert; + GstElement *appsink; + + void *new_sample_cb_user_data; + void *eos_cb_user_data; + + GstCaps *caps; + + pthread_spinlock_t new_sample_cb_guard; + pthread_spinlock_t eos_cb_guard; + + mv_video_reader_new_sample_cb new_sample_cb; + mv_video_reader_eos_cb eos_cb; +} mv_video_reader_s; + +typedef struct _mv_video_writer_s +{ + /* Main bin */ + GstElement *pl; + + /* Pipeline structure */ + GstElement *appsrc; + GstElement *capsfilter; + GstElement *videoconvert; + GstElement *encoder; + GstElement *queue; + GstElement *muxer; + GstElement *filesink; + + image_data_s image_data; + unsigned int fps; + unsigned int buffer_size; +} mv_video_writer_s; + +/* video reader internal funcitons */ +static int _mv_video_reader_create_internals(mv_video_reader_s *reader); +static int _mv_video_reader_link_internals(mv_video_reader_s *reader); +static int _mv_video_reader_state_change(mv_video_reader_s *reader, GstState state); + +/* video writer internal funciton */ +static int _mv_video_writer_create_internals(mv_video_writer_s *writer); +static int _mv_video_writer_link_internals(mv_video_writer_s *writer); +static int _mv_video_writer_state_change(mv_video_writer_s *writer, GstState state); + +static void appsink_eos(GstAppSink *appsink, gpointer user_data); +static GstFlowReturn appsink_newsample(GstAppSink *appsink, gpointer user_data); +static void cb_newpad(GstElement *decodebin, GstPad *new_pad, gpointer user_data); + +/* video reader */ +int mv_create_video_reader( + mv_video_reader_h *reader) +{ + mv_video_reader_s *handle = NULL; + int err = MEDIA_VISION_ERROR_NONE; + + if (reader == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + gst_init(NULL, NULL); + + handle = (mv_video_reader_s *) malloc(sizeof(mv_video_reader_s)); + if (!handle) + { + LOGE("Not enough memory"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + memset(handle, 0, sizeof(mv_video_reader_s)); + + err = _mv_video_reader_create_internals(handle); + if (MEDIA_VISION_ERROR_NONE != err) + { + LOGE("Failed to create internals"); + free(handle); + return err; + } + + err = _mv_video_reader_link_internals(handle); + if (MEDIA_VISION_ERROR_NONE != err) + { + LOGE("Failed to link internals"); + free(handle); + return err; + } + + *reader = (mv_video_reader_s *) handle; + + return err; +} + +int mv_destroy_video_reader( + mv_video_reader_h reader) +{ + mv_video_reader_s *handle = NULL; + + if (reader == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + handle = (mv_video_reader_s *) reader; + + if (handle->caps && GST_OBJECT_REFCOUNT(handle->caps)) + { + gst_caps_unref(handle->caps); + } + + if (handle->pl) + { + gst_object_unref(handle->pl); + } + handle->pl = NULL; + + pthread_spin_destroy(&(handle->new_sample_cb_guard)); + pthread_spin_destroy(&(handle->eos_cb_guard)); + + LOGD("video reader destroyed %p", handle); + + free(handle); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_video_reader_load( + mv_video_reader_h reader, + const char *path, + image_data_s *image_data, + unsigned int *fps) +{ + mv_video_reader_s *handle = NULL; + GstVideoInfo info; + + if (reader == NULL || path == NULL || + image_data == NULL || fps == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + handle = (mv_video_reader_s *) reader; + + /* Set input file location from path */ + g_object_set(G_OBJECT(handle->filesrc), + "location", path, + NULL); + + /* Start playback */ + if (_mv_video_reader_state_change(handle, GST_STATE_PLAYING)) + { + LOGE("Unable to change state"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + if (_mv_video_reader_state_change(handle, GST_STATE_PAUSED)) + { + LOGE("Unable to change state"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + if (handle->caps == NULL) + { + LOGE("Unable to get caps from decodebin"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + gst_video_info_from_caps(&info, handle->caps); + gst_caps_unref(handle->caps); + + *fps = info.fps_n/info.fps_d; + + /* Fill image data */ + image_data->image_width = info.width; + image_data->image_height = info.height; + + /* Look to : + * http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideo.html#GstVideoFormat */ + switch(GST_VIDEO_FORMAT_INFO_FORMAT(info.finfo)) + { + case(GST_VIDEO_FORMAT_GRAY8): + image_data->image_colorspace = MEDIA_VISION_COLORSPACE_Y800; + break; + case(GST_VIDEO_FORMAT_I420): + image_data->image_colorspace = MEDIA_VISION_COLORSPACE_I420; + break; + case(GST_VIDEO_FORMAT_NV12): + image_data->image_colorspace = MEDIA_VISION_COLORSPACE_NV12; + break; + case(GST_VIDEO_FORMAT_YV12): + image_data->image_colorspace = MEDIA_VISION_COLORSPACE_YV12; + break; + case(GST_VIDEO_FORMAT_NV21): + image_data->image_colorspace = MEDIA_VISION_COLORSPACE_NV21; + break; + case(GST_VIDEO_FORMAT_YUY2): + image_data->image_colorspace = MEDIA_VISION_COLORSPACE_YUYV; + break; + case(GST_VIDEO_FORMAT_UYVY): + image_data->image_colorspace = MEDIA_VISION_COLORSPACE_UYVY; + break; + case(GST_VIDEO_FORMAT_RGB): + image_data->image_colorspace = MEDIA_VISION_COLORSPACE_RGB888; + break; + case(GST_VIDEO_FORMAT_RGBA): + image_data->image_colorspace = MEDIA_VISION_COLORSPACE_RGBA; + break; + default: + LOGE("Video pixel format is not supported\n"); + return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT; + } + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_video_reader_start( + mv_video_reader_h reader) +{ + mv_video_reader_s *handle = NULL; + + if (reader == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + handle = (mv_video_reader_s *) reader; + + /* Start playback */ + if (_mv_video_reader_state_change(handle, GST_STATE_PLAYING)) + { + LOGE("Unable to change state"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_video_reader_stop( + mv_video_reader_h reader) +{ + mv_video_reader_s *handle = NULL; + + if (reader == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + handle = (mv_video_reader_s *) reader; + + /* Stop playback (NULL or READY) */ + if (_mv_video_reader_state_change(handle, GST_STATE_NULL)) + { + LOGE("Unable to change state"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_video_reader_set_new_sample_cb( + mv_video_reader_h reader, + mv_video_reader_new_sample_cb callback, + void *user_data) +{ + mv_video_reader_s *handle = NULL; + + if (reader == NULL || callback == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + handle = (mv_video_reader_s *) reader; + + pthread_spin_lock(&(handle->new_sample_cb_guard)); + handle->new_sample_cb = callback; + handle->new_sample_cb_user_data = user_data; + pthread_spin_unlock(&(handle->new_sample_cb_guard)); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_video_reader_set_eos_cb( + mv_video_reader_h reader, + mv_video_reader_eos_cb callback, + void *user_data) +{ + mv_video_reader_s *handle = NULL; + + if (reader == NULL || callback == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + handle = (mv_video_reader_s *) reader; + + pthread_spin_lock(&(handle->eos_cb_guard)); + handle->eos_cb = callback; + handle->eos_cb_user_data = user_data; + pthread_spin_unlock(&(handle->eos_cb_guard)); + + return MEDIA_VISION_ERROR_NONE; +} + +/* Video Writer */ +int mv_create_video_writer( + mv_video_writer_h *writer) +{ + mv_video_writer_s *handle = NULL; + int err = MEDIA_VISION_ERROR_NONE; + + if (writer == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + gst_init(NULL, NULL); + + handle = (mv_video_writer_s *) malloc(sizeof(mv_video_writer_s)); + if (!handle) + { + LOGE("Not enough memory"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + memset(handle, 0, sizeof(mv_video_writer_s)); + + err = _mv_video_writer_create_internals(handle); + if (MEDIA_VISION_ERROR_NONE != err) + { + LOGE("Failed to create internals"); + free(handle); + return err; + } + + *writer = (mv_video_writer_s *) handle; + + return err; +} + +int mv_destroy_video_writer( + mv_video_writer_h writer) +{ + mv_video_writer_s *handle = NULL; + + if (writer == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + handle = (mv_video_writer_s *) writer; + + _mv_video_writer_state_change(writer, GST_STATE_NULL); + + if (handle->pl) + { + gst_object_unref(handle->pl); + } + handle->pl = NULL; + + LOGD("video writer destroyed %p", handle); + + free(handle); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_video_writer_init( + mv_video_writer_h writer, + const char *path, + image_data_s image_data, + unsigned int fps) +{ + mv_video_writer_s *handle = NULL; + unsigned int err = MEDIA_VISION_ERROR_NONE; + + if (writer == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + handle = (mv_video_writer_s *) writer; + + handle->image_data.image_width = image_data.image_width; + handle->image_data.image_height = image_data.image_height; + handle->image_data.image_colorspace = image_data.image_colorspace; + + handle->fps = fps; + + g_object_set(G_OBJECT(handle->filesink), + "location", path, + NULL); + + err = _mv_video_writer_link_internals(handle); + if (MEDIA_VISION_ERROR_NONE != err) + { + LOGE("Failed to link internals"); + return err; + } + + return err; +} + +int mv_video_writer_write_frame( + mv_video_writer_h writer, + unsigned char *frame) +{ + mv_video_writer_s *handle = NULL; + GstMapInfo info; + GstBuffer *buffer = NULL; + + if (writer == NULL || frame == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + handle = (mv_video_writer_s *) writer; + + buffer = gst_buffer_new_allocate(NULL, handle->buffer_size, NULL); + if (!buffer) + { + LOGE("Unable to allocate buffer for frame"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + LOGD("Copying input frame to buffer and pushing to appsrc"); + gst_buffer_map(buffer, &info, GST_MAP_READWRITE); + memcpy(info.data, frame, info.size); + gst_buffer_unmap(buffer, &info); + + if (GST_FLOW_OK != + gst_app_src_push_buffer(handle->appsrc, buffer)) + { + LOGE("Failed to push buffer to appsrc"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + return MEDIA_VISION_ERROR_NONE; +} + +/* Internal functions */ +static int _mv_video_reader_create_internals( + mv_video_reader_s *reader) +{ + pthread_spin_init(&(reader->new_sample_cb_guard), PTHREAD_PROCESS_SHARED); + pthread_spin_init(&(reader->eos_cb_guard), PTHREAD_PROCESS_SHARED); + + reader->pl = gst_pipeline_new(NULL); + + reader->filesrc = gst_element_factory_make("filesrc", "filesrc"); + reader->decodebin = gst_element_factory_make("decodebin", "decoder"); + reader->videoconvert = gst_element_factory_make("videoconvert", "convert"); + reader->appsink = gst_element_factory_make("appsink", "appsink"); + + if ((!reader->pl) || + (!reader->filesrc) || + (!reader->decodebin) || + (!reader->videoconvert) || + (!reader->appsink)) + { + LOGE("Unable to create video read pipeline elements"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + gst_bin_add_many(GST_BIN(reader->pl), + reader->filesrc, + reader->decodebin, + reader->videoconvert, + reader->appsink, + NULL); + + return MEDIA_VISION_ERROR_NONE; +} + +static int _mv_video_reader_link_internals( + mv_video_reader_s *reader) +{ + GstCaps *caps = NULL; + + if (!gst_element_link_many(reader->filesrc, + reader->decodebin, + NULL)) + { + LOGE("Unable to link filesrc to decodebin"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + /* Decodebin pad will be linked during state change */ + g_signal_connect(reader->decodebin, + "pad-added", + G_CALLBACK(cb_newpad), + reader); + + if (!gst_element_link_many(reader->videoconvert, + reader->appsink, NULL)) + { + LOGE("Unable to link filesrc to decodebin"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + caps = gst_caps_new_simple("video/x-raw", + "format", G_TYPE_STRING, "RGB", + NULL); + + gst_app_sink_set_caps(GST_APP_SINK(reader->appsink), caps); + gst_caps_unref(caps); + + /* Configure appsink */ + gst_app_sink_set_emit_signals(GST_APP_SINK(reader->appsink), TRUE); + g_signal_connect(reader->appsink, + "new-sample", + G_CALLBACK(appsink_newsample), + reader); + g_signal_connect(reader->appsink, + "eos", + G_CALLBACK(appsink_eos), + reader); + g_object_set(G_OBJECT(reader->appsink), + "drop", TRUE, + "enable-last-sample", TRUE, + "sync", FALSE, + NULL); + + return MEDIA_VISION_ERROR_NONE; +} + +static int _mv_video_reader_state_change( + mv_video_reader_s *reader, + GstState state) +{ + mv_video_reader_s *handle = (mv_video_reader_s *) reader; + GstStateChangeReturn state_ret = GST_STATE_CHANGE_FAILURE; + GstState pipeline_state = GST_STATE_NULL; + + state_ret = gst_element_set_state(handle->pl, + state); + + if (GST_STATE_CHANGE_FAILURE == state_ret) + { + LOGE("Set state failure"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + LOGI("Set state [%d], change return [%d]", + state, state_ret); + + state_ret = gst_element_get_state(handle->pl, + &pipeline_state, + NULL, + GST_CLOCK_TIME_NONE); + + if (GST_STATE_CHANGE_FAILURE == state_ret) + { + LOGE("get state failure"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + return MEDIA_VISION_ERROR_NONE; +} + +static int _mv_video_writer_create_internals( + mv_video_writer_s *writer) +{ + writer->pl = gst_pipeline_new(NULL); + + writer->appsrc = gst_element_factory_make("appsrc", "appsrc"); + writer->capsfilter = gst_element_factory_make("capsfilter", NULL); + writer->videoconvert = gst_element_factory_make("videoconvert", "videoconvert"); + writer->encoder = gst_element_factory_make("avenc_mpeg4", "encoder"); + writer->queue = gst_element_factory_make("queue", "queue"); + writer->muxer = gst_element_factory_make("avmux_avi", "muxer"); + writer->filesink = gst_element_factory_make("filesink", "filesink"); + + if ((!writer->pl) || + (!writer->appsrc) || + (!writer->capsfilter) || + (!writer->videoconvert) || + (!writer->encoder) || + (!writer->queue) || + (!writer->muxer) || + (!writer->filesink)) + { + LOGE("Unable to create video read pipeline elements\n"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + gst_bin_add_many(GST_BIN(writer->pl), + writer->appsrc, + writer->capsfilter, + writer->videoconvert, + writer->encoder, + writer->queue, + writer->muxer, + writer->filesink, + NULL); + + return MEDIA_VISION_ERROR_NONE; +} + +static int _mv_video_writer_link_internals( + mv_video_writer_s *writer) +{ + GstVideoInfo vinfo; + GstCaps *caps = NULL; + char format[6] = {0}; + + /* Convert from mv_colorspace to GstVideoFormat */ + switch(writer->image_data.image_colorspace) + { + case(MEDIA_VISION_COLORSPACE_Y800): + strncpy(format, "GRAY8", 5); + break; + case(MEDIA_VISION_COLORSPACE_I420): + strncpy(format, "I420", 4); + break; + case(MEDIA_VISION_COLORSPACE_NV12): + strncpy(format, "NV12", 4); + break; + case(MEDIA_VISION_COLORSPACE_YV12): + strncpy(format, "YV12", 4); + break; + case(MEDIA_VISION_COLORSPACE_NV21): + strncpy(format, "NV21", 4); + break; + case(MEDIA_VISION_COLORSPACE_YUYV): + strncpy(format, "YUY2", 4); + break; + case(MEDIA_VISION_COLORSPACE_UYVY): + strncpy(format, "UYVY", 4); + break; + case(MEDIA_VISION_COLORSPACE_RGB888): + strncpy(format, "RGB", 3); + break; + case(MEDIA_VISION_COLORSPACE_RGBA): + strncpy(format, "RGBA", 4); + break; + default: + LOGE("Selected format %d is not supported", + writer->image_data.image_colorspace); + return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT; + } + + caps = gst_caps_new_simple("video/x-raw", + "format", G_TYPE_STRING, format, + "width", G_TYPE_INT, writer->image_data.image_width, + "height", G_TYPE_INT, writer->image_data.image_height, + "framerate", GST_TYPE_FRACTION, writer->fps, 1, + NULL); + + if (NULL == caps) + { + LOGE("Failed to create new caps"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + /* This is the simpler way to get buffer size */ + if (!gst_video_info_from_caps(&vinfo, caps)) + { + LOGE("Unable to set buffer size"); + gst_caps_unref(caps); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + writer->buffer_size = vinfo.size; + + /* link appsrc and capsfilter */ + if ((!gst_element_link_filtered(writer->appsrc, + writer->capsfilter, + caps))) + { + LOGE("Failed to link appsrc to capsfilter"); + gst_caps_unref(caps); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + gst_caps_unref(caps); + + if (!gst_element_link_many(writer->capsfilter, + writer->videoconvert, + writer->encoder, + writer->queue, + writer->muxer, + writer->filesink, + NULL)) + { + LOGE("Unable to capsfilter to filesink"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + g_object_set(G_OBJECT(writer->appsrc), + "max-bytes", 0, + "blocksize", writer->buffer_size, + "stream-type", 0, + "format", GST_FORMAT_BYTES, + NULL); + + if (_mv_video_writer_state_change(writer, + GST_STATE_PLAYING)) + { + LOGE("Unable to change video writer state"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + return MEDIA_VISION_ERROR_NONE; +} + +static int _mv_video_writer_state_change( + mv_video_writer_s *writer, + GstState state) +{ + mv_video_writer_s *handle = (mv_video_writer_s *) writer; + GstStateChangeReturn state_ret = GST_STATE_CHANGE_FAILURE; + GstState pipeline_state = GST_STATE_NULL; + + state_ret = gst_element_set_state(handle->pl, + state); + + if (GST_STATE_CHANGE_FAILURE == state_ret) + { + LOGE("Set state failure"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + LOGI("Set state [%d], change return [%d]", + state, state_ret); + + /* AppSrc can't go to PLAYING state before buffer is not pushed */ + + return MEDIA_VISION_ERROR_NONE; +} + +/* Callbacks */ +static GstFlowReturn appsink_newsample( + GstAppSink *appsink, + gpointer user_data) +{ + mv_video_reader_s *handle = NULL; + GstSample *sample = gst_app_sink_pull_sample(appsink); + + if (user_data == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (sample != NULL) + { + handle = (mv_video_reader_s *) user_data; + GstVideoInfo vinfo; + GstMapInfo info = GST_MAP_INFO_INIT; + GstBuffer *buf = gst_sample_get_buffer(sample); + GstCaps *caps = gst_sample_get_caps(sample); + image_data_s im_data; + char *buffer = NULL; + unsigned int buffer_size = 0; + + LOGD("Received sample from appsink"); + + /* map buffer */ + gst_buffer_map(buf, &info, GST_MAP_READ); + buffer = (char *) info.data; + + /* Fill image data */ + gst_video_info_from_caps(&vinfo, caps); + im_data.image_width = vinfo.width; + im_data.image_height = vinfo.height; + + /* Look to : + * http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideo.html#GstVideoFormat */ + switch(GST_VIDEO_FORMAT_INFO_FORMAT(vinfo.finfo)) + { + case(GST_VIDEO_FORMAT_GRAY8): + im_data.image_colorspace = MEDIA_VISION_COLORSPACE_Y800; + break; + case(GST_VIDEO_FORMAT_I420): + im_data.image_colorspace = MEDIA_VISION_COLORSPACE_I420; + break; + case(GST_VIDEO_FORMAT_NV12): + im_data.image_colorspace = MEDIA_VISION_COLORSPACE_NV12; + break; + case(GST_VIDEO_FORMAT_YV12): + im_data.image_colorspace = MEDIA_VISION_COLORSPACE_YV12; + break; + case(GST_VIDEO_FORMAT_NV21): + im_data.image_colorspace = MEDIA_VISION_COLORSPACE_NV21; + break; + case(GST_VIDEO_FORMAT_YUY2): + im_data.image_colorspace = MEDIA_VISION_COLORSPACE_YUYV; + break; + case(GST_VIDEO_FORMAT_UYVY): + im_data.image_colorspace = MEDIA_VISION_COLORSPACE_UYVY; + break; + case(GST_VIDEO_FORMAT_RGB): + im_data.image_colorspace = MEDIA_VISION_COLORSPACE_RGB888; + break; + case(GST_VIDEO_FORMAT_RGBA): + im_data.image_colorspace = MEDIA_VISION_COLORSPACE_RGBA; + break; + default: + LOGE("Video pixel format is not supported\n"); + + gst_buffer_unmap(buf, &info); + gst_sample_unref(sample); + return GST_FLOW_ERROR; + } + + pthread_spin_lock(&(handle->new_sample_cb_guard)); + if (handle->new_sample_cb != NULL) + { + handle->new_sample_cb( + buffer, + info.size, + im_data, + handle->new_sample_cb_user_data); + } + pthread_spin_unlock(&(handle->new_sample_cb_guard)); + + gst_buffer_unmap(buf, &info); + gst_sample_unref(sample); + } + else + { + LOGE("Failed to pull sample from appsink"); + return GST_FLOW_ERROR; + } + + return GST_FLOW_OK; +} + +static void appsink_eos( + GstAppSink *appsink, + gpointer user_data) +{ + if (user_data == NULL) + { + LOGE("NULL pointer passed"); + return; + } + + mv_video_reader_s *handle = (mv_video_reader_s *) user_data; + + /* EOS callback to terminate reading */ + pthread_spin_lock(&(handle->eos_cb_guard)); + if (handle->eos_cb != NULL) + { + handle->eos_cb(handle->eos_cb_user_data); + } + pthread_spin_unlock(&(handle->eos_cb_guard)); +} + +static void cb_newpad( + GstElement *decodebin, + GstPad *pad, + gpointer user_data) +{ + mv_video_reader_s *reader = (mv_video_reader_s *) user_data; + GstStructure *str = NULL; + GstCaps *caps = NULL; + GstPad *video_pad = NULL; + + LOGI("Received pad from decodebin. Linking"); + video_pad = gst_element_get_static_pad(reader->videoconvert, "sink"); + if (GST_PAD_IS_LINKED(video_pad)) + { + LOGI("Already linked"); + g_object_unref(video_pad); + return; + } + + /* Check for pad is video */ + reader->caps = gst_pad_query_caps(pad, NULL); + str = gst_caps_get_structure(reader->caps, 0); + if (!g_strrstr(gst_structure_get_name(str), "video")) + { + LOGI("Not a video pad"); + gst_object_unref(video_pad); + return; + } + + gst_pad_link(pad, video_pad); + g_object_unref(video_pad); +} diff --git a/test/testsuites/common/video_helper/mv_video_helper.h b/test/testsuites/common/video_helper/mv_video_helper.h new file mode 100644 index 0000000..b22c11e --- /dev/null +++ b/test/testsuites/common/video_helper/mv_video_helper.h @@ -0,0 +1,277 @@ +/** + * 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 __MV_VIDEO_HELPER_H__ +#define __MV_VIDEO_HELPER_H__ + +#include "mv_common.h" +#include "image_helper.h" + +/** + * @brief The handle to the video reader. + * + * @since_tizen 3.0 + */ +typedef void *mv_video_reader_h; + +/** + * @brief The handle to the video writer. + * + * @since_tizen 3.0 + */ +typedef void *mv_video_writer_h; + +/** + * @brief Called when new sample is available from video reader. + * + * @since_tizen 3.0 + * @remarks You don't need release @a buffer independently + * @param [in] buffer Raw video buffer + * @param [in] buffer_size Size of video buffer + * @param [in] image_data Image data for corresponding video buffer + * @param [in] user_data User data + * + * @pre Create a reader handle by calling mv_video_reader_create() + * @pre Set callback by calling mv_video_reader_set_new_sample_cb() + * + * @see mv_video_reader_set_new_sample_cb() + */ +typedef void (*mv_video_reader_new_sample_cb) ( + char *buffer, + unsigned int buffer_size, + image_data_s image_data, + void *user_data); + +/** + * @brief Called when stream from video reader is finished. + * + * @since_tizen 3.0 + * @param [in] user_data User data + * + * @pre Create a reader handle by calling mv_video_reader_create() + * @pre Set callback by calling mv_video_reader_set_eos_cb() + * + * @see mv_video_reader_set_eos_cb() + */ +typedef void (*mv_video_reader_eos_cb) ( + void *user_data); + +/** + * @brief Creates a video reader handle. + * + * @since_tizen 3.0 + * @remarks You must release @a reader by using @ref mv_destroy_video_reader(). + * @param [out] reader A new handle to the video reader + * @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_INVALID_OPERATION Invalid operation + * + * @see mv_destroy_video_reader() + */ +int mv_create_video_reader( + mv_video_reader_h *reader); + +/** + * @brief Destroys the video reader handle and releases all its resources. + * + * @since_tizen 3.0 + * @param [in] reader The handle to the video reader 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 + * + * @see mv_create_video_reader() + */ +int mv_destroy_video_reader( + mv_video_reader_h reader); + +/** + * @brief Loads video from file. + * + * @since_tizen 3.0 + * @param [in] reader The handle to the video reader + * @param [in] path Path to the video file to be loaded + * @param [out] image_data Image data for corresponding video buffer + * @param [out] fps Frame per second of corresponding video file + * @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_INVALID_OPERATION Invalid operation + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Not supported video format + * + * @pre Create a video reader handle by calling @ref mv_create_video_reader() + */ +int mv_video_reader_load( + mv_video_reader_h reader, + const char *path, + image_data_s *image_data, + unsigned int *fps); + +/** + * @brief Starts reader playback. + * + * @since_tizen 3.0 + * @param [in] reader The handle to the video reader + * @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_INVALID_OPERATION Invalid operation + * + * @pre Create a video reader handle by calling @ref mv_create_video_reader() + * and call @ref mv_video_reader_load() + * + * @post Stop reader playback by calling @ref mv_video_reader_stop() + */ +int mv_video_reader_start( + mv_video_reader_h reader); + +/** + * @brief Stops reader playback. + * + * @since_tizen 3.0 + * @param [in] reader The handle to the video reader + * @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_INVALID_OPERATION Invalid operation + * + * @pre Create a video reader handle by calling @ref mv_create_video_reader() + * and call @ref mv_video_reader_load() + */ +int mv_video_reader_stop( + mv_video_reader_h reader); + +/** + * @brief Sets new sample callback to video reader. + * + * @since_tizen 3.0 + * @param [in] reader The handle to the video reader + * @param [in] callback Callback that will be called + * @param [in] user_data User data + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIA_VISION_ERROR_NONE Successful + * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter + * + * @pre Create a video reader handle by calling @ref mv_create_video_reader() + * and load video with @ref mv_video_reader_load() + * + * @see mv_create_video_reader() + * @see mv_video_reader_load() + * + */ +int mv_video_reader_set_new_sample_cb( + mv_video_reader_h reader, + mv_video_reader_new_sample_cb callback, + void *user_data); + +/** + * @brief Sets end of stream callback to video reader. + * + * @since_tizen 3.0 + * @param [in] reader The handle to the video reader + * @param [in] callback Callback that will be called + * @param [in] user_data User data + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIA_VISION_ERROR_NONE Successful + * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter + * + * @pre Create a video reader handle by calling @ref mv_create_video_reader() + * and load video with @ref mv_video_reader_load() + * + * @see mv_create_video_reader() + * @see mv_video_reader_load() + * + */ +int mv_video_reader_set_eos_cb( + mv_video_reader_h reader, + mv_video_reader_eos_cb callback, + void *user_data); + +/** + * @brief Creates a video writer handle. + * + * @since_tizen 3.0 + * @remarks You must release @a writer by using @ref mv_destroy_video_writer(). + * @param [out] writer A new handle to the video writer + * @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_INVALID_OPERATION Invalid operation + * + * @see mv_destroy_video_writer() + */ +int mv_create_video_writer( + mv_video_writer_h *writer); + +/** + * @brief Destroys the video writer handle and releases all its resources. + * + * @since_tizen 3.0 + * @param [in] writer The handle to the video writer 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_INVALID_OPERATION Invalid operation + * + * @see mv_create_video_writer() + */ +int mv_destroy_video_writer( + mv_video_writer_h writer); + +/** + * @brief Sets path and frame size for video file to be stored. + * + * @since_tizen 3.0 + * @param [in] writer The handle to the video writer + * @param [in] path Path to the video file to be stored + * @param [in] image_data Image data for corresponding video buffer + * @param [in] fps Frame per second of resulted video file + * @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_INVALID_OPERATION Invalid operation + * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Not supported video format + * + * @pre Create a video writer handle by calling @ref mv_create_video_writer() + */ +int mv_video_writer_init( + mv_video_writer_h writer, + const char *path, + image_data_s image_data, + unsigned int fps); + +/** + * @brief Writes consequently video frame to the file. + * @details After video writer was initialized this function consequently + * writes frames to the file. + * + * @since_tizen 3.0 + * @param [in] writer The handle to the video writer + * @param [in] frame Raw image 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 + * @retval #MEDIA_VISION_ERROR_INVALID_OPERATION Invalid operation + * + * @pre Create a video writer handle by calling @ref mv_create_video_writer() + * and initialize video with @ref mv_video_writer_init() + */ +int mv_video_writer_write_frame( + mv_video_writer_h writer, + unsigned char *frame); + +#endif /* __MV_VIDEO_HELPER_H__ */ diff --git a/test/testsuites/face/CMakeLists.txt b/test/testsuites/face/CMakeLists.txt new file mode 100644 index 0000000..aed6de7 --- /dev/null +++ b/test/testsuites/face/CMakeLists.txt @@ -0,0 +1,34 @@ +project(mv_face_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_CXX_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_IMAGE_HELPER}) +include_directories(${INC_VIDEO_HELPER}) +include_directories(${INC_TS_COMMON}) + +file(GLOB MV_FACE_TEST_SUITE_INC_LIST "${PROJECT_SOURCE_DIR}/*.h") +file(GLOB MV_FACE_TEST_SUITE_SRC_LIST "${PROJECT_SOURCE_DIR}/*.c") + +add_executable(${PROJECT_NAME} + ${MV_FACE_TEST_SUITE_INC_LIST} + ${MV_FACE_TEST_SUITE_SRC_LIST} + ${MV_CAPI_MEDIA_VISION_INC_LIST}) + +target_link_libraries(${PROJECT_NAME} capi-media-vision + dlog + mv_image_helper + mv_video_helper + mv_testsuite_common) + +install(TARGETS ${PROJECT_NAME} DESTINATION ${testsuites_dir}) diff --git a/test/testsuites/face/face_test_suite.c b/test/testsuites/face/face_test_suite.c new file mode 100644 index 0000000..c26fce7 --- /dev/null +++ b/test/testsuites/face/face_test_suite.c @@ -0,0 +1,2146 @@ +/** + * 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 +#include + +#include + +#include +#include + +#include + +#include "pthread.h" + +#include +#include +#include +#include +#include +#include + +#define MIN_ALLOWED_LABEL 0 +#define MAX_ALLOWED_LABEL 100 + +static bool Perform_eye_condition_recognize = false; +static bool Perform_facial_expression_recognize = false; + +void eye_condition_cb( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s face_location, + mv_face_eye_condition_e eye_condition, + void *user_data) +{ + switch (eye_condition) + { + case MV_FACE_EYES_NOT_FOUND: + printf("Eyes not found"); + break; + case MV_FACE_EYES_OPEN: + printf("Eyes are open"); + break; + case MV_FACE_EYES_CLOSED: + printf("Eyes are closed"); + break; + } +} + +void face_expression_cb( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s face_location, + mv_face_facial_expression_e facial_expression, + void *user_data) +{ + switch (facial_expression) + { + case MV_FACE_NEUTRAL: + printf("Face expression is neutral"); + break; + case MV_FACE_SMILE: + printf("Face expression is smiling"); + break; + case MV_FACE_UNKNOWN: + printf("Face expression isn't recognized"); + break; + } +} + +void on_face_detected_cb( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s *faces_locations, + int number_of_faces, + void *user_data) +{ + printf("%i faces were detected on the image.\n", number_of_faces); + if (number_of_faces > 0) + { + int is_source_data_loaded = 0; + + char *file_name = NULL; + unsigned char *out_buffer = NULL; + unsigned int buf_size = 0; + image_data_s image_data = { 0, 0, MEDIA_VISION_COLORSPACE_INVALID }; + if (MEDIA_VISION_ERROR_NONE != mv_source_get_buffer(source, &out_buffer, &buf_size) || + MEDIA_VISION_ERROR_NONE != mv_source_get_width(source, &(image_data.image_width)) || + MEDIA_VISION_ERROR_NONE != mv_source_get_height(source, &(image_data.image_height)) || + MEDIA_VISION_ERROR_NONE != mv_source_get_colorspace(source, &(image_data.image_colorspace)) || + user_data == NULL) + { + printf("ERROR: Creating out image is impossible.\n"); + } + else + { + file_name = (char*)user_data; + is_source_data_loaded = 1; + } + + int i = 0; + for (i = 0; i < number_of_faces; ++i) + { + printf("\Face %i : x - %i, y - %i, width - %i, height - %i ", i, + faces_locations[i].point.x, faces_locations[i].point.y, + faces_locations[i].width, faces_locations[i].height); + + if (Perform_eye_condition_recognize) + { + if (MEDIA_VISION_ERROR_NONE != mv_face_eye_condition_recognize( + source, + engine_cfg, + faces_locations[i], + eye_condition_cb, + user_data)) + { + printf(TEXT_RED "\nEye condition recognition for %i face failed" + TEXT_RESET "\n", i); + } + } + + if (Perform_facial_expression_recognize) + { + if (MEDIA_VISION_ERROR_NONE != mv_face_facial_expression_recognize( + source, + engine_cfg, + faces_locations[i], + face_expression_cb, + user_data)) + { + printf(TEXT_RED "\nFacial expression recognition for %i " + "face failed" TEXT_RESET "\n", i); + } + } + + printf("\n"); + + if ((is_source_data_loaded == 1) && !Perform_eye_condition_recognize) + { + const int rectangle_thickness = 3; + const int drawing_color[] = {255, 0, 0}; + if (MEDIA_VISION_ERROR_NONE != draw_rectangle_on_buffer( + faces_locations[i].point.x, + faces_locations[i].point.y, + faces_locations[i].point.x + faces_locations[i].width, + faces_locations[i].point.y + faces_locations[i].height, + rectangle_thickness, + drawing_color, + &image_data, + out_buffer)) + { + continue; + } + } + } + + if (!Perform_eye_condition_recognize) + { + if (file_name != NULL && + MEDIA_VISION_ERROR_NONE == save_image_from_buffer( + file_name, + out_buffer, + &image_data, + 100)) + { + printf("Image was generated as %s\n", file_name); + } + else + { + printf("ERROR: Failed to generate output file. Check file name and permissions. \n"); + } + } + + printf("\n"); + } +} + +void on_face_recognized_cb( + 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 (NULL == face_location) + { + printf(TEXT_YELLOW "No faces were recognized in the source" + TEXT_RESET "\n"); + } + else + { + printf(TEXT_GREEN "Face labeled %i was recognized in the source with " + "recognition confidence of %.2f" + TEXT_RESET "\n", *face_label, confidence); + } +} + +int perform_detect() +{ + char *in_file_name = NULL; + char *out_file_name = NULL; + + // 1. Loading media source + while (input_string("Input file name to be analyzed:", 1024, &(in_file_name)) == -1) + { + printf("Incorrect input! Try again.\n"); + } + + mv_source_h source; + int err = mv_create_source(&source); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED + "ERROR: Errors were occurred during creating the source!!! code: %i" + TEXT_RESET "\n", err); + + free(in_file_name); + + return err; + } + + err = load_mv_source_from_file(in_file_name, source); + if (MEDIA_VISION_ERROR_NONE != err) + { + const int err2 = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf(TEXT_RED + "ERROR: Errors were occurred during destroying the source!!! code: %i" + TEXT_RESET "\n", err2); + + free(in_file_name); + + return err2; + } + + free(in_file_name); + + return err; + } + + free(in_file_name); + + // 2. Select output file to be generated + while (input_string("Input file name to be generated:", 1024, &(out_file_name)) == -1) + { + printf("Incorrect input! Try again.\n"); + } + + // 3. Select Haar cascade + const int options[3] = { 1, 2, 3 }; + const char *names[3] = { "haarcascade_frontalface_alt.xml", + "haarcascade_frontalface_alt2.xml", + "haarcascade_frontalface_alt_tree.xml"}; + + const int haarcascade = show_menu("Select Haarcascade:", options, names, 3); + + mv_engine_config_h eng_config; + err = mv_create_engine_config(&eng_config); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED + "ERROR: Errors were occurred during creating the engine config!!! code: %i" + TEXT_RESET "\n", err); + + free(out_file_name); + + return err; + } + + switch (haarcascade) + { + case 1: + mv_engine_config_set_string_attribute( + eng_config, + MV_FACE_DETECTION_MODEL_FILE_PATH, + "/usr/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml"); + break; + case 2: + mv_engine_config_set_string_attribute( + eng_config, + MV_FACE_DETECTION_MODEL_FILE_PATH, + "/usr/share/OpenCV/haarcascades/haarcascade_frontalface_alt2.xml"); + break; + case 3: + mv_engine_config_set_string_attribute( + eng_config, + MV_FACE_DETECTION_MODEL_FILE_PATH, + "/usr/share/OpenCV/haarcascades/haarcascade_frontalface_alt_tree.xml"); + break; + default: + printf(TEXT_YELLOW "Default Haar cascade was set.\n" TEXT_RESET); + } + + // 4. Perform detect + err = mv_face_detect(source, eng_config, on_face_detected_cb, out_file_name); + + free(out_file_name); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED + "ERROR: Errors were occurred during face detection!!! code: %i" + TEXT_RESET "\n", err); + + int err2 = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf(TEXT_RED + "ERROR: Errors were occurred during destroying the source!!! code: %i" + TEXT_RESET "\n", err2); + return err2; + } + + err2 = mv_destroy_engine_config(eng_config); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf(TEXT_RED + "ERROR: Errors were occurred during destroying the engine config!!! code: %i" + TEXT_RESET "\n", err2); + return err2; + } + + return err; + } + + err = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED + "ERROR: Errors were occurred during destroying the source!!! code: %i" + TEXT_RESET "\n", err); + return err; + } + + err = mv_destroy_engine_config(eng_config); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED + "ERROR: Errors were occurred during destroying the engine config!!! code: %i" + TEXT_RESET "\n", err); + return err; + } + + return err; +} + +int perform_mv_face_recognize(mv_face_recognition_model_h model) +{ + char *in_file_name = NULL; + + mv_source_h source = NULL; + int err = mv_create_source(&source); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED + "ERROR: Errors were occurred during creating the source!!! code: %i" + TEXT_RESET "\n", err); + return err; + } + + printf(TEXT_GREEN "HINT:" TEXT_RESET "\n" + TEXT_YELLOW "To achieve appropriate accuracy of recognition,\n" + "choose images with only faces. I.e. face has to cover\n" + "approximately 95-100%% of the image (passport photos\n" + "are the best example :)). Note that if this value is\n" + "less than 95%, accuracy can be significantly reduced.\n" + "In real code such images can be achieved by cropping\n" + "faces from images with face detection functionality.\n" + TEXT_RESET); + while (-1 == input_string( + "Input file name with the face to be recognized:", + 1024, + &(in_file_name))) + { + printf(TEXT_RED "Incorrect input! Try again." TEXT_RESET "\n"); + } + + err = load_mv_source_from_file(in_file_name, source); + + if (MEDIA_VISION_ERROR_NONE != err) + { + free(in_file_name); + + const int err2 = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf(TEXT_RED + "ERROR: Errors were occurred during destroying the source!!! code: %i" + TEXT_RESET "\n", err2); + return err2; + } + + return err; + } + + err = mv_face_recognize(source, model, NULL, NULL, on_face_recognized_cb, NULL); + + if (MEDIA_VISION_ERROR_NONE != err) + { + free(in_file_name); + + printf(TEXT_RED + "ERROR: Errors were occurred during face recognition!!! code: %i" + TEXT_RESET "\n", err); + + int err2 = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf(TEXT_RED + "ERROR: Errors were occurred during destroying the source!!! code: %i" + TEXT_RESET "\n", err2); + return err2; + } + + return err; + } + + free(in_file_name); + + return err; +} + +int add_single_example( + mv_face_recognition_model_h model, const char *in_file_name, + mv_rectangle_s *roi, int *face_label) +{ + mv_source_h source; + int err = mv_create_source(&source); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED + "ERROR: Errors were occurred during creating the source!!! code: %i" + TEXT_RESET "\n", err); + + return err; + } + + err = load_mv_source_from_file(in_file_name, source); + if (MEDIA_VISION_ERROR_NONE != err) + { + const int err2 = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf(TEXT_RED + "ERROR: Errors were occurred during destroying the source!!! code: %i" + TEXT_RESET "\n", err2); + return err2; + } + + return err; + } + + if (NULL != roi && !show_confirm_dialog("Do you want to use full image?")) + { + printf(TEXT_YELLOW "Specify the ROI as rectangle where face is located.\n" + "Use negative values if you want to check correctness\n" + "of error handling.\n" + TEXT_RESET); + + while (-1 == input_int("Specify top left ROI x coordinate:", + INT_MIN, INT_MAX, &(roi->point.x))) + { + printf("Incorrect input! Try again.\n"); + } + + while (-1 == input_int("Specify top left ROI y coordinate:", + INT_MIN, INT_MAX, &(roi->point.y))) + { + printf("Incorrect input! Try again.\n"); + } + + while (-1 == input_int("Specify top left ROI width:", + INT_MIN, INT_MAX, &(roi->width))) + { + printf("Incorrect input! Try again.\n"); + } + + while (-1 == input_int("Specify top left ROI height:", + INT_MIN, INT_MAX, &(roi->height))) + { + printf("Incorrect input! Try again.\n"); + } + } + else + { + roi = NULL; + } + + int real_label = 0; + if (NULL == face_label) + { + printf(TEXT_YELLOW "Also, you has to assign label for the face in the\n" + "image. You has assign the same labels for the same\n" + "persons. For example, always assign label '1' for\n" + "images with Alice's face; label '2' for Bob's faces,\n" + "'3' for Ann's faces and so on...\n" + TEXT_RESET); + + face_label = &real_label; + while (-1 == input_int("Specify label as integer:", + MIN_ALLOWED_LABEL, + MAX_ALLOWED_LABEL, + face_label)) + { + printf("Incorrect input! You can use %i-%i labels only. Try again.\n", + MIN_ALLOWED_LABEL, + MAX_ALLOWED_LABEL); + } + } + + err = mv_face_recognition_model_add(source, model, roi, *face_label); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED + "ERROR: Errors were occurred during adding the sample image from " + "[%s] to the face recognition model!!! code: %i" + TEXT_RESET "\n", in_file_name, err); + } + + const int err2 = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf(TEXT_RED + "ERROR: Errors were occurred during destroying the source!!! code: %i" + TEXT_RESET "\n", err2); + } + + return err; +} + +int perform_mv_face_recognition_model_add_face_example( + mv_face_recognition_model_h model, + notification_type_e *notification_type) +{ + char *in_file_name = NULL; + + printf(TEXT_GREEN "HINT:" TEXT_RESET "\n" + TEXT_YELLOW "To achieve appropriate accuracy of recognition,\n" + "choose images with only faces. I.e. face has to cover\n" + "approximately 95-100%% of the image (passport photos\n" + "are the best example :)). Note that if this value is\n" + "less than 95%, accuracy can be significantly reduced.\n" + "In real code such images can be achieved by cropping\n" + "faces from images with face detection functionality.\n" + TEXT_RESET); + + const bool from_dir = show_confirm_dialog("Do add images from directory?"); + const char *input_path_msg = + from_dir ? "Input path to the directory with the face images to be " + "loaded to the model:" + : "Input file name with the face to be loaded to the model:"; + + while (-1 == input_string(input_path_msg, 1024, &(in_file_name))) + { + printf(TEXT_RED "Incorrect input! Try again." TEXT_RESET "\n"); + } + + int err = MEDIA_VISION_ERROR_NONE; + + if (from_dir) + { + *notification_type = FAIL_OR_DONE; + int face_label = 0; + while (-1 == input_int("Specify label as integer:", + MIN_ALLOWED_LABEL, + MAX_ALLOWED_LABEL, + &face_label)) + { + printf("Incorrect input! You can use %i-%i labels only. Try again.\n", + MIN_ALLOWED_LABEL, + MAX_ALLOWED_LABEL); + } + + DIR *dir; + struct dirent *ent; + if ((dir = opendir(in_file_name)) != NULL) + { + char file_path[1024] = ""; + + // Traverses all the files and directories within source directory + while ((ent = readdir(dir)) != NULL) + { + // Determine current entry name + const char *file_name = ent->d_name; + + // If current entry is directory, or hidden object, skip the step: + if (file_name[0] == '.') + { + continue; + } + + sprintf(file_path, "%s/%s", in_file_name, file_name); + err = add_single_example(model, file_path, NULL, &face_label); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "Failed to add example from %s. " + "Error code: %i\n" TEXT_RESET, + file_path, err); + } + else + { + printf(TEXT_GREEN "Example labeled [%i] added from " TEXT_RESET + TEXT_YELLOW "%s\n" TEXT_RESET, face_label, file_path); + } + } + + closedir(dir); + } + else + { + printf(TEXT_RED "Can't read from specified directory (%s)\n" + TEXT_RESET, in_file_name); + } + } + else + { + *notification_type = FAIL_OR_SUCCESSS; + mv_rectangle_s roi; + err = add_single_example(model, in_file_name, &roi, NULL); + } + + free(in_file_name); + + return err; +} + +int perform_mv_face_recognition_model_reset_face_examples( + mv_face_recognition_model_h model, + bool full_reset) +{ + printf(TEXT_GREEN "HINT:" TEXT_RESET "\n" + TEXT_YELLOW "Reset of the examples will affect only examples has\n" + "been collected via mv_face_recognition_model_add()\n" + "function calls (i.e. through 'Add image example' menu\n" + "item). Previously learned model will be not affected,\n" + "so it is possible to recognize faces with this model\n" + "after examples reset. Reset of the examples can be\n" + "useful to erase a class of faces (i.e. all examples\n" + "related to this class) before learning the model.\n" + "Or, if it is needed to reset all collected previously\n" + "examples as an alternative to the creating the new\n" + "model.\n" + TEXT_RESET); + + int err = MEDIA_VISION_ERROR_NONE; + + if (full_reset) + { + err = mv_face_recognition_model_reset(model, NULL); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED + "ERROR: Errors were occurred during reset of all examples!!!" + " code: %i" TEXT_RESET "\n", err); + return err; + } + } + else + { + int reset_label = 0; + + while (-1 == input_int("Specify label for the examples to be reset:", + MIN_ALLOWED_LABEL, + MAX_ALLOWED_LABEL, + &reset_label)) + { + printf("Incorrect input! You can use %i-%i labels only. Try again.\n", + MIN_ALLOWED_LABEL, + MAX_ALLOWED_LABEL); + } + + err = mv_face_recognition_model_reset(model, &reset_label); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED + "ERROR: Errors were occurred during reset of examples labeled" + " with %i!!! code: %i" TEXT_RESET "\n", reset_label, err); + return err; + } + } + + return err; +} + +int perform_mv_face_recognition_model_save(mv_face_recognition_model_h model) +{ + char *out_file_name = NULL; + + while (input_string("Input file name to save the model:", + 1024, &(out_file_name)) == -1) + { + printf(TEXT_RED "Incorrect input! Try again." TEXT_RESET "\n"); + } + + const int err = mv_face_recognition_model_save(out_file_name, model); + + free(out_file_name); + + return err; +} + +int perform_mv_face_recognition_model_load(mv_face_recognition_model_h *model) +{ + char *in_file_name = NULL; + + while (input_string("Input file name to load model from:", + 1024, &(in_file_name)) == -1) + { + printf(TEXT_RED "Incorrect input! Try again." TEXT_RESET "\n"); + } + + const int err = mv_face_recognition_model_load(in_file_name,model); + + free(in_file_name); + + return err; +} + +int perform_mv_face_recognition_model_clone( + mv_face_recognition_model_h model_to_clone) +{ + int err = MEDIA_VISION_ERROR_NONE; + + mv_face_recognition_model_h cloned_model = NULL; + + printf(TEXT_GREEN "Perform clone of the recognition model..." + TEXT_RESET "\n"); + + err = mv_face_recognition_model_clone(model_to_clone, &cloned_model); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "Errors were occurred during model clone. Error code %i" + TEXT_RESET "\n", err); + return err; + } + + printf(TEXT_YELLOW "Model cloning is done." TEXT_RESET "\n"); + + if (show_confirm_dialog("Save " TEXT_YELLOW "source model" TEXT_RESET + " to file?")) + { + const int serr = perform_mv_face_recognition_model_save(model_to_clone); + if (MEDIA_VISION_ERROR_NONE != serr) + { + printf(TEXT_RED + "Errors were occurred when trying to save " + "source model to file. Error code %i" TEXT_RESET "\n", serr); + } + } + + if (show_confirm_dialog("Save " TEXT_YELLOW "destination model" TEXT_RESET + " to file?")) + { + const int serr = perform_mv_face_recognition_model_save(cloned_model); + if (MEDIA_VISION_ERROR_NONE != serr) + { + printf(TEXT_RED + "Errors were occurred when trying to save destination model " + "to file. Error code %i" TEXT_RESET "\n", serr); + } + } + + if (cloned_model) + { + const int dest_err = mv_face_recognition_model_destroy(cloned_model); + if (MEDIA_VISION_ERROR_NONE != dest_err) + { + printf(TEXT_RED + "Errors were occurred when destroying destination model ." + "Error code %i" TEXT_RESET "\n", dest_err); + } + } + + return err; +} + +int perform_mv_face_recognition_model_learn(mv_face_recognition_model_h model) +{ + printf(TEXT_YELLOW "Learning the model has to be performed after\n" + "adding some amount of examples to the model.\n" + "If you learn without examples, you will get useless\n" + "model, which will be unavailable to recognize. Anyway,\n" + "you can add examples and launch this method again to\n" + "get the appropriate recognition model suitable for\n" + "recognition." + TEXT_RESET "\n"); + + printf(TEXT_GREEN "Start learning process..." TEXT_RESET "\n"); + + const int err = mv_face_recognition_model_learn(NULL, model); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "Learning the model failed. Error code: %i. " + "But you still can test with this model.\n" + TEXT_RESET "\n", err); + } + else + { + printf(TEXT_YELLOW "Recognition model has been learned." + TEXT_RESET "\n"); + } + + return err; +} + +int perform_mv_face_recognition_model_query_labels(mv_face_recognition_model_h model) +{ + int *learned_labels = NULL; + int learned_labels_n = 0; + + const int err = mv_face_recognition_model_query_labels(model, &learned_labels, &learned_labels_n); + + if (MEDIA_VISION_ERROR_NONE != err) + { + free(learned_labels); + + return err; + } + + int i = 0; + printf(TEXT_YELLOW "Recognition model had been learned for the following labels: " + TEXT_RESET "\n" TEXT_GREEN); + for (i = 0; i < learned_labels_n; ++i) + { + printf("%i, ", learned_labels[i]); + } + printf(TEXT_RESET "\n"); + + free(learned_labels); + + return MEDIA_VISION_ERROR_NONE; +} + +static int TP = 0; +static int FP = 0; +static int TN = 0; +static int FN = 0; +static double THRESHOLD = 0.75; + +void evaluation_cb( + 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 (NULL != user_data) + { + const int real_label = *((int*)user_data); + const int rec_label = (NULL != face_label ? *face_label : -1); + if (real_label == -1) + { + confidence >= THRESHOLD ? ++FP : ++TN; + } + else if (real_label == rec_label) + { + confidence >= THRESHOLD ? ++TP : ++FN; + } + else + { + if (confidence >= THRESHOLD) { ++FP; } + ++FN; + } + } +} + +int perform_model_evaluation(mv_face_recognition_model_h model) +{ + int *learned_labels = NULL; + int learned_labels_n = 0; + + mv_face_recognition_model_query_labels(model, &learned_labels, &learned_labels_n); + + int i = 0; + + printf(TEXT_YELLOW "Evaluating model had been learned for the following labels: " + TEXT_RESET "\n" TEXT_GREEN); + for (i = 0; i < learned_labels_n; ++i) + { + printf("%i, ", learned_labels[i]); + } + printf(TEXT_RESET "\n"); + + // 100 directories are allowed: + const int max_dir_allowed = 100; + char (*directories)[1024] = malloc(sizeof *directories * max_dir_allowed); + int labels[max_dir_allowed]; + int unique_checks[MAX_ALLOWED_LABEL + 1]; + for (i = 0; i < MAX_ALLOWED_LABEL + 1; ++i) + { + unique_checks[i] = 0; + } + + int dir_n = 0; + int label_count = 0; + while (show_confirm_dialog("Add test images directory?") && + dir_n < max_dir_allowed) + { + char *in_file_name = NULL; + while (-1 == input_string("Specify path to the test images directory:", 1024, &(in_file_name))) + { + printf(TEXT_RED "Incorrect input! Try again." TEXT_RESET "\n"); + } + + DIR *dir; + if ((dir = opendir(in_file_name)) == NULL) + { + printf(TEXT_RED "Incorrect input! Directory %s can't be read.\n" + TEXT_RESET, in_file_name); + free(in_file_name); + in_file_name = NULL; + continue; + } + else + { + closedir(dir); + } + + int face_label = 0; + if (-1 == input_int("Specify label as integer:", + MIN_ALLOWED_LABEL, + MAX_ALLOWED_LABEL, + &face_label)) + { + printf(TEXT_RED "Incorrect input! You can use %i-%i labels only.\n" + TEXT_RESET, + MIN_ALLOWED_LABEL, + MAX_ALLOWED_LABEL); + free(in_file_name); + in_file_name = NULL; + continue; + } + + bool known_label = false; + for (i = 0; i < learned_labels_n; ++i) + { + if (learned_labels[i] == face_label) + { + known_label = true; + break; + } + } + + if (!known_label) + { + printf(TEXT_YELLOW "Recognition model didn't learn with specified label.\n" + "Images will be marked as unknown (-1)\n" TEXT_RESET); + } + + labels[dir_n] = known_label ? face_label : -1; + strcpy(directories[dir_n], in_file_name); + label_count += (0 == unique_checks[face_label] ? 1 : 0); + if (labels[dir_n] >= 0) + { + unique_checks[labels[dir_n]] += 1; + } + + free(in_file_name); + + ++dir_n; + + printf(TEXT_GREEN "Current test set for %i unique labels:\n" TEXT_RESET, label_count); + for (i = 0; i < dir_n; ++i) + { + printf(TEXT_YELLOW "Label %i: " TEXT_RESET "%s\n", labels[i], directories[i]); + } + } + + free(learned_labels); + + int rec_threshold = 0; + while (-1 == input_int("Specify recognition confidence threshold (0-100%):", 0, 100, &rec_threshold)) + { + printf(TEXT_RED "Incorrect input! You can use 0-100 values only." TEXT_RESET "\n"); + } + THRESHOLD = (double) rec_threshold / 100.0; + + TP = 0; + FP = 0; + TN = 0; + FN = 0; + + mv_source_h source = NULL; + int err = mv_create_source(&source); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED + "ERROR: Errors were occurred during creating the source!!! code: %i" + TEXT_RESET "\n", err); + return err; + } + + for (i = 0; i < dir_n; ++i) + { + DIR *dir; + struct dirent *ent; + printf("Processing %s...\n", directories[i]); + if ((dir = opendir(directories[i])) != NULL) + { + char file_path[1024] = ""; + + // Traverses all the files and directories within source directory + while ((ent = readdir(dir)) != NULL) + { + // Determine current entry name + const char *file_name = ent->d_name; + + // If current entry is directory, or hidden object, skip the step: + if (file_name[0] == '.') + { + continue; + } + + sprintf(file_path, "%s/%s", directories[i], file_name); + err = load_mv_source_from_file(file_path, source); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "Failed to test on example from %s. " + "Example will not affect the evaluation. " + "Error code: %i.\n" TEXT_RESET, + file_path, err); + } + else + { + err = mv_face_recognize(source, model, NULL, NULL, evaluation_cb, &(labels[i])); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "Failed to recognize on example from %s. " + "Example will not affect the evaluation. " + "Error code: %i\n" TEXT_RESET, + file_path, err); + } + } + } + + closedir(dir); + } + else + { + printf(TEXT_RED "Can't read from directory [%s]\n" + TEXT_RESET, directories[i]); + } + } + + int err2 = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err2) + { + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf(TEXT_RED + "ERROR: Errors were occurred during destroying the source!!! code: %i" + TEXT_RESET "\n", err2); + } + } + + double accuracy = (TP + TN) / (double) (TP + FP + TN + FN); + double precision = TP / (double) (TP + FP); + double recall = TP / (double) (TP + FN); + double f1 = 2 * precision * recall / (precision + recall); + + printf(TEXT_GREEN "Evaluation results:\n" TEXT_RESET); + printf(TEXT_YELLOW "\tTRUE POSITIVE : " TEXT_RESET "%5i\n", TP); + printf(TEXT_YELLOW "\tFALSE POSITIVE : " TEXT_RESET "%5i\n", FP); + printf(TEXT_YELLOW "\tTRUE NEGATIVE : " TEXT_RESET "%5i\n", TN); + printf(TEXT_YELLOW "\tFALSE NEGATIVE : " TEXT_RESET "%5i\n", FN); + printf(TEXT_YELLOW "\tAccuracy : " TEXT_RESET "%f\n", accuracy); + printf(TEXT_YELLOW "\tPrecision : " TEXT_RESET "%f\n", precision); + printf(TEXT_YELLOW "\tRecall : " TEXT_RESET "%f\n", recall); + printf(TEXT_YELLOW "\tF1 score : " TEXT_RESET "%f\n", f1); + + free(directories); + + return err; +} + +int perform_recognize() +{ + printf("\n" TEXT_YELLOW + "Recognition model isn't now created.\n" + "You may create it to perform positive \n" + "testing, or don't create to check the \n" + "functionality behaviour for uncreated model." + TEXT_RESET + "\n"); + + int err = MEDIA_VISION_ERROR_NONE; + mv_face_recognition_model_h recognition_model = NULL; + const bool do_create = show_confirm_dialog("Do Create Recognition Model?"); + if (do_create) + { + printf(TEXT_GREEN "Creating recognition model..." TEXT_RESET "\n"); + + err = mv_face_recognition_model_create(&recognition_model); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "Creating the model failed. Error code: %i. " + "But you still can test with uncreated model.\n" + TEXT_RESET "\n", err); + } + else + { + printf(TEXT_YELLOW "Recognition model has been created." + TEXT_RESET "\n"); + } + } + + int sel_opt = 0; + const int options[11] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + const char *names[11] = { "Add image example", + "Reset examples by id", + "Reset all examples", + "Clone the model", + "Learn the model", + "Show learned labels", + "Save model to file", + "Load model from file", + "Recognize with model", + "Evaluate the model", + "Destroy model and exit" }; + + while(!sel_opt) + { + sel_opt = show_menu("Select action:", options, names, 11); + notification_type_e notification_type = FAIL_OR_SUCCESSS; + + switch (sel_opt) + { + case 1: + err = perform_mv_face_recognition_model_add_face_example(recognition_model, ¬ification_type); + break; + case 2: + err = perform_mv_face_recognition_model_reset_face_examples(recognition_model, false); + break; + case 3: + err = perform_mv_face_recognition_model_reset_face_examples(recognition_model, true); + break; + case 4: + err = perform_mv_face_recognition_model_clone(recognition_model); + break; + case 5: + err = perform_mv_face_recognition_model_learn(recognition_model); + break; + case 6: + err = perform_mv_face_recognition_model_query_labels(recognition_model); + break; + case 7: + err = perform_mv_face_recognition_model_save(recognition_model); + break; + case 8: + err = perform_mv_face_recognition_model_load(&recognition_model); + break; + case 9: + err = perform_mv_face_recognize(recognition_model); + break; + case 10: + err = perform_model_evaluation(recognition_model); + break; + case 11: + if (do_create) + { + err = mv_face_recognition_model_destroy(recognition_model); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED + "Error with code %i was occurred during destoy" + TEXT_RESET "\n", err); + } + + return err; + } + else + { + return MEDIA_VISION_ERROR_NONE; + } + default: + sel_opt = 0; + printf("ERROR: Incorrect option was selected.\n"); + continue; + } + + print_action_result(names[sel_opt - 1], err, notification_type); + + sel_opt = 0; + } +} + +int perform_mv_face_tracking_model_save(mv_face_tracking_model_h model) +{ + char *out_file_name = NULL; + + while (input_string("Input file name to save the model:", + 1024, &(out_file_name)) == -1) + { + printf(TEXT_RED "Incorrect input! Try again." TEXT_RESET "\n"); + } + + const int err = mv_face_tracking_model_save(out_file_name, model); + + free(out_file_name); + + return err; +} + +int perform_mv_face_tracking_model_load(mv_face_tracking_model_h *model) +{ + char *in_file_name = NULL; + + while (input_string("Input file name to load model from:", + 1024, &(in_file_name)) == -1) + { + printf(TEXT_RED "Incorrect input! Try again." TEXT_RESET "\n"); + } + + const int err = mv_face_tracking_model_load(in_file_name, model); + + free(in_file_name); + + return err; +} + +int perform_mv_face_tracking_model_clone( + mv_face_tracking_model_h model_to_clone) +{ + int err = MEDIA_VISION_ERROR_NONE; + + mv_face_tracking_model_h cloned_model = NULL; + + printf(TEXT_GREEN "Perform clone of the tracking model..." + TEXT_RESET "\n"); + + err = mv_face_tracking_model_clone(model_to_clone, &cloned_model); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "Errors were occurred during model clone. Error code %i" + TEXT_RESET "\n", err); + return err; + } + + printf(TEXT_YELLOW "Model cloning is done." TEXT_RESET "\n"); + + if (show_confirm_dialog("Save " TEXT_YELLOW "source model" TEXT_RESET + " to file?")) + { + const int serr = perform_mv_face_tracking_model_save(model_to_clone); + if (MEDIA_VISION_ERROR_NONE != serr) + { + printf(TEXT_RED + "Errors were occurred when trying to save " + "source model to file. Error code %i" TEXT_RESET "\n", serr); + } + } + + if (show_confirm_dialog("Save " TEXT_YELLOW "destination model" TEXT_RESET + " to file?")) + { + const int serr = perform_mv_face_tracking_model_save(cloned_model); + if (MEDIA_VISION_ERROR_NONE != serr) + { + printf(TEXT_RED + "Errors were occurred when trying to save destination model " + "to file. Error code %i" TEXT_RESET "\n", serr); + } + } + + if (cloned_model) + { + const int dest_err = mv_face_tracking_model_destroy(cloned_model); + if (MEDIA_VISION_ERROR_NONE != dest_err) + { + printf(TEXT_RED + "Errors were occurred when destroying destination model ." + "Error code %i" TEXT_RESET "\n", dest_err); + } + } + + return err; +} + +static volatile bool frame_read = false; + +void video_1_sample_cb( + char *buffer, + unsigned int buffer_size, + image_data_s image_data, + void *user_data) +{ + if (!frame_read) + { + mv_source_h source = (mv_source_h)user_data; + + const int err = mv_source_fill_by_buffer( + source, + buffer, + buffer_size, + image_data.image_width, + image_data.image_height, + image_data.image_colorspace); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "ERROR: Errors were occurred during filling the " + "source based on the video frame! Error code: %i" + TEXT_RESET, err); + } + + frame_read = true; + } +} + +void face_detected_for_tracking_cb( + mv_source_h source, + mv_engine_config_h engine_cfg, + mv_rectangle_s *faces_locations, + int number_of_faces, + void *user_data) +{ + if (number_of_faces < 1) + { + printf(TEXT_RED "Unfortunatly, no faces were detected on the\n" + "preparation frame. You has to specify bounding\n" + "quadrangles for tracking without advices." + TEXT_RESET "\n"); + return; + } + + printf(TEXT_YELLOW "%i face(s) were detected at the preparation frame.\n" + "Following list includes information on faces bounding\n" + "boxes coordinates:" + TEXT_RESET "\n", number_of_faces); + + int idx = 0; + while (idx < number_of_faces) + { + printf(TEXT_MAGENTA "Face %i bounding box: " TEXT_RESET "\n", ++idx); + printf(TEXT_CYAN "\tTop left point: x1: %4i; y1: %4i\n" TEXT_RESET, + faces_locations[idx - 1].point.x, + faces_locations[idx - 1].point.y); + printf(TEXT_CYAN "\tTop right point: x2: %4i; y2: %4i\n" TEXT_RESET, + faces_locations[idx - 1].point.x + faces_locations[idx - 1].width, + faces_locations[idx - 1].point.y); + printf(TEXT_CYAN "\tBottom right point: x3: %4i; y3: %4i\n" TEXT_RESET, + faces_locations[idx - 1].point.x + faces_locations[idx - 1].width, + faces_locations[idx - 1].point.y + faces_locations[idx - 1].height); + printf(TEXT_CYAN "\tBottom right point: x4: %4i; y4: %4i\n" TEXT_RESET, + faces_locations[idx - 1].point.x, + faces_locations[idx - 1].point.y + faces_locations[idx - 1].height); + } +} + +int load_source_from_first_video_frame(const char *video_file, mv_source_h source) +{ + mv_video_reader_h reader = NULL; + int err = mv_create_video_reader(&reader); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "ERROR: Errors were occurred during creating the video " + "reader! Error code: %i\n" TEXT_RESET, err); + return err; + } + + err = mv_video_reader_set_new_sample_cb( + reader, + video_1_sample_cb, + source); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "ERROR: Errors were occurred during new sample " + "callback set! Error code: %i\n" TEXT_RESET, err); + + const int err2 = mv_destroy_video_reader(reader); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf(TEXT_RED "ERROR: Errors were occurred during video reader " + "destroy! Error code: %i\n" TEXT_RESET, err); + } + + return err; + } + + frame_read = false; + image_data_s video_info; + unsigned int fps; + err = mv_video_reader_load(reader, video_file, &video_info, &fps); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "ERROR: Errors were occurred during loading the video " + "by reader! Error code: %i\n" TEXT_RESET, err); + + const int err2 = mv_destroy_video_reader(reader); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf(TEXT_RED "ERROR: Errors were occurred during video reader " + "destroy! Error code: %i\n" TEXT_RESET, err); + } + + return err; + } + + //wait for the video reading thread + while (true) + { + if (frame_read) + { + int err2 = mv_video_reader_stop(reader); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf(TEXT_RED "ERROR: Errors were occurred during attempt to " + "stop video reader! Error code: %i\n" TEXT_RESET, err2); + } + + err2 = mv_destroy_video_reader(reader); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf(TEXT_RED "ERROR: Errors were occurred during video " + "reader destroy! Error code: %i\n" TEXT_RESET, err2); + } + + break; + } + } + + return MEDIA_VISION_ERROR_NONE; +} + +int perform_mv_face_tracking_model_prepare(mv_face_tracking_model_h model) +{ + printf(TEXT_YELLOW "Before any tracking session the tracking model\n" + "preparation is required. Exception is the case when\n" + "the next tracking session will be performed with the\n" + "video which is the direct continuation of the video\n" + "has been used at the previous tracking session.\n" + "Preparation has to be done with the first frame of\n" + "the video or first image from continuous image\n" + "sequence for which next tracking session plan to be\n" + "performed.\nTracking model preparation includes\n" + "specifying the location of the face to be tracked on\n" + "the first frame. Face tracking algorithm will try to\n" + "grab the face image significant features and\n" + "optionally will try to determine the background.\n" + "Actually, preparation is model-dependent and may\n" + "differs in respect to used tracking algorithm." + TEXT_RESET "\n"); + + int sel_opt = 0; + const int options[2] = { 1, 2 }; + const char *names[2] = { "Prepare with the video file", + "Prepare with the image file" }; + + bool is_video = false; + + while(!sel_opt) + { + sel_opt = show_menu("Select action:", options, names, 2); + switch (sel_opt) + { + case 1: + is_video = true; + break; + case 2: + is_video = false; + break; + default: + sel_opt = 0; + continue; + } + } + + mv_source_h preparation_frame = NULL; + int err = mv_create_source(&preparation_frame); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED + "ERROR: Errors were occurred during creating the source!!! code: %i" + TEXT_RESET "\n", err); + + return err; + } + + char *init_frame_file_name = NULL; + const char *prompt_str = + (is_video ? "Input video file name to prepare the model:" + : "Input image file name to prepare the model:"); + + while (input_string(prompt_str, 1024, &(init_frame_file_name)) == -1) + { + printf(TEXT_RED "Incorrect input! Try again.\n" TEXT_RESET); + } + + if (is_video) + { + err = load_source_from_first_video_frame(init_frame_file_name, preparation_frame); + } + else + { + err = load_mv_source_from_file(init_frame_file_name, preparation_frame); + } + + free(init_frame_file_name); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "ERROR: Errors were occurred during preparation " + "frame/image load! Error code: %i\n" TEXT_RESET, err); + + int err2 = mv_destroy_source(preparation_frame); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf(TEXT_RED "ERROR: Errors were occurred during destroying the " + "source! Error code: %i\n" TEXT_RESET, err2); + } + + return err; + } + + mv_engine_config_h eng_config = NULL; + err = mv_create_engine_config(&eng_config); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "ERROR: Errors were occurred during creating the " + "engine config! Error code: %i\n" TEXT_RESET, err); + } + else + { + err = mv_engine_config_set_string_attribute( + eng_config, + MV_FACE_DETECTION_MODEL_FILE_PATH, + "/usr/share/OpenCV/haarcascades/haarcascade_frontalface_alt2.xml"); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "ERROR: Errors were occurred during setting of the " + "the 'MV_FACE_DETECTION_MODEL_FILE_PATH' attribute " + "for engine configuration! Check media-vision-config.json " + "file existence. Error code: %i" TEXT_RESET, err); + } + } + + err = mv_face_detect( + preparation_frame, + eng_config, + face_detected_for_tracking_cb, + NULL); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "ERROR: Errors were occurred during face detection! " + "Error code: %i\n" TEXT_RESET, err); + + int err2 = mv_destroy_engine_config(eng_config); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf(TEXT_RED "ERROR: Errors were occurred during destroying the " + "engine configuration! Error code: %i\n" TEXT_RESET, err2); + } + + return err; + } + + mv_quadrangle_s roi; + + if (show_confirm_dialog("Do specify the face location?")) + { + printf(TEXT_YELLOW "Specify the coordinates of the quadrangle to be used\n" + "for tracking model preparation:" TEXT_RESET "\n"); + int idx = 0; + char str_prompt[100]; + while (idx < 4) + { + ++idx; + sprintf(str_prompt, "Specify point %i x coordinate: x%i = ", + idx - 1, idx); + while (-1 == input_int(str_prompt, INT_MIN, INT_MAX, + &(roi.points[idx - 1].x))) + { + printf("Incorrect input! Try again.\n"); + } + sprintf(str_prompt, "Specify point %i y coordinate: y%i = ", + idx - 1, idx); + while (-1 == input_int(str_prompt, INT_MIN, INT_MAX, + &(roi.points[idx - 1].y))) + { + printf("Incorrect input! Try again.\n"); + } + } + + err = mv_face_tracking_model_prepare( + model, eng_config, preparation_frame, &roi); + } + else + { + err = mv_face_tracking_model_prepare( + model, eng_config, preparation_frame, NULL); + } + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "ERROR: Errors were occurred during the tracking model " + "preparation! Error code: %i\n" TEXT_RESET, err); + } + + const int err2 = mv_destroy_source(preparation_frame); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf(TEXT_RED "ERROR: Errors were occurred during destroying the " + "source! Error code: %i\n" TEXT_RESET, err2); + } + + return err; +} + +static char *track_output_dir = NULL; + +static int track_frame_counter = 0; + +void track_cb( + mv_source_h source, + mv_face_tracking_model_h tracking_model, + mv_engine_config_h engine_cfg, + mv_quadrangle_s *location, + double confidence, + void *user_data) +{ + static bool track_catch_face = false; + + ++track_frame_counter; + + unsigned char *out_buffer = NULL; + unsigned int buf_size = 0; + image_data_s image_data = { 0, 0, MEDIA_VISION_COLORSPACE_INVALID }; + if (MEDIA_VISION_ERROR_NONE != + mv_source_get_buffer(source, &out_buffer, &buf_size) || + MEDIA_VISION_ERROR_NONE != + mv_source_get_width(source, &(image_data.image_width)) || + MEDIA_VISION_ERROR_NONE != + mv_source_get_height(source, &(image_data.image_height)) || + MEDIA_VISION_ERROR_NONE != + mv_source_get_colorspace(source, &(image_data.image_colorspace))) + { + printf("ERROR: Creating out image is impossible.\n"); + + return; + } + + if (NULL != location) + { + if (!track_catch_face) + { + printf(TEXT_GREEN "Frame %i : Tracked object is appeared" TEXT_RESET "\n", + track_frame_counter); + track_catch_face = true; + } + else + { + printf(TEXT_YELLOW "Frame %i : Tracked object is tracked" TEXT_RESET "\n", + track_frame_counter); + } + + const int rectangle_thickness = 3; + const int drawing_color[] = {255, 0, 0}; + + printf(TEXT_YELLOW + "Location: (%i,%i) -> (%i,%i) -> (%i,%i) -> (%i,%i)\n" + TEXT_RESET, + location->points[0].x, + location->points[0].y, + location->points[1].x, + location->points[1].y, + location->points[2].x, + location->points[2].y, + location->points[3].x, + location->points[3].y); + printf(TEXT_YELLOW "Track confidence: %f" TEXT_RESET "\n", confidence); + + const int err = draw_quadrangle_on_buffer( + *location, + rectangle_thickness, + drawing_color, + &image_data, + out_buffer); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "ERROR: Quadrangle wasn't drew on frame buffer! " + "Error code: %i\n" TEXT_RESET, err); + + return; + } + } + else + { + if (track_catch_face) + { + printf(TEXT_RED "Frame %i : Tracked object is lost" TEXT_RESET "\n", + track_frame_counter); + track_catch_face = false; + } + else + { + printf(TEXT_YELLOW "Frame %i : Tracked object isn't detected" TEXT_RESET "\n", + track_frame_counter); + } + } + + char file_path[1024]; + sprintf(file_path, "%s/%05d.jpg", track_output_dir, track_frame_counter); + if (MEDIA_VISION_ERROR_NONE == save_image_from_buffer( + file_path, out_buffer, &image_data, 100)) + { + printf("Frame %i was outputted as %s\n", track_frame_counter, file_path); + } + else + { + printf(TEXT_RED "ERROR: Failed to generate output file %s. " + "Check file name and permissions.\n" TEXT_RESET, file_path); + } +} + +void track_on_sample_cb( + char *buffer, + unsigned int buffer_size, + image_data_s image_data, + void *user_data) +{ + mv_source_h source = NULL; + int err = mv_create_source(&source); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "ERROR: Errors were occurred during creating the source " + "based on the video frame! Error code: %i\n" TEXT_RESET, err); + + return; + } + + err = mv_source_fill_by_buffer( + source, + buffer, + buffer_size, + image_data.image_width, + image_data.image_height, + image_data.image_colorspace); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "ERROR: Errors were occurred during filling the source " + "based on the video frame! Error code: %i\n" TEXT_RESET , err); + + return; + } + + mv_face_tracking_model_h tracking_model = + (mv_face_tracking_model_h)user_data; + + err = mv_face_track(source, tracking_model, NULL, track_cb, false, NULL); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "ERROR: Errors were occurred during tracking the face " + TEXT_RESET "on the video frame! Error code: %i\n", err); + + return; + } +} + +// end of stream callback +void eos_cb(void *user_data) +{ + printf("Video was fully processed\n"); + if (NULL == user_data) + { + printf(TEXT_RED + "ERROR: eos callback can't stop tracking process."TEXT_RESET); + return; + } + + pthread_mutex_unlock((pthread_mutex_t*)user_data); +} + +int generate_image_sequence( + mv_face_tracking_model_h tracking_model, + const char *track_target_file_name) +{ + mv_video_reader_h reader = NULL; + int err = mv_create_video_reader(&reader); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED + "ERROR: Errors were occurred during creating the video " + "reader! Error code: %i" TEXT_RESET "\n", err); + return err; + } + + image_data_s video_info; + unsigned int fps; + // init_frame_file_name + err = mv_video_reader_load(reader, track_target_file_name, &video_info, &fps); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "ERROR: Errors were occurred during loading the video " + "by reader! Error code: %i" TEXT_RESET "\n", err); + + const int err2 = mv_destroy_video_reader(reader); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf(TEXT_RED "ERROR: Errors were occurred during video reader " + "destroy! Error code: %i" TEXT_RESET "\n", err); + } + + return err; + } + + err = mv_video_reader_set_new_sample_cb( + reader, + track_on_sample_cb, + tracking_model); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED + "ERROR: Errors were occurred during new sample callback set!" + " Error code: %i" TEXT_RESET "\n", err); + + const int err2 = mv_destroy_video_reader(reader); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf(TEXT_RED "ERROR: Errors were occurred during video reader " + "destroy! Error code: %i" TEXT_RESET "\n", err); + } + + return err; + } + + pthread_mutex_t block_during_tracking_mutex; + pthread_mutex_init(&block_during_tracking_mutex, NULL); + pthread_mutex_lock(&block_during_tracking_mutex); + + // set end of stream callback + err = mv_video_reader_set_eos_cb(reader, eos_cb, &block_during_tracking_mutex); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED + "ERROR: Errors were occurred during setting the eos " + "callback for reader! Error code: %i" TEXT_RESET "\n", err); + + const int err2 = mv_destroy_video_reader(reader); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf(TEXT_RED + "ERROR: Errors were occurred during video reader destroy!" + " Error code: %i" TEXT_RESET "\n", err); + } + + pthread_mutex_unlock(&block_during_tracking_mutex); + pthread_mutex_destroy(&block_during_tracking_mutex); + + return err; + } + + err = mv_video_reader_start(reader); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "ERROR: Errors were occurred during starting the " + "video reader! Error code: %i" TEXT_RESET "\n", err); + + const int err2 = mv_destroy_video_reader(reader); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf(TEXT_RED + "ERROR: Errors were occurred during video reader destroy!" + " Error code: %i" TEXT_RESET "\n", err); + } + + pthread_mutex_unlock(&block_during_tracking_mutex); + pthread_mutex_destroy(&block_during_tracking_mutex); + + return err; + } + + //wait for the video reading thread + + pthread_mutex_lock(&block_during_tracking_mutex); + pthread_mutex_unlock(&block_during_tracking_mutex); + pthread_mutex_destroy(&block_during_tracking_mutex); + + err = mv_video_reader_stop(reader); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "ERROR: Errors were occurred during " + "attempt to stop video reader! Error code: %i\n" + TEXT_RESET, err); + } + + err = mv_destroy_video_reader(reader); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "ERROR: Errors were occurred during video " + "reader destroy! Error code: %i\n" TEXT_RESET, err); + } + + return MEDIA_VISION_ERROR_NONE; +} + +int perform_mv_face_track(mv_face_tracking_model_h tracking_model) +{ + printf(TEXT_YELLOW "Before any tracking session the tracking model\n" + "preparation is required. Exception is the case when\n" + "the next tracking session will be performed with the\n" + "video which is the direct continuation of the video\n" + "has been used at the previous tracking session.\n" + "If you want to test correct tracking case, don't\n" + "forget to perform preparation before tracking." + TEXT_RESET "\n"); + + char *track_target_file_name = NULL; + + while (input_string("Input video file name to track on:", + 1024, &(track_target_file_name)) == -1) + { + printf(TEXT_RED "Incorrect input! Try again." TEXT_RESET "\n"); + } + + while (input_string("Input directory to save tracking results:", + 1024, &(track_output_dir)) == -1) + { + printf(TEXT_RED "Incorrect input! Try again." TEXT_RESET "\n"); + } + + track_frame_counter = 0; + + return generate_image_sequence(tracking_model, track_target_file_name); +} + +int perform_track() +{ + printf("\n" TEXT_YELLOW + "Tracking model isn't now created.\n" + "You may create it to perform positive \n" + "testing, or don't create to check the \n" + "functionality behaviour for uncreated model." + TEXT_RESET + "\n"); + + int err = MEDIA_VISION_ERROR_NONE; + mv_face_tracking_model_h tracking_model = NULL; + const bool do_create = show_confirm_dialog("Do Create Tracking Model?"); + if (do_create) + { + printf(TEXT_GREEN "Creating tracking model..." TEXT_RESET "\n"); + + err = mv_face_tracking_model_create(&tracking_model); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED "Creating the model failed. Error code: %i. " + "But you still can test with uncreated model.\n" + TEXT_RESET "\n", err); + } + else + { + printf(TEXT_YELLOW "Tracking model has been created." + TEXT_RESET "\n"); + } + } + + int sel_opt = 0; + const int options[6] = { 1, 2, 3, 4, 5, 6 }; + const char *names[6] = { "Prepare the model", + "Clone the model", + "Save model to file", + "Load model from file", + "Track with model", + "Destroy model and exit" }; + + while(!sel_opt) + { + sel_opt = show_menu("Select action:", options, names, 6); + notification_type_e notification_type = FAIL_OR_SUCCESSS; + + switch (sel_opt) + { + case 1: + err = perform_mv_face_tracking_model_prepare(tracking_model); + break; + case 2: + err = perform_mv_face_tracking_model_clone(tracking_model); + break; + case 3: + err = perform_mv_face_tracking_model_save(tracking_model); + break; + case 4: + err = perform_mv_face_tracking_model_load(&tracking_model); + break; + case 5: + err = perform_mv_face_track(tracking_model); + notification_type = FAIL_OR_DONE; + break; + case 6: + if (do_create) + { + err = mv_face_tracking_model_destroy(tracking_model); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf(TEXT_RED + "Error with code %i was occurred during destroy" + TEXT_RESET "\n", err); + } + + return err; + } + else + { + return MEDIA_VISION_ERROR_NONE; + } + default: + sel_opt = 0; + printf("ERROR: Incorrect input.\n"); + continue; + } + + print_action_result(names[sel_opt - 1], err, notification_type); + + sel_opt = 0; + } +} + +int perform_eye_condition_recognize() +{ + Perform_eye_condition_recognize = true; + + const int err = perform_detect(); + + Perform_eye_condition_recognize = false; + + return err; +} + +int perform_face_expression_recognize() +{ + Perform_facial_expression_recognize = true; + + const int err = perform_detect(); + + Perform_facial_expression_recognize = false; + + return err; +} + +int main(void) +{ + int err = MEDIA_VISION_ERROR_NONE; + + int sel_opt = 0; + const int options[6] = { 1, 2, 3, 4, 5, 6 }; + const char *names[6] = { "Detect", + "Track", + "Recognize", + "Eye condition", + "Face expression", + "Exit" }; + + while (sel_opt == 0) + { + sel_opt = show_menu("Select action:", options, names, 6); + switch (sel_opt) + { + case 1: + err = perform_detect(); + break; + case 2: + err = perform_track(); + break; + case 3: + err = perform_recognize(); + break; + case 4: + err = perform_eye_condition_recognize(); + break; + case 5: + err = perform_face_expression_recognize(); + break; + case 6: + return 0; + default: + sel_opt = 0; + printf("Invalid option.\n"); + continue; + } + + int do_another = 0; + + if (err != MEDIA_VISION_ERROR_NONE) + { + printf("ERROR: Action is finished with error code: %i\n", err); + } + + sel_opt = 0; + const int options_last[2] = { 1, 2 }; + const char *names_last[2] = { "YES", "NO" }; + + while (sel_opt == 0) + { + sel_opt = show_menu("Perform another action?", options_last, names_last, 2); + + switch (sel_opt) + { + case 1: + do_another = 1; + break; + case 2: + do_another = 0; + break; + default: + sel_opt = 0; + printf("Invalid option.\n"); + break; + } + } + + sel_opt = (do_another == 1 ? 0 : sel_opt); + } + + return 0; +} diff --git a/test/testsuites/image/CMakeLists.txt b/test/testsuites/image/CMakeLists.txt new file mode 100644 index 0000000..6c66495 --- /dev/null +++ b/test/testsuites/image/CMakeLists.txt @@ -0,0 +1,41 @@ +project(mv_image_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_IMAGE_HELPER}) +include_directories(${INC_VIDEO_HELPER}) +include_directories(${INC_TS_COMMON}) + +file(GLOB MV_TEST_SUITE_INC_LIST "${PROJECT_SOURCE_DIR}/*.h") +file(GLOB MV_TEST_SUITE_SRC_LIST "${PROJECT_SOURCE_DIR}/*.c") + +find_package(PkgConfig REQUIRED) +pkg_check_modules(GLIB_PKG glib-2.0) + +if (NOT GLIB_PKG_FOUND) + message(SEND_ERROR "Failed to find glib") + return() +else() + include_directories(${GLIB_PKG_INCLUDE_DIRS}) +endif() + +add_executable(${PROJECT_NAME} ${MV_TEST_SUITE_SRC_LIST} ${MV_TEST_SUITE_INC_LIST} ${MV_CAPI_MEDIA_VISION_INC_LIST}) + +target_link_libraries(${PROJECT_NAME} capi-media-vision + glib-2.0 + mv_image_helper + mv_video_helper + mv_testsuite_common) + +install(TARGETS ${PROJECT_NAME} DESTINATION ${testsuites_dir}) diff --git a/test/testsuites/image/image_test_suite.c b/test/testsuites/image/image_test_suite.c new file mode 100644 index 0000000..a0d1a11 --- /dev/null +++ b/test/testsuites/image/image_test_suite.c @@ -0,0 +1,2076 @@ +/** + * 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_image.h" +#include "mv_private.h" + +#include "image_helper.h" +#include "mv_video_helper.h" +#include "mv_testsuite_common.h" + +#include +#include + +#include + +typedef enum +{ + SOURCE_TYPE_GENERATION, + SOURCE_TYPE_LOADING, + SOURCE_TYPE_CLONING, + SOURCE_TYPE_EMPTY, + SOURCE_TYPE_INVALID +} source_type_e; + +typedef enum +{ + OBJECT_TYPE_IMAGE_OBJECT, + OBJECT_TYPE_IMAGE_TRACKING_MODEL, + OBJECT_TYPE_INVALID +} testing_object_type_e; + +#define testing_object_maximum_label_length 300 + +typedef struct testing_object_s +{ + void *entity; + + char origin_label[testing_object_maximum_label_length]; + + char actual_label[testing_object_maximum_label_length]; + + testing_object_type_e object_type; + + source_type_e source_type; + + int cloning_counter; +} testing_object; + +typedef testing_object *testing_object_h; + +void testing_object_create(testing_object_h *result) +{ + (*result) = malloc(sizeof(testing_object)); + + (*result)->entity = (void*)NULL; + (*result)->object_type = OBJECT_TYPE_INVALID; + (*result)->source_type = SOURCE_TYPE_INVALID; + (*result)->cloning_counter = 0; + (*result)->origin_label[0] = '\0'; + (*result)->actual_label[0] = '\0'; +} + +void testing_object_fill( + testing_object_h target, + void *entity, + testing_object_type_e object_type, + source_type_e source_type, + void *source) +{ + target->entity = entity; + target->object_type = object_type; + target->source_type = source_type; + target->cloning_counter = 0; + + switch (source_type) + { + case SOURCE_TYPE_GENERATION: + { + if (OBJECT_TYPE_IMAGE_OBJECT == object_type) + { + sprintf( + target->origin_label, + "generated from \"%s\"", + (char*)source); + } + else if (OBJECT_TYPE_IMAGE_TRACKING_MODEL == object_type) + { + sprintf( + target->origin_label, + "generated from image object which is %s", + ((testing_object_h)source)->actual_label); + } + else + { + sprintf( + target->origin_label, + "generated unknown type of testing object"); + } + + strcpy(target->actual_label, target->origin_label); + break; + } + case SOURCE_TYPE_LOADING: + { + sprintf(target->origin_label, "loaded from \"%s\"", (char*)source); + strcpy(target->actual_label, target->origin_label); + break; + } + case SOURCE_TYPE_CLONING: + { + testing_object_h source_object = (testing_object_h)source; + strcpy(target->origin_label, source_object->origin_label); + target->cloning_counter = source_object->cloning_counter + 1; + + char number_of_cloning[10]; + number_of_cloning[0] = '\0'; + if (1 < target->cloning_counter) + { + sprintf(number_of_cloning, "%s%i%s", + "(x", target->cloning_counter, ")"); + } + + char type_name[20]; + if (OBJECT_TYPE_IMAGE_OBJECT == object_type) + { + sprintf(type_name, "image object"); + } + else if (OBJECT_TYPE_IMAGE_TRACKING_MODEL == object_type) + { + sprintf(type_name, "tracking model"); + } + else + { + sprintf(type_name, "unknown object"); + } + sprintf(target->actual_label, "%s%s%s%s%s%s", + "cloned ", number_of_cloning, + " from ", type_name, + " which is ", target->origin_label); + break; + } + case SOURCE_TYPE_EMPTY: + { + strcpy(target->origin_label, "created an empty"); + strcpy(target->actual_label, target->origin_label); + break; + } + default: + { + strcpy(target->origin_label, "having unknown source"); + break; + } + } +} + +void testing_object_destroy(testing_object_h *target) +{ + switch ((*target)->object_type) + { + case OBJECT_TYPE_IMAGE_OBJECT: + { + int err = mv_image_object_destroy((mv_image_object_h)((*target)->entity)); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("\nERROR: Errors were occurred during image object " + "destroying; code %i\n", err); + } + break; + } + case OBJECT_TYPE_IMAGE_TRACKING_MODEL: + { + int err = mv_image_tracking_model_destroy( + (mv_image_tracking_model_h)((*target)->entity)); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("\nERROR: Errors were occurred during image tracking " + "model destroying; code %i\n", err); + } + break; + } + } + free(*target); + (*target) = NULL; +} + +typedef struct +{ + mv_quadrangle_s **locations; + unsigned int locations_size; + unsigned int currently_number; +} recognition_result; + +void destroy_recognition_result(recognition_result *result) +{ + if (result->locations_size == 0) + { + return; + } + + int i = 0; + for (; i < result->locations_size; ++i) + { + if (NULL != result->locations[i]) + { + free(result->locations[i]); + } + } + free(result->locations); +} + +void recognized_cb( + mv_source_h source, + mv_engine_config_h engine_cfg, + const mv_image_object_h *image_objects, + mv_quadrangle_s **locations, + unsigned int number_of_objects, + void *user_data) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + if (NULL == user_data) + { + return; + } + + recognition_result *result = (recognition_result*)user_data; + + int object_num = 0; + for(; object_num < number_of_objects; ++object_num) + { + if (result->currently_number >= result->locations_size) + { + return; + } + + if (NULL == locations[object_num]) + { + result->locations[result->currently_number] = NULL; + } + else + { + result->locations[result->currently_number] = malloc(sizeof(mv_quadrangle_s)); + *(result->locations[result->currently_number]) = *(locations[object_num]); + } + + ++result->currently_number; + } + + MEDIA_VISION_FUNCTION_LEAVE(); +} + +void handle_recognition_result( + const recognition_result *result, + int number_of_objects, + mv_source_h *source, + char *file_name) +{ + int is_source_data_loaded = 0; + + unsigned char *out_buffer = NULL; + int buffer_size = 0; + image_data_s image_data = { 0, 0, MEDIA_VISION_COLORSPACE_INVALID }; + + if (MEDIA_VISION_ERROR_NONE != mv_source_get_buffer(source, &(out_buffer), &buffer_size) || + MEDIA_VISION_ERROR_NONE != mv_source_get_width(source, &(image_data.image_width)) || + MEDIA_VISION_ERROR_NONE != mv_source_get_height(source, &(image_data.image_height)) || + MEDIA_VISION_ERROR_NONE != mv_source_get_colorspace(source, &(image_data.image_colorspace)) || + NULL == file_name) + { + printf("ERROR: Creating out image is impossible.\n"); + } + else + { + is_source_data_loaded = 1; + } + + int object_num = 0; + + + for (; object_num < number_of_objects; ++object_num) + { + if (NULL == result->locations[object_num]) + { + printf("\nImage #%i is not recognized\n", object_num); + continue; + } + + printf("\nImage #%i is recognized\n", object_num); + printf("Recognized image coordinates:\n"); + + int point_num = 0; + for (; point_num < 4; ++point_num) + { + printf("%d point - x = %d, y = %d\n", point_num + 1, + result->locations[object_num]->points[point_num].x, + result->locations[object_num]->points[point_num].y); + } + + if (is_source_data_loaded) + { + const int thickness = 2; + const int color[] = {0, 255, 0}; + + const int err = draw_quadrangle_on_buffer( + *(result->locations[object_num]), + thickness, + color, + &image_data, + out_buffer); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Impossible to draw quadrangle\n"); + } + } + } + if (save_image_from_buffer(file_name, out_buffer, + &image_data, 100) != MEDIA_VISION_ERROR_NONE) + { + printf("\nERROR: Failed to generate output file\n"); + } + else + { + printf("\nImage was generated as %s\n", file_name); + } +} + +int generate_image_object_from_file(const char *path_to_image, + bool roi_selected, + mv_rectangle_s roi, + mv_image_object_h *result) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + mv_source_h source; + int err = mv_create_source(&source); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Errors were occurred during source creating!!! code %i\n", err); + } + + err = load_mv_source_from_file(path_to_image, source); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: image is not loaded; code %i\n", err); + + int err2 = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf("\nERROR: Errors were occurred during source " + "destroying; code %i\n", err2); + } + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; + } + + mv_engine_config_h config; + err = mv_create_engine_config(&config); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: engine configuration is not created; code %i\n", err); + + int err2 = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf("\nERROR: Errors were occurred during source " + "destroying; code %i\n", err2); + } + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; + } + + err = mv_image_object_create(result); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Errors were occurred during creating image object; " + "code %i\n", err); + + int err2 = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf("\nERROR: Errors were occurred during source " + "destroying; code %i\n", err2); + } + + err2 = mv_destroy_engine_config(config); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf("\nERROR: Errors were occurred during engine config " + "destroying; code %i\n", err2); + } + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; + } + + if (roi_selected) + { + err = mv_image_object_fill(*result, config, source, &roi); + } + else + { + err = mv_image_object_fill(*result, config, source, NULL); + } + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: Errors were occurred during filling image object; " + "code %i\n", err); + + int err2 = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf("\nERROR: Errors were occurred during source " + "destroying; code %i\n", err2); + } + + err2 = mv_image_object_destroy(*result); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf("\nERROR: Errors were occurred during image object " + "destroying; code %i\n", err2); + } + + err2 = mv_destroy_engine_config(config); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf("\nERROR: Errors were occurred during engine config " + "destroying; code %i\n", err2); + } + + *result = NULL; + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; + } + + err = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("\nERROR: Errors were occurred during source " + "destroying; code %i\n", err); + + int err2 = mv_destroy_engine_config(config); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf("\nERROR: Errors were occurred during engine config " + "destroying; code %i\n", err2); + } + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; + } + + err = mv_destroy_engine_config(config); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("\nERROR: Errors were occurred during engine config " + "destroying; code %i\n", err); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; + } + + MEDIA_VISION_FUNCTION_LEAVE(); + return err; +} + +int recognize_image(const char *path_to_image, + const char *path_to_generated_image, + mv_image_object_h *targets, + int number_of_targets) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + + if (NULL == targets) + { + printf("\nYou must create at least one model for recognition\n"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + mv_source_h source; + int err = mv_create_source(&source); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("\nERROR: Errors were occurred during source creating; code %i\n", err); + return err; + } + + err = load_mv_source_from_file(path_to_image, source); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: image is not loaded; code %i\n", err); + int err2 = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf("\nERROR: Errors were occurred during source destroying; " + "code %i\n", err2); + } + MEDIA_VISION_FUNCTION_LEAVE(); + return err; + } + + recognition_result result; + result.currently_number = 0; + if (0 < number_of_targets) + { + result.locations = malloc(sizeof(mv_quadrangle_s*) * number_of_targets); + result.locations_size = number_of_targets; + } + else + { + result.locations = NULL; + result.locations_size = 0; + } + + mv_engine_config_h config; + err = mv_create_engine_config(&config); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: engine configuration is not created; code %i\n", err); + int err2 = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf("\nERROR: Errors were occurred during source destroying;" + "code %i\n", err2); + } + MEDIA_VISION_FUNCTION_LEAVE(); + return err; + } + + err = mv_image_recognize(source, targets, number_of_targets, config, + recognized_cb, &result); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("\nERROR: Image is not recognized; code %i\n", err); + + destroy_recognition_result(&result); + + int err2 = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf("\nERROR: Errors were occurred during source " + "destroying; code %i\n", err2); + } + err2 = mv_destroy_engine_config(config); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf("\nERROR: Errors were occurred during engine config " + "destroying; code %i\n", err2); + } + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; + } + + handle_recognition_result(&result, number_of_targets, source, + path_to_generated_image); + + destroy_recognition_result(&result); + + err = mv_destroy_source(source); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("\nERROR: Errors were occurred during source destroying; code %i\n", + err); + + int err2 = mv_destroy_engine_config(config); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf("\nERROR: Errors were occurred during engine config " + "destroying; code %i\n", err2); + } + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; + } + + err = mv_destroy_engine_config(config); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("\nERROR: Errors were occurred during engine config destroying; " + "code %i\n", err); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; + } + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; +} + +int perform_get_confidence(mv_image_object_h target) +{ + if (NULL == target) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + double confidence = 0; + const int err = mv_image_object_get_recognition_rate(target, &confidence); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("\nError: confidence hasn't been received with error code %i\n", err); + return err; + } + + printf("\nConfidence has been successfully received. Its value equal %f.\n", confidence); + + return MEDIA_VISION_ERROR_NONE; +} + +int perform_set_label(mv_image_object_h target) +{ + if (NULL == target) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + int label = 0; + + while (input_int("Input label (int):", INT_MIN, INT_MAX, + &label) == -1) + { + printf("Incorrect input! Try again.\n"); + } + + const int err = mv_image_object_set_label(target, label); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("\nError: the label hasn't been set with error code %i\n", err); + return err; + } + + printf("\nLabel has been successfully set.\n"); + + return MEDIA_VISION_ERROR_NONE; +} + +int perform_get_label(mv_image_object_h target) +{ + if (NULL == target) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + int label = 0; + const int err = mv_image_object_get_label(target, &label); + if (MEDIA_VISION_ERROR_NO_DATA == err) + { + printf("\nSelected image object haven't label.\n"); + return MEDIA_VISION_ERROR_NONE; + } + else if (MEDIA_VISION_ERROR_NONE != err) + { + printf("\nError: label hasn't been received with error code %i\n", err); + return err; + } + + printf("\nLabel has been successfully received. Its equal %i.\n", label); + + return MEDIA_VISION_ERROR_NONE; +} + +int perform_recognize(mv_image_object_h *targets, int number_of_targets) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + char *path_to_image = NULL; + char *path_to_generated_image = NULL; + + while (input_string("Input file name with image for recognizing:", + 1024, &path_to_image) == -1) + { + printf("Incorrect input! Try again.\n"); + } + + while (input_string("Input file name for generated image:", + 1024, &path_to_generated_image) == -1) + { + printf("Incorrect input! Try again.\n"); + } + + const int err = recognize_image(path_to_image, path_to_generated_image, targets, + number_of_targets); + + free(path_to_image); + free(path_to_generated_image); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; +} + +int perform_load_image_object(char **path_to_object, mv_image_object_h *result) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + if (NULL != (*result)) + { + mv_image_object_destroy(*result); + *result = NULL; + } + + while (input_string("Input file name with image object to be loaded:", + 1024, path_to_object) == -1) + { + printf("Incorrect input! Try again.\n"); + } + + int err = mv_image_object_load(result, *path_to_object); + + if (MEDIA_VISION_ERROR_NONE != err && NULL != (*result)) + { + printf("Error: object isn't loaded with error code %i\n", err); + return err; + } + + printf("\nObject successfully loaded\n"); + + MEDIA_VISION_FUNCTION_LEAVE(); + return err; +} + +int perform_save_image_object(mv_image_object_h object) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + int err = MEDIA_VISION_ERROR_NONE; + char *path_to_object = NULL; + + while (input_string("Input file name to be generated for image object storing:", + 1024, &path_to_object) == -1) + { + printf("Incorrect input! Try again.\n"); + } + + err = mv_image_object_save(path_to_object, object); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("\nError during saving the image object. Error code is %i\n", err); + free(path_to_object); + return err; + } + + printf("\nObject successfully saved\n"); + + free(path_to_object); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; +} + +int perform_generate_image_object(mv_image_object_h *result, char **path_to_image) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + if (NULL == path_to_image || NULL == result) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + while (input_string("Input file name with image to be analyzed:", + 1024, path_to_image) == -1) + { + printf("Incorrect input! Try again.\n"); + } + + mv_rectangle_s roi; + const bool sel_roi = show_confirm_dialog("Select if you want to set ROI"); + if (sel_roi) + { + printf("\nInput ROI coordinates\n"); + while (input_int("Input x coordinate:", INT_MIN, INT_MAX, + &(roi.point.x)) == -1) + { + printf("Incorrect input! Try again.\n"); + } + + while (input_int("Input y coordinate:", INT_MIN, INT_MAX, + &(roi.point.y)) == -1) + { + printf("Incorrect input! Try again.\n"); + } + + while (input_int("Input ROI width:", INT_MIN, INT_MAX, + &(roi.width)) == -1) + { + printf("Incorrect input! Try again.\n"); + } + + while (input_int("Input ROI height:", INT_MIN, INT_MAX, + &(roi.height)) == -1) + { + printf("Incorrect input! Try again.\n"); + } + + } + + int err = generate_image_object_from_file(*path_to_image, sel_roi, roi, result); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("\nError in generation image object. Error code is %i\n", err); + + if (NULL != (*result)) + { + mv_image_object_destroy(*result); + (*result) = NULL; + } + + return err; + } + + printf("\nObject successfully generated\n"); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; +} + +int perform_clone_image_object(mv_image_object_h src, mv_image_object_h *result) +{ + int err = mv_image_object_clone(src, result); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("\nError: object isn't cloned with error code %i\n", err); + + int err2 = mv_image_object_destroy(*result); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf("\nERROR: Errors were occurred during image object " + "destroying; code %i\n", err); + } + + (*result) = NULL; + + return err; + } + + printf("\nObject successfully cloned\n"); + + return err; +} + +int handle_tracking_result( + mv_video_writer_h writer, + mv_source_h frame, + int frame_number, + mv_quadrangle_s *location) +{ + unsigned char *data_buffer = NULL; + unsigned int buffer_size = 0; + image_data_s image_data; + + int err = mv_source_get_buffer(frame, &data_buffer, &buffer_size); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf( + "ERROR: Errors were occurred during getting buffer from the " + "source; code %i\n", + err); + return err; + } + + err = mv_source_get_width(frame, &image_data.image_width); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf( + "ERROR: Errors were occurred during getting width from the " + "source; code %i\n", + err); + return err; + } + + err = mv_source_get_height(frame, &image_data.image_height); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf( + "ERROR: Errors were occurred during getting height from the " + "source; code %i\n", + err); + return err; + } + + if (location) + { + printf( + "Frame #%i: object is found." + "Location: {%i, %i}; {%i, %i}; {%i, %i}; {%i, %i}.\n", + frame_number, + location->points[0].x, + location->points[0].y, + location->points[1].x, + location->points[1].y, + location->points[2].x, + location->points[2].y, + location->points[3].x, + location->points[3].y); + const int thickness = 2; + const int color[] = {0, 255, 0}; + + err = draw_quadrangle_on_buffer( + *location, + thickness, + color, + &image_data, + data_buffer); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf( + "ERROR: Errors were occurred during drawing quadrangle on " + "the frame; code %i\n", + err); + return err; + } + } + else + { + usleep(1000000); + printf("Frame #%i: object isn't found.\n", frame_number); + } + + err = mv_video_writer_write_frame(writer, data_buffer); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf( + "ERROR: Errors were occurred during writing frame to the " + "result video file; code %i\n", + err); + return err; + } + + return err; +} + +typedef struct +{ + mv_image_tracking_model_h target; + mv_video_writer_h writer; + int frame_number; +} tracking_cb_data; + +void tracked_cb( + mv_source_h source, + mv_image_object_h image_object, + mv_engine_config_h engine_cfg, + mv_quadrangle_s *location, + void *user_data) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + if (NULL == user_data) + { + return; + } + + tracking_cb_data *cb_data = (tracking_cb_data*)user_data; + + handle_tracking_result(cb_data->writer, source, cb_data->frame_number, location); + + MEDIA_VISION_FUNCTION_LEAVE(); +} + +void new_frame_cb( + char *buffer, + unsigned int buffer_size, + image_data_s image_data, + void *user_data) +{ + if (NULL == user_data) + { + return; + } + + mv_source_h frame = NULL; + +#define release_resources() \ + if (frame) \ + { \ + const int err2 = mv_destroy_source(frame); \ + if (MEDIA_VISION_ERROR_NONE != err2) \ + { \ + printf( \ + "\nERROR: Errors were occurred during source destroying; " \ + "code %i\n", \ + err2); \ + } \ + } + + tracking_cb_data *cb_data = (tracking_cb_data*)user_data; + + ++(cb_data->frame_number); + + int err = mv_create_source(&frame); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf( + "\nERROR: Errors were occurred during source creating; " + "code %i\n", + err); + release_resources(); + return; + } + + err = mv_source_fill_by_buffer( + frame, + buffer, + buffer_size, + image_data.image_width, + image_data.image_height, + image_data.image_colorspace); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: mv_source_h for frame is not filled; code %i\n", err); + release_resources(); + return; + } + + err = mv_image_track( + frame, + cb_data->target, + NULL, + tracked_cb, + cb_data); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf( + "ERROR: Errors were occurred during tracking object on " + "the video; code %i\n", + err); + release_resources(); + return; + } + + release_resources() + +#undef release_resources() +} + +void eos_frame_cb( + void *user_data) +{ + if (NULL == user_data) + { + printf("ERROR: eos callback can't stop tracking process."); + return; + } + + pthread_mutex_unlock((pthread_mutex_t*)user_data); +} + +int perform_track(mv_image_tracking_model_h target) +{ + if (NULL == target) + { + printf("\nTarget is invalid. It is impossible to track of this target.\n"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + MEDIA_VISION_FUNCTION_ENTER(); + + mv_video_reader_h reader = NULL; + mv_video_writer_h writer = NULL; + char *path_to_video = NULL; + char *path_to_generated_video = NULL; + image_data_s image_data = {0}; + unsigned int fps = 0; + +#define release_resources() \ + int err2 = MEDIA_VISION_ERROR_NONE; \ + if (reader) \ + { \ + err2 = mv_destroy_video_reader(reader); \ + if (MEDIA_VISION_ERROR_NONE != err2) \ + { \ + printf( \ + "\nERROR: Errors were occurred during video reader destroying; " \ + "code %i\n", \ + err2); \ + } \ + } \ + if (writer) \ + { \ + err2 = mv_destroy_video_writer(writer); \ + if (MEDIA_VISION_ERROR_NONE != err2) \ + { \ + printf( \ + "\nERROR: Errors were occurred during video writer destroying; " \ + "code %i\n", \ + err2); \ + } \ + } \ + if (path_to_video) \ + { \ + free(path_to_video); \ + } \ + if (path_to_generated_video) \ + { \ + free(path_to_generated_video); \ + } + + while (input_string("Input file name with video for tracking:", + 1024, &path_to_video) == -1) + { + printf("Incorrect input! Try again.\n"); + } + + while (input_string("Input file name for generated video:", + 1024, &path_to_generated_video) == -1) + { + printf("Incorrect input! Try again.\n"); + } + + int err = mv_create_video_reader(&reader); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("\nERROR: Errors were occurred during video reader creating; " + "code %i\n", err); + release_resources(); + MEDIA_VISION_FUNCTION_LEAVE(); + return err; + } + + err = mv_create_video_writer(&writer); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf( + "\nERROR: Errors were occurred during video writer creating; " + "code %i\n", + err); + release_resources(); + MEDIA_VISION_FUNCTION_LEAVE(); + return err; + } + + err = mv_video_reader_load( + reader, + path_to_video, + &image_data, + &fps); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("\nERROR: Errors were occurred during video loading; code %i\n", err); + release_resources(); + MEDIA_VISION_FUNCTION_LEAVE(); + return err; + } + + printf("Receive frame metadata: wxh - %ux%u, fps - %u, format - %d\n", + image_data.image_width, image_data.image_height, fps, image_data.image_colorspace); + + // Temporary we accept only RGB888 + image_data.image_colorspace = MEDIA_VISION_COLORSPACE_RGB888; + + err = mv_video_writer_init( + writer, + path_to_generated_video, + image_data, + fps); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf( + "\nERROR: Errors were occurred during video writer initializing; " + "code %i\n", + err); + release_resources(); + MEDIA_VISION_FUNCTION_LEAVE(); + return err; + } + + tracking_cb_data cb_data; + cb_data.target = target; + cb_data.writer = writer; + cb_data.frame_number = 0; + err = mv_video_reader_set_new_sample_cb(reader, new_frame_cb, &cb_data); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf( + "\nERROR: Errors were occurred during set new frame callback; " + "code %i\n", + err); + release_resources(); + MEDIA_VISION_FUNCTION_LEAVE(); + return err; + } + + pthread_mutex_t block_during_tracking_mutex; + pthread_mutex_init(&block_during_tracking_mutex, NULL); + pthread_mutex_lock(&block_during_tracking_mutex); + err = mv_video_reader_set_eos_cb(reader, eos_frame_cb, &block_during_tracking_mutex); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf( + "\nERROR: Errors were occurred during set new frame callback; " + "code %i\n", + err); + release_resources(); + pthread_mutex_unlock(&block_during_tracking_mutex); + pthread_mutex_destroy(&block_during_tracking_mutex); + MEDIA_VISION_FUNCTION_LEAVE(); + return err; + } + + err = mv_video_reader_start(reader); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf( + "\nERROR: Errors were occurred during video reading starts; " + "code %i\n", + err); + release_resources(); + pthread_mutex_unlock(&block_during_tracking_mutex); + pthread_mutex_destroy(&block_during_tracking_mutex); + MEDIA_VISION_FUNCTION_LEAVE(); + return err; + } + + pthread_mutex_lock(&block_during_tracking_mutex); + pthread_mutex_unlock(&block_during_tracking_mutex); + pthread_mutex_destroy(&block_during_tracking_mutex); + release_resources(); + +#undef release_resources() + + printf("\nTracking process is finished\n"); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; +} + +int perform_save_image_tracking_model(mv_image_tracking_model_h model) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + int err = MEDIA_VISION_ERROR_NONE; + char *path_to_file = NULL; + + while (input_string( + "Input file name to be generated for image tracking model storing:", + 1024, + &path_to_file) == -1) + { + printf("Incorrect input! Try again.\n"); + } + + err = mv_image_tracking_model_save(path_to_file, model); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf( + "\nError during saving the image tracking model. " + "Error code is %i\n", + err); + free(path_to_file); + return err; + } + + printf("\nTracking model successfully saved\n"); + + free(path_to_file); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; +} + +int perform_load_image_tracking_model( + char **path_to_file, mv_image_tracking_model_h *result) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + while (input_string( + "Input file name with image tracking model to be loaded:", + 1024, + path_to_file) == -1) + { + printf("Incorrect input! Try again.\n"); + } + + int err = mv_image_tracking_model_load(*path_to_file, result); + + if (MEDIA_VISION_ERROR_NONE != err && NULL != (*result)) + { + printf("Error: tracking model isn't loaded with error code %i\n", err); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; + } + + printf("\nTracking model successfully loaded\n"); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; +} + +int perform_clone_image_tracking_model( + mv_image_tracking_model_h src, + mv_image_tracking_model_h *result) +{ + MEDIA_VISION_FUNCTION_ENTER(); + + int err = mv_image_tracking_model_clone(src, result); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("\nError: tracking model isn't cloned with error code %i\n", err); + + int err2 = mv_image_tracking_model_destroy(*result); + if (MEDIA_VISION_ERROR_NONE != err2) + { + printf("\nERROR: Errors were occurred during tracking model " + "destroying; code %i\n", err); + } + + (*result) = NULL; + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; + } + + printf("\nTracking model successfully cloned\n"); + + MEDIA_VISION_FUNCTION_LEAVE(); + + return err; +} + +int perform_refresh_image_tracking_model(mv_image_tracking_model_h target) +{ + if (NULL == target) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + const int err = mv_image_tracking_model_refresh(target, NULL); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("\nError: tracking model isn't refreshed with error code %i\n", err); + return err; + } + + printf("\nTracking model is successfully refreshed.\n"); + + return MEDIA_VISION_ERROR_NONE; +} + +void show_testing_objects(const char *title, GArray *testing_objects) +{ + printf("\n"); + int i = 0; + if (1 > testing_objects->len) + { + printf("There are no created objects.\n"); + } + else + { + printf("%s:\n", title); + printf("-------------------------------------------------------------------------------------\n"); + for (i = 0; i < testing_objects->len; ++i) + { + testing_object_h temp = g_array_index (testing_objects, testing_object_h, i); + if (OBJECT_TYPE_IMAGE_OBJECT == temp->object_type) + { + printf("Image object "); + } + else if (OBJECT_TYPE_IMAGE_TRACKING_MODEL == temp->object_type) + { + printf("Image tracking model "); + } + else + { + printf("Unknown testing object "); + } + printf("#%i. %s\n", i, temp->actual_label); + } + printf("-------------------------------------------------------------------------------------\n"); + } +} + +int select_testing_object(GArray *testing_objects, testing_object_h *result, char *title) +{ + if (0 == testing_objects->len) + { + printf("Firstly you must create at least one testing object.\n"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + show_testing_objects(title, testing_objects); + int sel_index = 0; + while (input_int("Input number of element:", 0, + testing_objects->len - 1, &sel_index) == -1) + { + printf("Incorrect input! Try again.\n"); + } + (*result) = g_array_index(testing_objects, testing_object_h, sel_index); + return MEDIA_VISION_ERROR_NONE; +} + +int select_testing_object_index(GArray *testing_objects, guint *result_index, char *title) +{ + if (0 == testing_objects->len) + { + printf("Firstly you must create at least one testing object.\n"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + show_testing_objects(title, testing_objects); + + int sel_index = 0; + while (input_int("Input number of element:", 0, + testing_objects->len - 1, &sel_index) == -1) + { + printf("Incorrect input! Try again.\n"); + } + (*result_index) = sel_index; + return MEDIA_VISION_ERROR_NONE; +} + +int add_testing_object(GArray *testing_objects, testing_object_h object) +{ + if (NULL == object) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + g_array_append_val(testing_objects, object); + return MEDIA_VISION_ERROR_NONE; +} + +int remove_testing_object(GArray *testing_objects, guint index) +{ + if (index >= testing_objects->len) + { + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + g_array_remove_index(testing_objects, index); + return MEDIA_VISION_ERROR_NONE; +} + +void perform_recognition_cases(GArray *image_objects) +{ + const char *names[] = { + "Show created set of image objects", + "Generate new image object from source image (mv_image_object_fill )", + "Load existed image object from file (mv_image_object_load)", + "Clone existed image object (mv_image_object_clone)", + "Create empty image object (mv_image_object_create)", + "Save existed image object to the file (mv_image_object_save)", + "Remove image object from created set (mv_image_object_destroy)", + "Get confidence from existed image object (mv_image_object_get_recognition_rate)", + "Recognize all image objects on image (mv_image_recognize)", + "Set label for existed image object (mv_image_set_label_of_object)", + "Get label from existed image object (mv_image_get_label_of_object)", + "Back to the main menu"}; + + int number_of_options = sizeof(names) / sizeof(names[0]); + int options[number_of_options]; + int index = 0; + for (; index < number_of_options; ++index) + { + options[index] = index + 1; + } + + while (1) + { + int err = MEDIA_VISION_ERROR_NONE; + + int sel_opt = show_menu("Select action:", options, names, number_of_options); + + switch (sel_opt) + { + case 1: // Show created set of image objects + { + show_testing_objects("Set of image objects", image_objects); + break; + } + case 2: // Generate new image object from source image (mv_image_object_fill) + { + mv_image_object_h temporary = NULL; + char *path_to_image = NULL; + + err = perform_generate_image_object(&temporary, &path_to_image); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("Generation failed (error code - %i)\n", err); + if (NULL != path_to_image) + { + free(path_to_image); + } + break; + } + + testing_object_h added_object; + testing_object_create(&added_object); + testing_object_fill(added_object, temporary, + OBJECT_TYPE_IMAGE_OBJECT, SOURCE_TYPE_GENERATION, path_to_image); + + if (NULL != path_to_image) + { + free(path_to_image); + } + + add_testing_object(image_objects, added_object); + break; + } + case 3: // Load existed image object from file (mv_image_object_load) + { + mv_image_object_h temporary_image_object = NULL; + char *path_to_object = NULL; + + err = perform_load_image_object( + &path_to_object, &temporary_image_object); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("Loading failed (error code - %i)\n", err); + break; + } + + testing_object_h added_object = NULL; + testing_object_create(&added_object); + testing_object_fill( + added_object, + temporary_image_object, + OBJECT_TYPE_IMAGE_OBJECT, + SOURCE_TYPE_LOADING, + path_to_object); + + free(path_to_object); + + add_testing_object(image_objects, added_object); + break; + } + case 4: // Clone existed image object (mv_image_object_clone) + { + if (image_objects->len <= 0) + { + printf("\nFirstly you must create at least one image object.\n"); + break; + } + + testing_object_h temporary_testing_object = NULL; + select_testing_object( + image_objects, + &temporary_testing_object, + "Select the object you want to clone"); + + mv_image_object_h temporary_image_object = NULL; + perform_clone_image_object( + temporary_testing_object->entity, + &temporary_image_object); + + testing_object_h added_object = NULL; + testing_object_create(&added_object); + testing_object_fill( + added_object, + temporary_image_object, + OBJECT_TYPE_IMAGE_OBJECT, + SOURCE_TYPE_CLONING, + temporary_testing_object); + + add_testing_object(image_objects, added_object); + break; + } + case 5: // Create empty image object (mv_image_object_create) + { + mv_image_object_h temporary_image_object = NULL; + int err = mv_image_object_create(&temporary_image_object); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: image object creation is failed with code %i\n", err); + break; + } + + testing_object_h added_object = NULL; + testing_object_create(&added_object); + testing_object_fill( + added_object, + temporary_image_object, + OBJECT_TYPE_IMAGE_OBJECT, + SOURCE_TYPE_EMPTY, + NULL); + + add_testing_object(image_objects, added_object); + printf("\nImage object successfully created\n"); + break; + } + case 6: // Save existed image object to the file (mv_image_object_save) + { + if (image_objects->len <= 0) + { + printf("\nFirstly you must create at least one image object.\n"); + break; + } + + testing_object_h temporary_testing_object = NULL; + select_testing_object(image_objects, &temporary_testing_object, + "Select the object you want to save"); + perform_save_image_object(temporary_testing_object->entity); + break; + } + case 7: // Remove image object from created set (mv_image_object_destroy) + { + if (image_objects->len <= 0) + { + printf("\nFirstly you must create at least one image object.\n"); + break; + } + + guint selected_index; + int err = select_testing_object_index( + image_objects, + &selected_index, + "Select the object you want to remove"); + if (MEDIA_VISION_ERROR_NONE == err) + { + remove_testing_object(image_objects, selected_index); + printf("\nImage object successfully removed\n"); + } + break; + } + case 8: // Get confidence from existed image object (mv_image_object_get_recognition_rate) + { + if (image_objects->len <= 0) + { + printf("\nFirstly you must create at least one image object.\n"); + break; + } + + testing_object_h temporary_testing_object = NULL; + select_testing_object(image_objects, &temporary_testing_object, + "Select the object from which you want getting confidence"); + perform_get_confidence(temporary_testing_object->entity); + break; + } + case 9: // Recognize all image objects on image (mv_image_recognize) + { + if (image_objects->len <= 0) + { + printf("\nFirstly you must create at least one image object.\n"); + break; + } + + mv_image_object_h *objects_pool = malloc(sizeof(mv_image_object_h) * image_objects->len); + int index = 0; + for (;index < image_objects->len; ++index) + { + objects_pool[index] = g_array_index(image_objects, testing_object_h, index)->entity; + } + perform_recognize(objects_pool, image_objects->len); + free(objects_pool); + break; + } + case 10: // Set label for existed image object (mv_image_object_set_label) + { + if (image_objects->len <= 0) + { + printf("\nFirstly you must create at least one image object.\n"); + break; + } + + testing_object_h temporary_testing_object = NULL; + select_testing_object(image_objects, &temporary_testing_object, + "Select the object for which you want setting label"); + perform_set_label(temporary_testing_object->entity); + break; + } + case 11: // Get label from existed image object (mv_image_object_get_label) + { + if (image_objects->len <= 0) + { + printf("\nFirstly you must create at least one image object.\n"); + break; + } + + testing_object_h temporary_testing_object = NULL; + select_testing_object(image_objects, &temporary_testing_object, + "Select the object from which you want getting label"); + perform_get_label(temporary_testing_object->entity); + break; + } + case 12: // Back to the main menu + { + return; + } + default: + printf("Invalid option.\n"); + } + } +} + +void perform_tracking_cases(GArray *image_objects, GArray *image_tracking_models) +{ + const char *names[] = { + "Show created set of tracking models", + "Create empty tracking model (mv_image_tracking_model_create)", + "Generate model based on image object (mv_image_tracking_model_set_target)", + "Load existed tracking model from file (mv_image_tracking_model_load)", + "Clone existed tracking model (mv_image_tracking_model_clone)", + "Save existed tracking model to the file (mv_image_tracking_model_save)", + "Remove tracking model from created set (mv_image_tracking_model_destroy)", + "Refresh tracking model (mv_image_tracking_model_refresh)", + "Track (mv_image_track)", + "Back to the main menu"}; + + int number_of_options = sizeof(names) / sizeof(names[0]); + int options[number_of_options]; + int index = 0; + for (; index < number_of_options; ++index) + { + options[index] = index + 1; + } + + while (1) + { + int err = MEDIA_VISION_ERROR_NONE; + + int sel_opt = show_menu("Select action:", options, names, number_of_options); + + switch (sel_opt) + { + case 1: // Show created set of tracking models + { + show_testing_objects("Set of image tracking models", image_tracking_models); + break; + } + case 2: // Create empty tracking model (mv_image_tracking_model_create) + { + mv_image_tracking_model_h temporary_image_tracking_model = NULL; + + int err = mv_image_tracking_model_create(&temporary_image_tracking_model); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("ERROR: tracking model creation is failed with code %i\n", err); + break; + } + + testing_object_h added_object = NULL; + testing_object_create(&added_object); + testing_object_fill( + added_object, + temporary_image_tracking_model, + OBJECT_TYPE_IMAGE_TRACKING_MODEL, + SOURCE_TYPE_EMPTY, + NULL); + + add_testing_object(image_tracking_models, added_object); + printf("\nTracking model successfully created\n"); + break; + } + case 3: // Generate model based on image object (mv_image_tracking_model_set_target) + { + if (image_objects->len <= 0) + { + printf("\nFirstly you must create at least one image object.\n"); + break; + } + + mv_image_tracking_model_h temporary_image_tracking_model = NULL; + err = mv_image_tracking_model_create(&temporary_image_tracking_model); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("Error: tracking model isn't created with error code %i\n", err); + break; + } + + testing_object_h temporary_testing_object = NULL; + select_testing_object( + image_objects, + &temporary_testing_object, + "Select the image object for tracking"); + + err = mv_image_tracking_model_set_target( + (mv_image_object_h)(temporary_testing_object->entity), + temporary_image_tracking_model); + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("Error: target isn't set with error code %i\n", err); + break; + } + + testing_object_h added_object = NULL; + testing_object_create(&added_object); + testing_object_fill( + added_object, + temporary_image_tracking_model, + OBJECT_TYPE_IMAGE_TRACKING_MODEL, + SOURCE_TYPE_GENERATION, + temporary_testing_object); + + add_testing_object(image_tracking_models, added_object); + printf("\nTracking model successfully generated\n"); + break; + } + case 4: // Load existed tracking model from file (mv_image_tracking_model_load) + { + mv_image_tracking_model_h temporary_image_tracking_model = NULL; + char *path_to_object = NULL; + + err = perform_load_image_tracking_model( + &path_to_object, &temporary_image_tracking_model); + + if (MEDIA_VISION_ERROR_NONE != err) + { + printf("Loading failed (error code - %i)\n", err); + break; + } + + testing_object_h added_object = NULL; + testing_object_create(&added_object); + testing_object_fill( + added_object, + temporary_image_tracking_model, + OBJECT_TYPE_IMAGE_TRACKING_MODEL, + SOURCE_TYPE_LOADING, + path_to_object); + + free(path_to_object); + + add_testing_object(image_tracking_models, added_object); + break; + } + case 5: // Clone existed tracking model (mv_image_tracking_model_clone) + { + if (image_tracking_models->len <= 0) + { + printf( + "\nFirstly you must create at least one image " + "tracking model.\n"); + break; + } + + testing_object_h temporary_testing_object = NULL; + select_testing_object( + image_tracking_models, + &temporary_testing_object, + "Select the tracking model you want to clone"); + + mv_image_tracking_model_h temporary_image_tracking_model = NULL; + perform_clone_image_tracking_model( + temporary_testing_object->entity, + &temporary_image_tracking_model); + + testing_object_h added_object = NULL; + testing_object_create(&added_object); + testing_object_fill( + added_object, + temporary_image_tracking_model, + OBJECT_TYPE_IMAGE_TRACKING_MODEL, + SOURCE_TYPE_CLONING, + temporary_testing_object); + + add_testing_object(image_tracking_models, added_object); + break; + } + case 6: // Save existed tracking model to the file (mv_image_tracking_model_save) + { + if (image_tracking_models->len <= 0) + { + printf( + "\nFirstly you must create at least one image " + "tracking model.\n"); + break; + } + + testing_object_h temporary_testing_object = NULL; + select_testing_object( + image_tracking_models, + &temporary_testing_object, + "Select the tracking model you want to save"); + + perform_save_image_tracking_model(temporary_testing_object->entity); + break; + } + case 7: // Remove tracking model from created set (mv_image_tracking_model_destroy) + { + if (image_tracking_models->len <= 0) + { + printf( + "\nFirstly you must create at least one image " + "tracking model.\n"); + break; + } + + guint selected_index; + err = select_testing_object_index( + image_tracking_models, + &selected_index, + "Select the object you want to remove"); + + if (MEDIA_VISION_ERROR_NONE == err) + { + remove_testing_object(image_tracking_models, selected_index); + printf("\nTracking model successfully removed\n"); + } + break; + } + case 8: // Refresh tracking model (mv_image_tracking_model_refresh) + { + if (image_tracking_models->len <= 0) + { + printf( + "\nFirstly you must create at least one image " + "tracking model.\n"); + break; + } + + testing_object_h temporary_testing_object = NULL; + select_testing_object( + image_tracking_models, + &temporary_testing_object, + "Select the tracking model you want to refresh"); + + perform_refresh_image_tracking_model(temporary_testing_object->entity); + break; + } + case 9: // Track (mv_image_track) + { + if (image_tracking_models->len <= 0) + { + printf( + "\nFirstly you must create at least one image " + "tracking model.\n"); + break; + } + + testing_object_h temporary_testing_object = NULL; + err = select_testing_object( + image_tracking_models, + &temporary_testing_object, + "Select the object which you want to track on video"); + + if (MEDIA_VISION_ERROR_NONE == err) + { + perform_track(temporary_testing_object->entity); + } + break; + } + case 10: // Back to the main menu + { + return; + } + } + } +} + +int main(void) +{ + LOGI("Image Media Vision Testsuite is launched."); + + GArray *image_objects = g_array_new(FALSE, FALSE, sizeof(testing_object_h)); + GArray *image_tracking_models = g_array_new(FALSE, FALSE,sizeof(testing_object_h)); + + const int options[3] = { 1, 2, 3 }; + const char *names[3] = { + "Recognition cases", + "Tracking cases", + "Exit" }; + + mv_image_object_h current_object = NULL; + + while(1) + { + char exit = 'n'; + int sel_opt = show_menu("Select action:", options, names, 3); + switch (sel_opt) + { + case 1: // Recognition cases + perform_recognition_cases(image_objects); + break; + case 2: // Tracking cases + perform_tracking_cases(image_objects, image_tracking_models); + break; + case 3: // Exit + exit = 'y'; + break; + default: + printf("Invalid option.\n"); + 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: + printf("Invalid option. Back to the main menu."); + sel_opt = 0; + break; + } + } + + if ('y' == exit) + { + break; + } + } + + } + + guint i = 0; + for (i = 0; i < image_objects->len; ++i) + { + testing_object_h temp = g_array_index( + image_objects, + testing_object_h, + i); + testing_object_destroy(&temp); + } + g_array_free(image_objects, TRUE); + + for (i = 0; i < image_tracking_models->len; ++i) + { + testing_object_h temp = g_array_index( + image_tracking_models, + testing_object_h, + i); + testing_object_destroy(&temp); + } + g_array_free(image_tracking_models, TRUE); + + LOGI("Image Media Vision Testsuite is closed"); + + return 0; +}