X-Git-Url: https://git.sesse.net/?p=movit;a=blobdiff_plain;f=deinterlace_effect_test.cpp;fp=deinterlace_effect_test.cpp;h=31bd363024bb22ef3db70b51a1a29608b3b29abc;hp=0000000000000000000000000000000000000000;hb=c06f1c4cc39bbebe13fe8e42a9278a55b5d0a216;hpb=4b08ab8b7c55672e8a44afea18f5a6b3a66bd502 diff --git a/deinterlace_effect_test.cpp b/deinterlace_effect_test.cpp new file mode 100644 index 0000000..31bd363 --- /dev/null +++ b/deinterlace_effect_test.cpp @@ -0,0 +1,196 @@ +// Unit tests for DeinterlaceEffect. + +#include + +#include + +#include "effect_chain.h" +#include "gtest/gtest.h" +#include "image_format.h" +#include "input.h" +#include "deinterlace_effect.h" +#include "test_util.h" + +using namespace std; + +namespace movit { + +TEST(DeinterlaceTest, ConstantColor) { + float data[] = { + 0.3f, 0.3f, + 0.3f, 0.3f, + 0.3f, 0.3f, + }; + float expected_data[] = { + 0.3f, 0.3f, + 0.3f, 0.3f, + 0.3f, 0.3f, + 0.3f, 0.3f, + 0.3f, 0.3f, + 0.3f, 0.3f, + }; + float out_data[12]; + EffectChainTester tester(NULL, 2, 6); + Effect *input1 = tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, 2, 3); + Effect *input2 = tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, 2, 3); + Effect *input3 = tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, 2, 3); + Effect *input4 = tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, 2, 3); + Effect *input5 = tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, 2, 3); + Effect *deinterlace_effect = tester.get_chain()->add_effect(new DeinterlaceEffect(), input1, input2, input3, input4, input5); + + ASSERT_TRUE(deinterlace_effect->set_int("current_field_position", 0)); + tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR); + expect_equal(expected_data, out_data, 2, 6); + + ASSERT_TRUE(deinterlace_effect->set_int("current_field_position", 1)); + tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR); + expect_equal(expected_data, out_data, 2, 6); +} + +// Also tests that top/bottom change works like expected. +TEST(DeinterlaceTest, VerticalInterpolation) { + const int width = 11; + const int height = 2; + float data[width * height] = { + 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.2f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.4f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, // Differs from previous. + }; + float expected_data_top[width * height * 2] = { + 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.2f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, // Unchanged. + 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.3f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.4f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, // Unchanged. + 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.4f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, // Repeated. + }; + float expected_data_bottom[width * height * 2] = { + 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.2f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, // Repeated + 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.2f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, // Unchanged. + 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.3f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.4f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, // Unchanged. + }; + float neg_blowout_data[width * height]; + float pos_blowout_data[width * height]; + float out_data[width * height * 2]; + + // Set previous and next fields to something so big that all the temporal checks + // are effectively turned off. + fill(neg_blowout_data, neg_blowout_data + width * height, -100.0f); + fill(neg_blowout_data, pos_blowout_data + width * height, 100.0f); + + EffectChainTester tester(NULL, width, height * 2); + Effect *input1 = tester.add_input(neg_blowout_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height); + Effect *input2 = tester.add_input(neg_blowout_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height); + Effect *input3 = tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height); + Effect *input4 = tester.add_input(pos_blowout_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height); + Effect *input5 = tester.add_input(pos_blowout_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height); + Effect *deinterlace_effect = tester.get_chain()->add_effect(new DeinterlaceEffect(), input1, input2, input3, input4, input5); + + ASSERT_TRUE(deinterlace_effect->set_int("current_field_position", 0)); + tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR); + expect_equal(expected_data_top, out_data, width, height * 2); + + ASSERT_TRUE(deinterlace_effect->set_int("current_field_position", 1)); + tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR); + expect_equal(expected_data_bottom, out_data, width, height * 2); +} + +TEST(DeinterlaceTest, DiagonalInterpolation) { + const int width = 11; + const int height = 3; + float data[width * height] = { + 0.0f, 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.2f, 0.6f, 0.8f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.4f, 0.6f, 0.4f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, 0.0f, // Offset two pixels, one value modified. + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.4f, 0.6f, 0.8f, // Offset four the other way. + }; + + // Expected degrees are marked in comments. Mostly we want +45 for the second line + // and -63 for the fourth, but due to the score being over three neighboring pixels, + // sometimes it doesn't work ideally like that. + float expected_data_top[width * height * 2] = { + 0.0f, 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.2f, 0.6f, 0.8f, 0.0f, 0.0f, // Unchanged. + // | / / / / / / / / / | + // 0 +45 +45 +45 +45 +45 +45 +45 +45 +45 0 + 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.3f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, + // | / / / / / / / / / | + 0.0f, 0.0f, 0.4f, 0.6f, 0.4f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, 0.0f, // Unchanged. + + // 0 -45 -63 -63 -63 -63 -63 -63 +63! +63! +63! + 0.0f, 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.4f, 0.6f, 0.2f, 0.3f, 0.2f, + + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.4f, 0.6f, 0.8f, // Unchanged. + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.4f, 0.6f, 0.8f, // Repeated. + }; + float neg_blowout_data[width * height]; + float pos_blowout_data[width * height]; + float out_data[width * height * 2]; + + // Set previous and next fields to something so big that all the temporal checks + // are effectively turned off. + fill(neg_blowout_data, neg_blowout_data + width * height, -100.0f); + fill(pos_blowout_data, pos_blowout_data + width * height, 100.0f); + + EffectChainTester tester(NULL, width, height * 2); + Effect *input1 = tester.add_input(neg_blowout_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height); + Effect *input2 = tester.add_input(neg_blowout_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height); + Effect *input3 = tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height); + Effect *input4 = tester.add_input(pos_blowout_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height); + Effect *input5 = tester.add_input(pos_blowout_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height); + Effect *deinterlace_effect = tester.get_chain()->add_effect(new DeinterlaceEffect(), input1, input2, input3, input4, input5); + + ASSERT_TRUE(deinterlace_effect->set_int("current_field_position", 0)); + tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR, OUTPUT_ALPHA_FORMAT_PREMULTIPLIED); + expect_equal(expected_data_top, out_data, width, height * 2); +} + +TEST(DeinterlaceTest, FlickerBox) { + const int width = 4; + const int height = 4; + float white_data[width * height] = { + 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + }; + float black_data[width * height] = { + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + }; + float striped_data[width * height * 2] = { + 1.0f, 1.0f, 1.0f, 1.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + }; + float out_data[width * height * 2]; + + { + EffectChainTester tester(NULL, width, height * 2); + Effect *white_input = tester.add_input(white_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height); + Effect *black_input = tester.add_input(black_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height); + Effect *deinterlace_effect = tester.get_chain()->add_effect(new DeinterlaceEffect(), white_input, black_input, white_input, black_input, white_input); + + ASSERT_TRUE(deinterlace_effect->set_int("current_field_position", 0)); + tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR, OUTPUT_ALPHA_FORMAT_PREMULTIPLIED); + expect_equal(white_data, out_data, width, height); + expect_equal(white_data, out_data + width * height, width, height); + } + + { + EffectChainTester tester(NULL, width, height * 2); + Effect *white_input = tester.add_input(white_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height); + Effect *black_input = tester.add_input(black_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height); + Effect *deinterlace_effect = tester.get_chain()->add_effect(new DeinterlaceEffect(), white_input, black_input, white_input, black_input, white_input); + + ASSERT_TRUE(deinterlace_effect->set_int("enable_spatial_interlacing_check", 0)); + ASSERT_TRUE(deinterlace_effect->set_int("current_field_position", 0)); + tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR, OUTPUT_ALPHA_FORMAT_PREMULTIPLIED); + expect_equal(striped_data, out_data, width, height * 2); + } +} + +} // namespace movit