diff options
Diffstat (limited to 'mv_image')
21 files changed, 5089 insertions, 0 deletions
diff --git a/mv_image/CMakeLists.txt b/mv_image/CMakeLists.txt new file mode 100644 index 00000000..36d20373 --- /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 00000000..0269712f --- /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 00000000..2d43430f --- /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 <opencv/cv.h> + +/** + * @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 00000000..1fae7979 --- /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 <opencv/cv.h> + +/** + * @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<cv::Point2f>& 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<cv::Point2f> computeStabilizedQuadrangleContour(void); + +private: + + static const size_t MovingHistoryAmount = 3u; + + std::vector<float> m_speeds; + + std::vector<size_t> m_currentCornersSpeed; + + std::deque<std::vector<cv::Point2f> > m_movingHistory; + + std::vector<cv::Point2f> m_lastStabilizedContour; + + size_t m_currentHistoryAmount; + + int m_tempContourIndex; + + std::vector<float> 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 00000000..ebc95d70 --- /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 <opencv/cv.h> + +/** + * @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 00000000..a4945540 --- /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 <opencv/cv.h> + +/** + * @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<cv::Point2f> m_boundingContour; + + std::vector<cv::KeyPoint> 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 00000000..8494e3aa --- /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 <opencv/cv.h> + +/** + * @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<cv::Point2f>& contour) const; + +private: + + ImageRecognizer(); + + bool findHomophraphyMatrix( + const ImageObject& target, + const RecognitionParams& params, + cv::Mat& homophraphyMatrix) const; + + size_t matchesSelection( + std::vector<cv::DMatch>& examples, + unsigned int filterAmount, unsigned int allowableError) const; + + float computeLinearSupportElement( + const std::vector<cv::DMatch>& 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 00000000..2bfd5b1b --- /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 <opencv/cv.h> + +/** + * @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 00000000..2f55c2d1 --- /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 <opencv/cv.h> + +#include <pthread.h> + +#include <vector> +#include <list> + +/** + * @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<cv::Point2f> getLastlocation() const; + +private: + + ImageObject m_recognitionObject; + + ImageContourStabilizator m_stabilizator; + + std::vector<cv::Point2f> 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 00000000..f6128fd5 --- /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 00000000..47fdaef4 --- /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 00000000..1c486593 --- /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<cv::Point2f>& 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<cv::Point2f> 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<cv::Point2f> ImageContourStabilizator::computeStabilizedQuadrangleContour(void) +{ + // final contour + std::vector<cv::Point2f> stabilizedState( + NumberOfQuadrangleCorners, cv::Point2f(0.f, 0.f)); + + // calculation the direction of contour corners to a new location + std::vector<cv::Point2f> 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<cv::Point2f> directionsToLastPos(NumberOfQuadrangleCorners); + for (size_t j = 0u; j < NumberOfQuadrangleCorners; ++j) + { + // calculation the moving directions and computing average direction + std::vector<cv::Point2f> 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<float> 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 00000000..8bf5ba83 --- /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 00000000..531ec62d --- /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 <app_common.h> + +#include "mv_private.h" +#include "mv_common.h" + +#include <opencv/cv.h> +#include <opencv2/features2d/features2d.hpp> + +#include <fstream> +#include <unistd.h> + +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<<std::setprecision(7); + + os<<obj.m_isEmpty<<'\n'; + os<<obj.m_isLabeled<<'\n'; + os<<obj.m_label<<'\n'; + + os<<obj.m_boundingContour.size()<<'\n'; + for (size_t pointNum = 0u; pointNum < obj.m_boundingContour.size(); ++pointNum) + { + os<<obj.m_boundingContour[pointNum].x<<' '; + os<<obj.m_boundingContour[pointNum].y<<'\n'; + } + + os<<obj.m_objectKeypoints.size()<<'\n'; + for (size_t keypointNum = 0u; keypointNum < obj.m_objectKeypoints.size();++keypointNum) + { + os<<obj.m_objectKeypoints[keypointNum].pt.x<<' '; + os<<obj.m_objectKeypoints[keypointNum].pt.y<<' '; + os<<obj.m_objectKeypoints[keypointNum].size<<' '; + os<<obj.m_objectKeypoints[keypointNum].response<<' '; + os<<obj.m_objectKeypoints[keypointNum].angle<<' '; + os<<obj.m_objectKeypoints[keypointNum].octave<<' '; + os<<obj.m_objectKeypoints[keypointNum].class_id<<'\n'; + } + + os<<obj.m_objectDescriptors.rows<<' '; + os<<obj.m_objectDescriptors.cols<<' '; + os<<obj.m_objectDescriptors.type()<<'\n'; + for (int descriptorNum = 0; descriptorNum < obj.m_objectDescriptors.rows; + ++descriptorNum) + { + for (int featureNum = 0; featureNum < obj.m_objectDescriptors.cols; + ++featureNum, os<<'\n') + { + os<<(int)obj.m_objectDescriptors.at<uchar>(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<uchar>(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 00000000..c9215556 --- /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<cv::Point2f>& 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<cv::DMatch> 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<cv::Point2f> objectPoints(matchesNumber); + std::vector<cv::Point2f> 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<cv::DMatch>& 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<cv::DMatch>& 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 00000000..9c114f58 --- /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 <pthread.h> + +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<cv::Point2f> 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<cv::Point2f> 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 00000000..e0a75c97 --- /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 <app_common.h> + +#include "mv_private.h" +#include "mv_common.h" + +#include <fstream> +#include <unistd.h> + +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<cv::Point2f> ImageTrackingModel::getLastlocation() const +{ + std::vector<cv::Point2f> 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<<STATE_VISIBLE_IO_ID; + } + else + { + os<<STATE_UNSEEN_IO_ID; + } + + return os; +} + +std::istream& operator >> (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::setprecision(7); + + pthread_mutex_lock(&obj.m_globalGuard); + + os<<obj.m_recognitionObject; + + os<<obj.m_lastLocation.size(); + for (size_t pointNum = 0u; pointNum < obj.m_lastLocation.size(); ++pointNum) + { + os<<' '<<obj.m_lastLocation[pointNum].x<<' '<<obj.m_lastLocation[pointNum].y; + } + os<<'\n'; + + os<<obj.m_state<<'\n'; + + pthread_mutex_unlock(&obj.m_globalGuard); + + return os; +} + +std::istream& operator >> (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 00000000..1d351a44 --- /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 <opencv/cv.h> + +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<cv::Point2f> 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<cv::Point2f> 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 00000000..b38e47b8 --- /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 00000000..29e1c1dc --- /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 00000000..356e563c --- /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; +} |