diff --git a/src/KeyFrameBBox.cpp b/src/KeyFrameBBox.cpp
index 2a861014..7109101d 100644
--- a/src/KeyFrameBBox.cpp
+++ b/src/KeyFrameBBox.cpp
@@ -142,14 +142,14 @@ KeyFrameBBox::KeyFrameBBox() : delta_x(0.0), delta_y(0.0), scale_x(1.0), scale_y
}
// Add a BBox to the BoxVec map
-void KeyFrameBBox::AddBox(int64_t _frame_num, float _x1, float _y1, float _width, float _height)
+void KeyFrameBBox::AddBox(int64_t _frame_num, float _cx, float _cy, float _width, float _height, float _angle)
{
// Check if the given frame number is valid
if (_frame_num < 0)
return;
// Instantiate a new bounding-box
- BBox newBBox = BBox(_x1, _y1, _width, _height);
+ BBox newBBox = BBox(_cx, _cy, _width, _height, _angle);
// Get the time of given frame
double time = this->FrameNToTime(_frame_num, 1.0);
@@ -231,25 +231,12 @@ BBox KeyFrameBBox::GetValue(int64_t frame_number)
BBox currentBBox = currentBBoxIterator->second;
// Adjust the BBox properties by the Keyframes values
- currentBBox.x1 += this->delta_x.GetValue(frame_number);
- currentBBox.y1 += this->delta_y.GetValue(frame_number);
+ currentBBox.cx += this->delta_x.GetValue(frame_number);
+ currentBBox.cy += this->delta_y.GetValue(frame_number);
currentBBox.width *= this->scale_x.GetValue(frame_number);
currentBBox.height *= this->scale_y.GetValue(frame_number);
+ currentBBox.angle += this->rotation.GetValue(frame_number);
- /* TODO - Add rotation
- (x1,y1) -> current point
- (x1',y1') -> transformed point
- (xc, yc) -> center of the BBox
- (xc, yc) = (x1 + w/2, y1 + h/2)
- rot -> rotation angle [radians]
- x1' = xc + (x1 - xc)*cos(rot) - (y1-yc)*sin(rot)
- y1' = yc + (x1 - xc)*sin(rot) + (y1-yc)*cos(rot)
- ***
- x1' = (x1 + w/2) + (-w/2)*cos(rot) - (-h/2)*sin(rot)
- y1' = (y1 + h/2) + (-w/2)*sin(rot) + (-h/2)*cos(rot)
- currentBBox.x1 += currentBBox.width/2 - (currentBBox.width/2)*cos(rot*PI/180) + (currentBBox.height)*sin(rot*PI/180);
- currentBBox.y1 += currentBBox.height/2 - (currentBBox.width/2)*sin(rot*PI/180) - (currentBBox.height)*cos(rot*PI/180);
- */
return currentBBox;
}
@@ -263,10 +250,11 @@ BBox KeyFrameBBox::GetValue(int64_t frame_number)
previousBBox, currentBBox, time);
// Adjust the BBox properties by the Keyframes values
- interpolatedBBox.x1 += this->delta_x.GetValue(frame_number);
- interpolatedBBox.y1 += this->delta_y.GetValue(frame_number);
+ interpolatedBBox.cx += this->delta_x.GetValue(frame_number);
+ interpolatedBBox.cy += this->delta_y.GetValue(frame_number);
interpolatedBBox.width *= this->scale_x.GetValue(frame_number);
interpolatedBBox.height *= this->scale_y.GetValue(frame_number);
+ interpolatedBBox.angle += this->rotation.GetValue(frame_number);
return interpolatedBBox;
}
@@ -274,26 +262,35 @@ BBox KeyFrameBBox::GetValue(int64_t frame_number)
// Interpolate the bouding-boxes properties
BBox KeyFrameBBox::InterpolateBoxes(double t1, double t2, BBox left, BBox right, double target)
{
+ // Interpolate the x-coordinate of the center point
+ Point cx_left(t1, left.cx, openshot::InterpolationType::LINEAR);
+ Point cx_right(t2, right.cx, openshot::InterpolationType::LINEAR);
+ Point cx = InterpolateBetween(cx_left, cx_right, target, 0.01);
- Point p1_left(t1, left.x1, openshot::InterpolationType::LINEAR);
- Point p1_right(t2, right.x1, openshot::InterpolationType::LINEAR);
- Point p1 = InterpolateBetween(p1_left, p1_right, target, 0.01);
+ // Interpolate de y-coordinate of the center point
+ Point cy_left(t1, left.cy, openshot::InterpolationType::LINEAR);
+ Point cy_right(t2, right.cy, openshot::InterpolationType::LINEAR);
+ Point cy = InterpolateBetween(cy_left, cy_right, target, 0.01);
- Point p2_left(t1, left.y1, openshot::InterpolationType::LINEAR);
- Point p2_right(t2, right.y1, openshot::InterpolationType::LINEAR);
- Point p2 = InterpolateBetween(p2_left, p2_right, target, 0.01);
+ // Interpolate the width
+ Point width_left(t1, left.width, openshot::InterpolationType::LINEAR);
+ Point width_right(t2, right.width, openshot::InterpolationType::LINEAR);
+ Point width = InterpolateBetween(width_left, width_right, target, 0.01);
- Point p3_left(t1, left.height, openshot::InterpolationType::LINEAR);
- Point p3_right(t2, right.height, openshot::InterpolationType::LINEAR);
- Point p3 = InterpolateBetween(p3_left, p3_right, target, 0.01);
+ // Interpolate the height
+ Point height_left(t1, left.height, openshot::InterpolationType::LINEAR);
+ Point height_right(t2, right.height, openshot::InterpolationType::LINEAR);
+ Point height = InterpolateBetween(height_left, height_right, target, 0.01);
- Point p4_left(t1, left.width, openshot::InterpolationType::LINEAR);
- Point p4_right(t2, right.width, openshot::InterpolationType::LINEAR);
- Point p4 = InterpolateBetween(p4_left, p4_right, target, 0.01);
+ // Interpolate the rotation angle
+ Point angle_left(t1, left.angle, openshot::InterpolationType::LINEAR);
+ Point angle_right(t1, right.angle, openshot::InterpolationType::LINEAR);
+ Point angle = InterpolateBetween(angle_left, angle_right, target, 0.01);
- BBox ans(p1.co.Y, p2.co.Y, p4.co.Y, p3.co.Y);
+ // Create a bounding box with the interpolated points
+ BBox interpolatedBox(cx.co.Y, cy.co.Y, width.co.Y, height.co.Y, angle.co.Y);
- return ans;
+ return interpolatedBox;
}
// Update object's BaseFps
@@ -348,16 +345,18 @@ bool KeyFrameBBox::LoadBoxData(std::string inputFilePath)
// Get bounding box data from current frame
const libopenshottracker::Frame::Box &box = pbFrameData.bounding_box();
-
- float x1 = box.x1();
- float y1 = box.y1();
- float x2 = box.x2();
- float y2 = box.y2();
- if ( (x1 >= 0.0) && (y1 >= 0.0) && (x2 >= 0.0) && (y2 >= 0.0) )
+ float width = box.x2() - box.x1();
+ float height = box.y2() - box.y1();
+ float cx = box.x1() + width/2;
+ float cy = box.y1() + height/2;
+ float angle = 0.0;
+
+
+ if ( (cx >= 0.0) && (cy >= 0.0) && (width >= 0.0) && (height >= 0.0) )
{
// The bounding-box properties are valid, so add it to the BoxVec map
- this->AddBox(frame_number, x1, y1, (x2 - x1), (y2 - y1));
+ this->AddBox(frame_number, cx, cy, width, height, angle);
}
}
@@ -464,7 +463,6 @@ void KeyFrameBBox::SetJsonValue(const Json::Value root)
// Insert BBox into the BoxVec map
BBox box;
box.SetJsonValue(existing_point["data"]);
- //BoxVec.insert({existing_point["time"].asDouble(), box});
BoxVec[existing_point["time"].asDouble()] = box;
}
}
@@ -482,4 +480,4 @@ void KeyFrameBBox::SetJsonValue(const Json::Value root)
rotation.SetJsonValue(root["rotation"]);
return;
-}
\ No newline at end of file
+}
diff --git a/src/KeyFrameBBox.h b/src/KeyFrameBBox.h
index fb7fc16a..4480bddb 100644
--- a/src/KeyFrameBBox.h
+++ b/src/KeyFrameBBox.h
@@ -60,10 +60,11 @@ namespace openshot
struct BBox
{
- float x1 = -1; ///< x-coordinate of the top left corner
- float y1 = -1; ///< y-coordinate of the top left corner
+ float cx = -1; ///< x-coordinate of the bounding box center
+ float cy = -1; ///< y-coordinate of the bounding box center
float width = -1; ///< bounding box width
float height = -1; ///< bounding box height
+ float angle = -1; ///< bounding box rotation angle [degrees]
/// Blank constructor
BBox()
@@ -72,18 +73,21 @@ namespace openshot
}
/// Default constructor, which takes the bounding box top-left corner coordinates, width and height.
- /// @param _x1 X-coordinate of the top left corner
- /// @param _y1 Y-coordinate of the top left corner
+ /// @param _cx X-coordinate of the bounding box center
+ /// @param _cy Y-coordinate of the bounding box center
/// @param _width Bounding box width
- /// @param _height Bouding box height
- BBox(float _x1, float _y1, float _width, float _height)
+ /// @param _height Bounding box height
+ /// @param _angle Bounding box rotation angle [degrees]
+ BBox(float _cx, float _cy, float _width, float _height, float _angle)
{
- x1 = _x1;
- y1 = _y1;
+ cx = _cx;
+ cy = _cy;
width = _width;
height = _height;
+ angle = _angle;
}
+
/// Generate JSON string of this object
std::string Json() const
{
@@ -94,10 +98,11 @@ namespace openshot
Json::Value JsonValue() const
{
Json::Value root;
- root["x1"] = x1;
- root["y1"] = y1;
- root["height"] = height;
+ root["cx"] = cx;
+ root["cy"] = cy;
root["width"] = width;
+ root["height"] = height;
+ root["angle"] = angle;
return root;
}
@@ -124,15 +129,17 @@ namespace openshot
{
// Set data from Json (if key is found)
- if (!root["x1"].isNull())
- x1 = root["x1"].asDouble();
- if (!root["y1"].isNull())
- y1 = root["y1"].asDouble();
- if (!root["height"].isNull())
- height = root["height"].asDouble();
+ if (!root["cx"].isNull())
+ cx = root["cx"].asDouble();
+ if (!root["cy"].isNull())
+ cy = root["cy"].asDouble();
if (!root["width"].isNull())
width = root["width"].asDouble();
- }
+ if (!root["height"].isNull())
+ height = root["height"].asDouble();
+ if (!root["angle"].isNull())
+ angle = root["angle"].asDouble();
+ }
};
/**
@@ -166,7 +173,7 @@ namespace openshot
KeyFrameBBox();
/// Add a BBox to the BoxVec map
- void AddBox(int64_t _frame_num, float _x1, float _y1, float _width, float _height);
+ void AddBox(int64_t _frame_num, float _cx, float _cy, float _width, float _height, float _angle);
/// Update object's BaseFps
void SetBaseFPS(Fraction fps);
@@ -214,4 +221,4 @@ namespace openshot
} // namespace openshot
-#endif
\ No newline at end of file
+#endif
diff --git a/src/effects/Tracker.cpp b/src/effects/Tracker.cpp
index d3965ed6..6833b7f0 100644
--- a/src/effects/Tracker.cpp
+++ b/src/effects/Tracker.cpp
@@ -73,11 +73,11 @@ std::shared_ptr Tracker::GetFrame(std::shared_ptr frame, int64_t f
cv::Mat frame_image = frame->GetImageCV();
// Check if frame isn't NULL
- if(!frame_image.empty()){
-
+ if(!frame_image.empty())
+ {
// Check if track data exists for the requested frame
- if (trackedData.Contains(frame_number)) {
-
+ if (trackedData.Contains(frame_number))
+ {
// Get the width and height of the image
float fw = frame_image.size().width;
float fh = frame_image.size().height;
@@ -85,12 +85,18 @@ std::shared_ptr Tracker::GetFrame(std::shared_ptr frame, int64_t f
// Get the bounding-box of given frame
BBox fd = this->trackedData.GetValue(frame_number);
- // Draw the bounding-box on the image
- cv::Rect2d box((int)( (fd.x1 ) * fw ),
- (int)( (fd.y1 ) * fh ),
- (int)( (fd.width) * fw),
- (int)( (fd.height) * fh) );
- cv::rectangle(frame_image, box, cv::Scalar( 255, 0, 0 ), 2, 1 );
+ // Create a rotated rectangle object that holds the bounding box
+ cv::RotatedRect box ( cv::Point2f( (int)(fd.cx*fw), (int)(fd.cy*fh) ),
+ cv::Size2f( (int)(fd.width*fw), (int)(fd.height*fh) ),
+ (int) (fd.angle) );
+ // Get the bouding box vertices
+ cv::Point2f vertices[4];
+ box.points(vertices);
+ // Draw the bounding-box on the image
+ for (int i = 0; i < 4; i++)
+ {
+ cv::line(frame_image, vertices[i], vertices[(i+1)%4], cv::Scalar(255,0,0), 2);
+ }
}
}
@@ -194,10 +200,10 @@ std::string Tracker::PropertiesJSON(int64_t requested_frame) const {
// Get the bounding-box for the given-frame
BBox fd = trackedData.GetValue(requested_frame);
// Add the data of given frame bounding-box to the JSON object
- root["x1"] = add_property_json("X1", fd.x1, "float", "", NULL, 0.0, 1.0, false, requested_frame);
- root["y1"] = add_property_json("Y1", fd.y1, "float", "", NULL, 0.0, 1.0, false, requested_frame);
- root["x2"] = add_property_json("X2", fd.x1+fd.width, "float", "", NULL, 0.0, 1.0, false, requested_frame);
- root["y2"] = add_property_json("Y2", fd.y1+fd.height, "float", "", NULL, 0.0, 1.0, false, requested_frame);
+ root["x1"] = add_property_json("X1", fd.cx-(fd.width/2), "float", "", NULL, 0.0, 1.0, false, requested_frame);
+ root["y1"] = add_property_json("Y1", fd.cy-(fd.height/2), "float", "", NULL, 0.0, 1.0, false, requested_frame);
+ root["x2"] = add_property_json("X2", fd.cx+(fd.width/2), "float", "", NULL, 0.0, 1.0, false, requested_frame);
+ root["y2"] = add_property_json("Y2", fd.cy+(fd.height/2), "float", "", NULL, 0.0, 1.0, false, requested_frame);
// Add the bounding-box Keyframes to the JSON object
root["delta_x"] = add_property_json("Displacement X-axis", trackedData.delta_x.GetValue(requested_frame), "float", "", &trackedData.delta_x, -1.0, 1.0, false, requested_frame);
@@ -260,4 +266,4 @@ void Tracker::SetJson(int64_t requested_frame, const std::string value)
throw InvalidJSON("JSON is invalid (missing keys or invalid data types)");
}
return;
-}
\ No newline at end of file
+}
diff --git a/tests/KeyFrame_Tests.cpp b/tests/KeyFrame_Tests.cpp
index 50ce041b..05cd5109 100644
--- a/tests/KeyFrame_Tests.cpp
+++ b/tests/KeyFrame_Tests.cpp
@@ -505,7 +505,7 @@ TEST(KeyFrameBBox_init_test) {
TEST(KeyFrameBBox_addBox_test) {
KeyFrameBBox kfb;
- kfb.AddBox(1, 10.0, 10.0, 100.0, 100.0);
+ kfb.AddBox(1, 10.0, 10.0, 100.0, 100.0, 0.0);
CHECK_EQUAL(true, kfb.Contains(1));
CHECK_EQUAL(1, kfb.GetLength());
@@ -520,43 +520,44 @@ TEST(KeyFrameBBox_addBox_test) {
TEST(KeyFrameBBox_GetVal_test) {
KeyFrameBBox kfb;
- kfb.AddBox(1, 10.0, 10.0, 100.0, 100.0);
+ kfb.AddBox(1, 10.0, 10.0, 100.0, 100.0, 0.0);
BBox val = kfb.GetValue(1);
- CHECK_EQUAL(10.0, val.x1);
- CHECK_EQUAL(10.0, val.y1);
+ CHECK_EQUAL(10.0, val.cx);
+ CHECK_EQUAL(10.0, val.cy);
CHECK_EQUAL(100.0,val.width);
CHECK_EQUAL(100.0,val.height);
+ CHECK_EQUAL(0.0, val.angle);
}
TEST(KeyFrameBBox_GetVal_Interpolation) {
KeyFrameBBox kfb;
- kfb.AddBox(1, 10.0, 10.0, 100.0, 100.0);
- kfb.AddBox(11, 20.0, 20.0, 100.0, 100.0);
- kfb.AddBox(21, 30.0, 30.0, 100.0, 100.0);
- kfb.AddBox(31, 40.0, 40.0, 100.0, 100.0);
+ kfb.AddBox(1, 10.0, 10.0, 100.0, 100.0, 0.0);
+ kfb.AddBox(11, 20.0, 20.0, 100.0, 100.0, 0.0);
+ kfb.AddBox(21, 30.0, 30.0, 100.0, 100.0, 0.0);
+ kfb.AddBox(31, 40.0, 40.0, 100.0, 100.0, 0.0);
BBox val = kfb.GetValue(5);
- CHECK_EQUAL(14.0, val.x1);
- CHECK_EQUAL(14.0, val.y1);
+ CHECK_EQUAL(14.0, val.cx);
+ CHECK_EQUAL(14.0, val.cy);
CHECK_EQUAL(100.0,val.width);
- CHECK_EQUAL(100.0, val.height);
+ CHECK_EQUAL(100.0,val.height);
val = kfb.GetValue(15);
- CHECK_EQUAL(24.0, val.x1);
- CHECK_EQUAL(24.0, val.y1);
+ CHECK_EQUAL(24.0, val.cx);
+ CHECK_EQUAL(24.0, val.cy);
CHECK_EQUAL(100.0,val.width);
CHECK_EQUAL(100.0, val.height);
val = kfb.GetValue(25);
- CHECK_EQUAL(34.0, val.x1);
- CHECK_EQUAL(34.0, val.y1);
+ CHECK_EQUAL(34.0, val.cx);
+ CHECK_EQUAL(34.0, val.cy);
CHECK_EQUAL(100.0,val.width);
CHECK_EQUAL(100.0, val.height);
@@ -566,10 +567,10 @@ TEST(KeyFrameBBox_GetVal_Interpolation) {
TEST(KeyFrameBBox_Json_set) {
KeyFrameBBox kfb;
- kfb.AddBox(1, 10.0, 10.0, 100.0, 100.0);
- kfb.AddBox(10, 20.0, 20.0, 100.0, 100.0);
- kfb.AddBox(20, 30.0, 30.0, 100.0, 100.0);
- kfb.AddBox(30, 40.0, 40.0, 100.0, 100.0);
+ kfb.AddBox(1, 10.0, 10.0, 100.0, 100.0, 0.0);
+ kfb.AddBox(10, 20.0, 20.0, 100.0, 100.0, 0.0);
+ kfb.AddBox(20, 30.0, 30.0, 100.0, 100.0, 0.0);
+ kfb.AddBox(30, 40.0, 40.0, 100.0, 100.0, 0.0);
kfb.scale_x.AddPoint(1, 2.0);
kfb.scale_x.AddPoint(10, 3.0);
@@ -591,16 +592,17 @@ TEST(KeyFrameBBox_Json_set) {
BBox kfb_bbox = kfb.BoxVec[time_kfb];
BBox fromJSON_bbox = fromJSON_kfb.BoxVec[time_fromJSON_kfb];
- CHECK_EQUAL(kfb_bbox.x1, fromJSON_bbox.x1);
- CHECK_EQUAL(kfb_bbox.y1, fromJSON_bbox.y1);
+ CHECK_EQUAL(kfb_bbox.cx, fromJSON_bbox.cx);
+ CHECK_EQUAL(kfb_bbox.cy, fromJSON_bbox.cy);
CHECK_EQUAL(kfb_bbox.width, fromJSON_bbox.width);
CHECK_EQUAL(kfb_bbox.height, fromJSON_bbox.height);
+ CHECK_EQUAL(kfb_bbox.angle, fromJSON_bbox.angle);
}
TEST(KeyFrameBBox_Scale_test){
KeyFrameBBox kfb;
- kfb.AddBox(1, 10.0, 10.0, 10.0, 10.0);
+ kfb.AddBox(1, 10.0, 10.0, 10.0, 10.0, 0.0);
kfb.scale_x.AddPoint(1.0, 2.0);
kfb.scale_y.AddPoint(1.0, 3.0);