2025-05-23 15:09:02 -05:00
|
|
|
|
/**
|
2025-05-23 16:50:04 -05:00
|
|
|
|
* @file
|
|
|
|
|
|
* @brief Unit tests for Sharpen effect
|
|
|
|
|
|
* @author Jonathan Thomas <jonathan@openshot.org>
|
|
|
|
|
|
*
|
|
|
|
|
|
* @ref License
|
2025-05-23 15:09:02 -05:00
|
|
|
|
*/
|
|
|
|
|
|
|
2025-05-23 16:50:04 -05:00
|
|
|
|
// Copyright (c) 2008-2025 OpenShot Studios, LLC
|
|
|
|
|
|
//
|
|
|
|
|
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
|
|
|
|
|
2025-05-23 15:09:02 -05:00
|
|
|
|
#include <memory>
|
|
|
|
|
|
#include <QImage>
|
|
|
|
|
|
#include <QColor>
|
|
|
|
|
|
#include "Frame.h"
|
|
|
|
|
|
#include "effects/Sharpen.h"
|
|
|
|
|
|
#include "openshot_catch.h"
|
|
|
|
|
|
|
|
|
|
|
|
using namespace openshot;
|
|
|
|
|
|
|
|
|
|
|
|
// allow Catch2 to print QColor on failure
|
|
|
|
|
|
static std::ostream& operator<<(std::ostream& os, QColor const& c)
|
|
|
|
|
|
{
|
|
|
|
|
|
os << "QColor(" << c.red() << "," << c.green()
|
|
|
|
|
|
<< "," << c.blue() << "," << c.alpha() << ")";
|
|
|
|
|
|
return os;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-23 16:11:17 -05:00
|
|
|
|
// Create a tiny 3×720 grayscale frame
|
|
|
|
|
|
static std::shared_ptr<Frame> makeGrayFrame()
|
2025-05-23 15:09:02 -05:00
|
|
|
|
{
|
2025-05-23 16:11:17 -05:00
|
|
|
|
QImage img(3, 720, QImage::Format_ARGB32);
|
2025-05-23 15:09:02 -05:00
|
|
|
|
img.fill(QColor(128,128,128,255));
|
2025-05-23 16:11:17 -05:00
|
|
|
|
img.setPixelColor(1,1, QColor(100,100,100,255));
|
2025-05-23 15:09:02 -05:00
|
|
|
|
auto frame = std::make_shared<Frame>();
|
|
|
|
|
|
*frame->GetImage() = img;
|
|
|
|
|
|
return frame;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-23 16:11:17 -05:00
|
|
|
|
// Create a tiny 3×720 colored frame
|
|
|
|
|
|
static std::shared_ptr<Frame> makeColorFrame()
|
2025-05-23 15:09:02 -05:00
|
|
|
|
{
|
2025-05-23 16:11:17 -05:00
|
|
|
|
QImage img(3, 720, QImage::Format_ARGB32);
|
|
|
|
|
|
img.fill(QColor(128,128,128,255));
|
|
|
|
|
|
img.setPixelColor(1,1, QColor(100,150,200,255));
|
|
|
|
|
|
auto frame = std::make_shared<Frame>();
|
|
|
|
|
|
*frame->GetImage() = img;
|
|
|
|
|
|
return frame;
|
2025-05-23 15:09:02 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-23 16:11:17 -05:00
|
|
|
|
TEST_CASE("zero radius leaves image unchanged", "[effect][sharpen]")
|
|
|
|
|
|
{
|
|
|
|
|
|
Sharpen effect;
|
|
|
|
|
|
effect.amount = Keyframe(1.0);
|
|
|
|
|
|
effect.radius = Keyframe(0.0);
|
|
|
|
|
|
effect.threshold = Keyframe(1.0);
|
|
|
|
|
|
|
|
|
|
|
|
auto frame = makeGrayFrame();
|
|
|
|
|
|
QColor before = frame->GetImage()->pixelColor(1,1);
|
|
|
|
|
|
|
|
|
|
|
|
auto out = effect.GetFrame(frame, 1);
|
|
|
|
|
|
QColor after = out->GetImage()->pixelColor(1,1);
|
|
|
|
|
|
|
|
|
|
|
|
CHECK(after == before);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_CASE("nonzero radius and threshold sharpens tiny grayscale image", "[effect][sharpen]")
|
2025-05-23 15:09:02 -05:00
|
|
|
|
{
|
|
|
|
|
|
Sharpen effect;
|
|
|
|
|
|
effect.amount = Keyframe(1.0);
|
|
|
|
|
|
effect.radius = Keyframe(1.0);
|
2025-05-23 16:11:17 -05:00
|
|
|
|
effect.threshold = Keyframe(1.0);
|
2025-05-23 15:09:02 -05:00
|
|
|
|
|
2025-05-23 16:11:17 -05:00
|
|
|
|
auto frame = makeGrayFrame();
|
|
|
|
|
|
QColor before = frame->GetImage()->pixelColor(1,1);
|
2025-05-23 15:09:02 -05:00
|
|
|
|
|
2025-05-23 16:11:17 -05:00
|
|
|
|
auto out = effect.GetFrame(frame, 1);
|
|
|
|
|
|
QColor after = out->GetImage()->pixelColor(1,1);
|
2025-05-23 15:09:02 -05:00
|
|
|
|
|
2025-05-23 16:11:17 -05:00
|
|
|
|
CHECK(after != before);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_CASE("zero amount leaves image unchanged", "[effect][sharpen]")
|
|
|
|
|
|
{
|
|
|
|
|
|
Sharpen effect;
|
|
|
|
|
|
effect.amount = Keyframe(0.0);
|
|
|
|
|
|
effect.radius = Keyframe(1.0);
|
|
|
|
|
|
effect.threshold = Keyframe(1.0);
|
|
|
|
|
|
|
|
|
|
|
|
auto frame = makeGrayFrame();
|
|
|
|
|
|
QColor before = frame->GetImage()->pixelColor(1,1);
|
|
|
|
|
|
|
|
|
|
|
|
auto out = effect.GetFrame(frame, 1);
|
|
|
|
|
|
QColor after = out->GetImage()->pixelColor(1,1);
|
|
|
|
|
|
|
|
|
|
|
|
CHECK(after == before);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_CASE("HighPass vs UnsharpMask produce distinct results on grayscale", "[effect][sharpen]")
|
|
|
|
|
|
{
|
|
|
|
|
|
Sharpen usm, hp;
|
|
|
|
|
|
usm.amount = Keyframe(2.0);
|
|
|
|
|
|
usm.radius = Keyframe(1.0);
|
|
|
|
|
|
usm.threshold = Keyframe(0.0);
|
|
|
|
|
|
usm.mode = 0; // UnsharpMask
|
|
|
|
|
|
|
|
|
|
|
|
hp = usm;
|
|
|
|
|
|
hp.mode = 1; // HighPassBlend
|
|
|
|
|
|
|
|
|
|
|
|
auto f1 = makeGrayFrame();
|
|
|
|
|
|
auto f2 = makeGrayFrame();
|
|
|
|
|
|
|
|
|
|
|
|
QColor out_usm = usm.GetFrame(f1,1)->GetImage()->pixelColor(1,1);
|
|
|
|
|
|
QColor out_hp = hp .GetFrame(f2,1)->GetImage()->pixelColor(1,1);
|
|
|
|
|
|
|
|
|
|
|
|
CHECK(out_hp != out_usm);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_CASE("Luma-only differs from All on colored image", "[effect][sharpen]")
|
|
|
|
|
|
{
|
|
|
|
|
|
Sharpen allc, lumac;
|
|
|
|
|
|
allc.amount = Keyframe(2.0);
|
|
|
|
|
|
allc.radius = Keyframe(1.0);
|
|
|
|
|
|
allc.threshold = Keyframe(0.0);
|
|
|
|
|
|
allc.mode = 0;
|
|
|
|
|
|
allc.channel = 0; // All
|
|
|
|
|
|
|
|
|
|
|
|
lumac = allc;
|
|
|
|
|
|
lumac.channel = 1; // Luma only
|
|
|
|
|
|
|
|
|
|
|
|
auto f_all = makeColorFrame();
|
|
|
|
|
|
auto f_luma = makeColorFrame();
|
|
|
|
|
|
|
|
|
|
|
|
QColor out_all = allc .GetFrame(f_all, 1)->GetImage()->pixelColor(1,1);
|
|
|
|
|
|
QColor out_luma = lumac.GetFrame(f_luma,1)->GetImage()->pixelColor(1,1);
|
|
|
|
|
|
|
|
|
|
|
|
CHECK(out_luma != out_all);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_CASE("Chroma-only differs from All on colored image", "[effect][sharpen]")
|
|
|
|
|
|
{
|
|
|
|
|
|
Sharpen allc, chromac;
|
|
|
|
|
|
allc.amount = Keyframe(2.0);
|
|
|
|
|
|
allc.radius = Keyframe(1.0);
|
|
|
|
|
|
allc.threshold = Keyframe(0.0);
|
|
|
|
|
|
allc.mode = 0;
|
|
|
|
|
|
allc.channel = 0; // All
|
|
|
|
|
|
|
|
|
|
|
|
chromac = allc;
|
|
|
|
|
|
chromac.channel = 2; // Chroma only
|
|
|
|
|
|
|
|
|
|
|
|
auto f_all = makeColorFrame();
|
|
|
|
|
|
auto f_chroma = makeColorFrame();
|
|
|
|
|
|
|
|
|
|
|
|
QColor out_all = allc .GetFrame(f_all, 1)->GetImage()->pixelColor(1,1);
|
|
|
|
|
|
QColor out_chroma = chromac.GetFrame(f_chroma,1)->GetImage()->pixelColor(1,1);
|
|
|
|
|
|
|
|
|
|
|
|
CHECK(out_chroma != out_all);
|
|
|
|
|
|
}
|