1 /**
2  * @file
3  * @brief Header file for the TrackedObjectBBox class
4  * @author Jonathan Thomas <jonathan@openshot.org>
5  * @author Brenno Caldato <brenno.caldato@outlook.com>
6  *
7  * @ref License
8  */
9 
10 /* LICENSE
11  *
12  * Copyright (c) 2008-2019 OpenShot Studios, LLC
13  * <http://www.openshotstudios.com/>. This file is part of
14  * OpenShot Library (libopenshot), an open-source project dedicated to
15  * delivering high quality video editing and animation solutions to the
16  * world. For more information visit <http://www.openshot.org/>.
17  *
18  * OpenShot Library (libopenshot) is free software: you can redistribute it
19  * and/or modify it under the terms of the GNU Lesser General Public License
20  * as published by the Free Software Foundation, either version 3 of the
21  * License, or (at your option) any later version.
22  *
23  * OpenShot Library (libopenshot) is distributed in the hope that it will be
24  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26  * GNU Lesser General Public License for more details.
27  *
28  * You should have received a copy of the GNU Lesser General Public License
29  * along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
30  */
31 
32 #ifndef OPENSHOT_TRACKEDOBJECTBBOX_H
33 #define OPENSHOT_TRACKEDOBJECTBBOX_H
34 
35 #include "TrackedObjectBase.h"
36 
37 #include "Color.h"
38 #include "Exceptions.h"
39 #include "Fraction.h"
40 #include "Json.h"
41 #include "KeyFrame.h"
42 
43 namespace openshot
44 {
45 	/**
46 	 * @brief This struct holds the information of a bounding-box.
47 	 *
48 	 * A bounding-box is a rectangular shape that enclosures an
49 	 * object or a desired set of pixels in a digital image.
50 	 *
51 	 * The bounding-box structure holds five floating-point properties:
52 	 * the x and y coordinates of the rectangle's center point (cx, cy),
53 	 * the rectangle's width, height and rotation.
54 	 */
55 	struct BBox
56 	{
57 		float cx = -1; ///< x-coordinate of the bounding box center
58 		float cy = -1; ///< y-coordinate of the bounding box center
59 		float width = -1; ///< bounding box width
60 		float height = -1; ///< bounding box height
61 		float angle = -1; ///< bounding box rotation angle [degrees]
62 
63 		/// Blank constructor
BBoxBBox64 		BBox() {}
65 
66 		/// Default constructor, which takes the bounding box top-left corner coordinates, width and height.
67 		/// @param _cx X-coordinate of the bounding box center
68 		/// @param _cy Y-coordinate of the bounding box center
69 		/// @param _width Bounding box width
70 		/// @param _height Bounding box height
71 		/// @param _angle Bounding box rotation angle [degrees]
BBoxBBox72 		BBox(float _cx, float _cy, float _width, float _height, float _angle)
73 		{
74 			cx = _cx;
75 			cy = _cy;
76 			width = _width;
77 			height = _height;
78 			angle = _angle;
79 		}
80 
81 
82 		/// Generate JSON string of this object
JsonBBox83 		std::string Json() const
84 		{
85 			return JsonValue().toStyledString();
86 		}
87 
88 		/// Generate Json::Value for this object
JsonValueBBox89 		Json::Value JsonValue() const
90 		{
91 			Json::Value root;
92 			root["cx"] = cx;
93 			root["cy"] = cy;
94 			root["width"] = width;
95 			root["height"] = height;
96 			root["angle"] = angle;
97 
98 			return root;
99 		}
100 
101 		/// Load JSON string into this object
SetJsonBBox102 		void SetJson(const std::string value)
103 		{
104 			// Parse JSON string into JSON objects
105 			try
106 			{
107 				const Json::Value root = openshot::stringToJson(value);
108 				// Set all values that match
109 				SetJsonValue(root);
110 			}
111 			catch (const std::exception &e)
112 			{
113 				// Error parsing JSON (or missing keys)
114 				throw InvalidJSON("JSON is invalid (missing keys or invalid data types)");
115 			}
116 		}
117 
118 		/// Load Json::Value into this object
SetJsonValueBBox119 		void SetJsonValue(const Json::Value root)
120 		{
121 
122 			// Set data from Json (if key is found)
123 			if (!root["cx"].isNull())
124 				cx = root["cx"].asDouble();
125 			if (!root["cy"].isNull())
126 				cy = root["cy"].asDouble();
127 			if (!root["width"].isNull())
128 				width = root["width"].asDouble();
129 			if (!root["height"].isNull())
130 				height = root["height"].asDouble();
131 			if (!root["angle"].isNull())
132 				angle = root["angle"].asDouble();
133 		}
134 	};
135 
136 	/**
137 	 * @brief This class contains the properties of a tracked object
138 	 * and functions to manipulate it.
139 	 *
140 	 * The bounding-box displacement in X and Y directions, it's width,
141 	 * height and rotation variation over the frames are set as
142 	 * openshot::Keyframe objects.
143 	 *
144 	 * The bounding-box information over the clip's frames are
145 	 * saved into a protobuf file and loaded into an
146 	 * object of this class.
147 	 */
148 	class TrackedObjectBBox : public TrackedObjectBase
149 	{
150 	private:
151 		Fraction BaseFps;
152 		double TimeScale;
153 
154 	public:
155 		std::map<double, BBox> BoxVec; ///< Index the bounding-box by time of each frame
156 		Keyframe delta_x; ///< X-direction displacement Keyframe
157 		Keyframe delta_y; ///< Y-direction displacement Keyframe
158 		Keyframe scale_x; ///< X-direction scale Keyframe
159 		Keyframe scale_y; ///< Y-direction scale Keyframe
160 		Keyframe rotation; ///< Rotation Keyframe
161 		Keyframe background_alpha; ///< Background box opacity
162 		Keyframe background_corner; ///< Radius of rounded corners
163 		Keyframe stroke_width; ///< Thickness of border line
164 		Keyframe stroke_alpha; ///< Stroke box opacity
165 		Color stroke; ///< Border line color
166 		Color background; ///< Background fill color
167 
168 		std::string protobufDataPath; ///< Path to the protobuf file that holds the bounding box points across the frames
169 
170 		/// Default Constructor
171 		TrackedObjectBBox();
172 		TrackedObjectBBox(int Red, int Green, int Blue, int Alfa);
173 
174 		/// Add a BBox to the BoxVec map
175 		void AddBox(int64_t _frame_num, float _cx, float _cy, float _width, float _height, float _angle) override;
176 
177 		/// Update object's BaseFps
178 		void SetBaseFPS(Fraction fps);
179 
180 		/// Return the object's BaseFps
181 		Fraction GetBaseFPS();
182 
183 		/// Update the TimeScale member variable
184 		void ScalePoints(double scale) override;
185 
186 		/// Check if there is a bounding-box in the given frame
187 		bool Contains(int64_t frame_number) const;
188 		/// Check if there is a bounding-box in the exact frame number
189 		bool ExactlyContains(int64_t frame_number) const override;
190 
191 		/// Get the size of BoxVec map
192 		int64_t GetLength() const;
193 
194 		/// Remove a bounding-box from the BoxVec map
195 		void RemoveBox(int64_t frame_number);
196 
197 		/// Return a bounding-box from BoxVec with it's properties adjusted by the Keyframes
198 		BBox GetBox(int64_t frame_number);
199 		/// Const-cast of the GetBox function, so that it can be called inside other cont function
GetBox(int64_t frame_number)200 		BBox GetBox(int64_t frame_number) const
201 		{
202 			return const_cast<TrackedObjectBBox *>(this)->GetBox(frame_number);
203 		}
204 
205 		/// Load the bounding-boxes information from the protobuf file
206 		bool LoadBoxData(std::string inputFilePath);
207 
208 		/// Get the time of the given frame
209 		double FrameNToTime(int64_t frame_number, double time_scale) const;
210 
211 		/// Interpolate the bouding-boxes properties
212 		BBox InterpolateBoxes(double t1, double t2, BBox left, BBox right, double target);
213 
214 		/// Clear the BoxVec map
215 		void clear();
216 
217 		/// Get and Set JSON methods
218 		std::string Json() const override;				  ///< Generate JSON string of this object
219 		Json::Value JsonValue() const override;			 ///< Generate Json::Value for this object
220 		void SetJson(const std::string value) override;	 ///< Load JSON string into this object
221 		void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object
222 
223 		/// Get all properties for a specific frame (perfect for a UI to display the current state
224 		/// of all properties at any time)
225 		Json::Value PropertiesJSON(int64_t requested_frame) const override;
226 
227 		// Generate JSON for a property
228 		Json::Value add_property_json(std::string name, float value, std::string type, std::string memo, const Keyframe* keyframe, float min_value, float max_value, bool readonly, int64_t requested_frame) const;
229 
230 		/// Return a map that contains the bounding box properties and it's keyframes indexed by their names
231 		std::map<std::string, float> GetBoxValues(int64_t frame_number) const override;
232 		/// Return a map that contains the properties of this object's parent clip
233 		std::map<std::string, float> GetParentClipProperties(int64_t frame_number) const override;
234 
235 	};
236 } // namespace openshot
237 
238 #endif
239