Skip to content

Add shadow effect to libopenshot #999

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 26 commits into
base: develop
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a11c9b2
Add support for alpha channel in image conversion methods and refacto…
aperture147 Mar 21, 2025
4551154
Refactor image conversion methods to be member functions of Frame cla…
aperture147 Mar 21, 2025
b020108
Add unit test for image conversion with alpha channel support
aperture147 Mar 21, 2025
ed33b6d
Rename imagecv to brga_image_cv for clarity and consistency in Frame …
aperture147 Mar 21, 2025
6027f5d
Add Shadow effect implementation and corresponding tests
aperture147 Mar 21, 2025
ab80bd8
Fix author attribution in Shadow effect class documentation
aperture147 Mar 22, 2025
dae3766
Add author attribution and enhance Shadow effect tests
aperture147 Mar 22, 2025
11f8f78
Fix author attribution and remove unrelated note
aperture147 Mar 22, 2025
2520c68
Update author attribution and modify image channel check in unit test…
aperture147 Mar 22, 2025
be5e2e9
Update author attribution in Outline effect files for clarity
aperture147 Mar 22, 2025
9d2f082
Merge branch 'add-bgra-cvmat-converter' into shadow-effect
aperture147 Mar 22, 2025
f2f76e0
Release resources for brga_image_cv in Frame destructor
aperture147 Mar 22, 2025
6da48a2
Merge branch 'add-bgra-cvmat-converter' into shadow-effect
aperture147 Mar 22, 2025
71d2be9
Enhance documentation for Shadow effect to clarify animation capabili…
aperture147 Mar 22, 2025
790f5a8
Adjust shadow effect alpha value and improve shadow rendering logic
aperture147 Mar 22, 2025
944bf0f
Refactor Shadow effect header to remove unused includes and update co…
aperture147 Mar 22, 2025
f0d415c
Optimize shadow rendering logic to handle edge cases for frame bounda…
aperture147 Mar 22, 2025
ee01994
Fix shadow boundary check to use absolute offsets for improved accuracy
aperture147 Mar 23, 2025
61302db
Change blur_radius property type from float to int for consistency in…
aperture147 Mar 25, 2025
95f6a68
updating blur_radius max value to a more reasonable number
aperture147 Mar 25, 2025
c4e3c56
Update x_offset and y_offset ranges to -4000 to 4000; change color pr…
aperture147 Mar 25, 2025
87d9d61
Update file descriptions to reflect Shadow effect instead of Outline …
aperture147 Mar 25, 2025
bb037c9
Temporarily disable CVShadow test in CMakeLists.txt
aperture147 Mar 25, 2025
28b46d1
Merge branch 'OpenShot:develop' into shadow-effect
aperture147 May 25, 2025
39962f9
Merge branch 'OpenShot:develop' into shadow-effect
aperture147 May 29, 2025
461752f
Merge branch 'OpenShot:develop' into shadow-effect
aperture147 Jun 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions bindings/python/openshot.i
Original file line number Diff line number Diff line change
@@ -115,6 +115,7 @@
#include "effects/Tracker.h"
#include "effects/ObjectDetection.h"
#include "effects/Outline.h"
#include "effects/Shadow.h"
#include "TrackedObjectBase.h"
#include "TrackedObjectBBox.h"
%}
@@ -357,4 +358,5 @@
%include "effects/Tracker.h"
%include "effects/ObjectDetection.h"
%include "effects/Outline.h"
%include "effects/Shadow.h"
#endif
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -100,6 +100,7 @@ set(OPENSHOT_CV_SOURCES
effects/Tracker.cpp
effects/ObjectDetection.cpp
effects/Outline.cpp
effects/Shadow.cpp
./sort_filter/sort.cpp
./sort_filter/Hungarian.cpp
./sort_filter/KalmanTracker.cpp)
4 changes: 4 additions & 0 deletions src/EffectInfo.cpp
Original file line number Diff line number Diff line change
@@ -112,6 +112,9 @@
#ifdef USE_OPENCV
else if (effect_type == "Outline")
return new Outline();

else if (effect_type == "Shadow")
return new Shadow();

Check warning on line 117 in src/EffectInfo.cpp

Codecov / codecov/patch

src/EffectInfo.cpp#L116-L117

Added lines #L116 - L117 were not covered by tests

else if(effect_type == "Stabilizer")
return new Stabilizer();
@@ -165,6 +168,7 @@

#ifdef USE_OPENCV
root.append(Outline().JsonInfo());
root.append(Shadow().JsonInfo());

Check warning on line 171 in src/EffectInfo.cpp

Codecov / codecov/patch

src/EffectInfo.cpp#L171

Added line #L171 was not covered by tests
root.append(Stabilizer().JsonInfo());
root.append(Tracker().JsonInfo());
root.append(ObjectDetection().JsonInfo());
1 change: 1 addition & 0 deletions src/Effects.h
Original file line number Diff line number Diff line change
@@ -47,6 +47,7 @@

/* OpenCV Effects */
#ifdef USE_OPENCV
#include "effects/Shadow.h"
#include "effects/Outline.h"
#include "effects/ObjectDetection.h"
#include "effects/Tracker.h"
47 changes: 42 additions & 5 deletions src/Frame.cpp
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
* @file
* @brief Source file for Frame class
* @author Jonathan Thomas <jonathan@openshot.org>
* @author HaiVQ <me@haivq.com>
*
* @ref License
*/
@@ -112,6 +113,7 @@
audio.reset();
#ifdef USE_OPENCV
imagecv.release();
brga_image_cv.release();
#endif
}

@@ -890,6 +892,13 @@
return imagecv;
}

// Set pointer to OpenCV image object
void Frame::SetImageCV(cv::Mat _image)

Check warning on line 896 in src/Frame.cpp

Codecov / codecov/patch

src/Frame.cpp#L896

Added line #L896 was not covered by tests
{
imagecv = _image;
image = Mat2Qimage(_image);
}

Check warning on line 900 in src/Frame.cpp

Codecov / codecov/patch

src/Frame.cpp#L898-L900

Added lines #L898 - L900 were not covered by tests

std::shared_ptr<QImage> Frame::Mat2Qimage(cv::Mat img){
cv::cvtColor(img, img, cv::COLOR_BGR2RGB);
QImage qimg((uchar*) img.data, img.cols, img.rows, img.step, QImage::Format_RGB888);
@@ -903,11 +912,39 @@
return imgIn;
}

// Set pointer to OpenCV image object
void Frame::SetImageCV(cv::Mat _image)
{
imagecv = _image;
image = Mat2Qimage(_image);
// Convert QImage to cv::Mat and vice versa
// Frame class has GetImageCV, but it does not include alpha channel
// so we need a separate methods which preserve alpha channel
cv::Mat Frame::QImage2BGRACvMat(std::shared_ptr<QImage>& qimage) {
cv::Mat cv_img(
qimage->height(), qimage->width(),
CV_8UC4, (uchar*)qimage->constBits(),
qimage->bytesPerLine()
);
return cv_img;
}

// Convert cv::Mat back to QImage
std::shared_ptr<QImage> Frame::BGRACvMat2QImage(cv::Mat img) {
cv::Mat final_img;
cv::cvtColor(img, final_img, cv::COLOR_BGRA2RGBA);
QImage qimage(final_img.data, final_img.cols, final_img.rows, final_img.step, QImage::Format_ARGB32);
std::shared_ptr<QImage> imgIn = std::make_shared<QImage>(qimage.convertToFormat(QImage::Format_RGBA8888_Premultiplied));
return imgIn;
}

// Get BGRA
cv::Mat Frame::GetBGRACvMat() {
if (!image)
// Fill with black
AddColor(width, height, color);

Check warning on line 940 in src/Frame.cpp

Codecov / codecov/patch

src/Frame.cpp#L940

Added line #L940 was not covered by tests
brga_image_cv = QImage2BGRACvMat(image);
return brga_image_cv;
}

void Frame::SetBGRACvMat(cv::Mat _image) {
brga_image_cv = _image;
image = BGRACvMat2QImage(_image);
}
#endif

14 changes: 14 additions & 0 deletions src/Frame.h
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
* @file
* @brief Header file for Frame class
* @author Jonathan Thomas <jonathan@openshot.org>
* @author HaiVQ <me@haivq.com>
*
* @ref License
*/
@@ -106,6 +107,7 @@ namespace openshot

#ifdef USE_OPENCV
cv::Mat imagecv; ///< OpenCV image. It will always be in BGR format
cv::Mat brga_image_cv; ///< OpenCV image. It will always be in BGR format
#endif

/// Constrain a color value from 0 to 255
@@ -277,6 +279,18 @@ namespace openshot

/// Set pointer to OpenCV image object
void SetImageCV(cv::Mat _image);

/// Convert QImage to OpenCV Mat (alpha channel included)
cv::Mat QImage2BGRACvMat(std::shared_ptr<QImage>& qimage);

/// Convert OpenCV Mat to QImage (alpha channel included)
std::shared_ptr<QImage> BGRACvMat2QImage(cv::Mat img);

/// Get pointer to OpenCV Mat image object (with alpha channel)
cv::Mat GetBGRACvMat();

/// Set pointer to OpenCV image object (with alpha channel)
void SetBGRACvMat(cv::Mat _image);
#endif
};

41 changes: 20 additions & 21 deletions src/effects/Outline.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/**
* @file
* @brief Source file for Outline effect class
* @author Jonathan Thomas <jonathan@openshot.org>, HaiVQ <me@haivq.com>
*
* @author Jonathan Thomas <jonathan@openshot.org>
* @author HaiVQ <me@haivq.com>
*
* @ref License
*/

@@ -60,12 +61,11 @@ std::shared_ptr<openshot::Frame> Outline::GetFrame(std::shared_ptr<openshot::Fra
}

// Get the frame's image
std::shared_ptr<QImage> frame_image = frame->GetImage();

cv::Mat cv_image = frame->GetBGRACvMat();
float sigmaValue = widthValue / 3.0;
if (sigmaValue <= 0.0)
sigmaValue = 0.01;
cv::Mat cv_image = QImageToBGRACvMat(frame_image);

// Extract alpha channel for the mask
std::vector<cv::Mat> channels(4);
@@ -95,25 +95,24 @@ std::shared_ptr<openshot::Frame> Outline::GetFrame(std::shared_ptr<openshot::Fra
solid_color_mat.copyTo(final_image, outline_mask);
cv_image.copyTo(final_image, alpha_mask);

std::shared_ptr<QImage> new_frame_image = BGRACvMatToQImage(final_image);

// FIXME: The shared_ptr::swap does not work somehow
*frame_image = *new_frame_image;
frame->SetBGRACvMat(final_image);

return frame;
}

cv::Mat Outline::QImageToBGRACvMat(std::shared_ptr<QImage>& qimage) {
cv::Mat cv_img(qimage->height(), qimage->width(), CV_8UC4, (uchar*)qimage->constBits(), qimage->bytesPerLine());
return cv_img;
}

std::shared_ptr<QImage> Outline::BGRACvMatToQImage(cv::Mat img) {
cv::Mat final_img;
cv::cvtColor(img, final_img, cv::COLOR_RGBA2BGRA);
QImage qimage(final_img.data, final_img.cols, final_img.rows, final_img.step, QImage::Format_ARGB32);
std::shared_ptr<QImage> imgIn = std::make_shared<QImage>(qimage.convertToFormat(QImage::Format_RGBA8888_Premultiplied));
return imgIn;
}
// Moved to Frame.cpp
// cv::Mat Outline::QImageToBGRACvMat(std::shared_ptr<QImage>& qimage) {
// cv::Mat cv_img(qimage->height(), qimage->width(), CV_8UC4, (uchar*)qimage->constBits(), qimage->bytesPerLine());
// return cv_img;
// }

// std::shared_ptr<QImage> Outline::BGRACvMatToQImage(cv::Mat img) {
// cv::Mat final_img;
// cv::cvtColor(img, final_img, cv::COLOR_RGBA2BGRA);
// QImage qimage(final_img.data, final_img.cols, final_img.rows, final_img.step, QImage::Format_ARGB32);
// std::shared_ptr<QImage> imgIn = std::make_shared<QImage>(qimage.convertToFormat(QImage::Format_RGBA8888_Premultiplied));
// return imgIn;
// }

// Generate JSON string of this object
std::string Outline::Json() const {
13 changes: 6 additions & 7 deletions src/effects/Outline.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/**
* @file
* @brief Header file for Outline effect class
* @author Jonathan Thomas <jonathan@openshot.org>, HaiVQ <me@haivq.com>
* @author Jonathan Thomas <jonathan@openshot.org>
* @author HaiVQ <me@haivq.com>
*
* @ref License
*/
@@ -33,19 +34,17 @@ namespace openshot
* with openshot::Keyframe curves over time.
*
* Outlines can be added around any image or text, and animated over time.
* Idea from: https://stackoverflow.com/a/78480103
*/
class Outline : public EffectBase
{
private:
/// Init effect settings
void init_effect_details();

// Convert QImage to cv::Mat and vice versa
// Although Frame class has GetImageCV, but it does not include alpha channel
// so we need a separate methods which preserve alpha channel
// Idea from: https://stackoverflow.com/a/78480103
cv::Mat QImageToBGRACvMat(std::shared_ptr<QImage>& qimage);
std::shared_ptr<QImage> BGRACvMatToQImage(cv::Mat img);
// Moved to Frame.h
// cv::Mat QImageToBGRACvMat(std::shared_ptr<QImage>& qimage);
// std::shared_ptr<QImage> BGRACvMatToQImage(cv::Mat img);

public:
Keyframe width; ///< Width of the outline
Loading