From 9bd3133502873c24b672b1893587efd0b131abdf Mon Sep 17 00:00:00 2001 From: Andy Mina Date: Sat, 4 Nov 2023 11:31:11 -0400 Subject: [PATCH 1/2] add convenience methods for multiple seams --- libseam_carving/carver.cpp | 134 ++++++++++++++++++------ libseam_carving/seam_carving/carver.hpp | 52 ++++++++- 2 files changed, 152 insertions(+), 34 deletions(-) diff --git a/libseam_carving/carver.cpp b/libseam_carving/carver.cpp index 0325de9..1e1adbf 100644 --- a/libseam_carving/carver.cpp +++ b/libseam_carving/carver.cpp @@ -7,6 +7,7 @@ #include namespace seam_carving { + /** PROTECTED */ Seam Carver::FindVerticalSeam(cv::InputArray img) { // compute the energy map cv::Mat energy_map; @@ -261,6 +262,87 @@ namespace seam_carving { res.copyTo(output); } + /** PUBLIC */ + std::vector Carver::FindVerticalSeams(const int &k, cv::InputArray input) { + cv::Mat temp = input.getMat(); + std::vector seams; + + int count = k; + while (count > 0) { + Seam seam = FindVerticalSeam(temp); + seams.push_back(seam); + RemoveVerticalSeam(seam, temp, temp); + count--; + } + + return seams; + } + + std::vector Carver::FindHorizontalSeams(const int &k, cv::InputArray input) { + cv::Mat temp = input.getMat(); + std::vector seams; + + int count = k; + while (count > 0) { + Seam seam = FindHorizontalSeam(temp); + seams.push_back(seam); + RemoveHorizontalSeam(seam, temp, temp); + count--; + } + + return seams; + } + + void Carver::InsertVerticalSeams(const int& k, cv::InputArray input, cv::OutputArray output) { + std::vector seams = FindVerticalSeams(k, input); + input.copyTo(output); + + for (const Seam& s : seams) + InsertVerticalSeam(s, output, output); + } + + void Carver::InsertHorizontalSeams(const int& k, cv::InputArray input, cv::OutputArray output) { + std::vector seams = FindHorizontalSeams(k, input); + input.copyTo(output); + + for (const Seam& s : seams) + InsertHorizontalSeam(s, output, output); + } + + void Carver::InsertSeams(const std::vector& seams, cv::InputOutputArray output) { + for (const Seam& s : seams) { + if (s.dir() == VERT) + InsertVerticalSeam(s, output, output); + else + InsertHorizontalSeam(s, output, output); + } + } + + void Carver::RemoveVerticalSeams(const int& k, cv::InputArray input, cv::OutputArray output) { + std::vector seams = FindVerticalSeams(k, input); + input.copyTo(output); + + for (const Seam& s : seams) + RemoveVerticalSeam(s, output, output); + } + + void Carver::RemoveHorizontalSeams(const int& k, cv::InputArray input, cv::OutputArray output) { + std::vector seams = FindHorizontalSeams(k, input); + input.copyTo(output); + + for (const Seam& s : seams) + RemoveHorizontalSeam(s, output, output); + } + + void Carver::RemoveSeams(const std::vector& seams, cv::InputOutputArray output) { + for (const Seam& s : seams) { + if (s.dir() == VERT) + RemoveVerticalSeam(s, output, output); + else + RemoveHorizontalSeam(s, output, output); + } + } + void Carver::Carve(const int& rows, const int& cols, cv::InputArray input, cv::OutputArray output) { // (0, 0) if (rows == 0 && cols == 0) { @@ -278,55 +360,47 @@ namespace seam_carving { int col_diff = cols - res.cols; /** HANDLE ALL CASES WHERE ONE DIMENSION IS POSITIVE */ - // (+, +) + // (+, +) - alternate seam inserting starting with vertical while (row_diff > 0 && col_diff > 0) { - const Seam verticalSeam = FindVerticalSeam(res); - InsertVerticalSeam(verticalSeam, res, res); + InsertVerticalSeams(1, res, res); col_diff--; // update the remaining difference - const Seam horizontalSeam = FindHorizontalSeam(res); - InsertHorizontalSeam(horizontalSeam, res, res); + InsertHorizontalSeams(1, res, res); row_diff--; // update the remaining difference } - // (0/-, +) - while (col_diff > 0) { - const Seam verticalSeam = FindVerticalSeam(res); - InsertVerticalSeam(verticalSeam, res, res); - col_diff--; + // (0/-, +) - insert any remaining vertical seams necessary + if (col_diff > 0) { + InsertVerticalSeams(col_diff, res, res); + col_diff = 0; } - // (+, 0/-) - while (row_diff > 0) { - const Seam horizontalSeam = FindHorizontalSeam(res); - InsertHorizontalSeam(horizontalSeam, res, res); - row_diff--; + // (+, 0/-) - insert any remaining horizontal seams necessary + if (row_diff > 0) { + InsertHorizontalSeams(row_diff, res, res); + row_diff = 0; } /** HANDLE ALL CASES WHERE ONE DIMENSION IS NEGATIVE */ - // (-, -) + // (-, -) - alternate seam removal starting with vertical while (row_diff < 0 && col_diff < 0) { - const Seam verticalSeam = FindVerticalSeam(res); - RemoveVerticalSeam(verticalSeam, res, res); + RemoveVerticalSeams(1, res, res); col_diff++; // update the remaining difference - const Seam horizontalSeam = FindHorizontalSeam(res); - RemoveHorizontalSeam(horizontalSeam, res, res); + RemoveHorizontalSeams(1, res, res); row_diff++; // update the remaining difference } - // (0/+, -) - while (col_diff < 0) { - const Seam verticalSeam = FindVerticalSeam(res); - RemoveVerticalSeam(verticalSeam, res, res); - col_diff++; + // (0/+, -) - remove any remaining vertical seams necessary + if (col_diff < 0) { + RemoveVerticalSeams(col_diff * -1, res, res); + col_diff = 0; } - // (-, 0/+) - while (row_diff < 0) { - const Seam horizontalSeam = FindHorizontalSeam(res); - RemoveHorizontalSeam(horizontalSeam, res, res); - row_diff++; + // (-, 0/+) - remove any remaining horizontal seams necessary + if (row_diff < 0) { + RemoveHorizontalSeams(row_diff * -1, res, res); + row_diff = 0; } res.copyTo(output); diff --git a/libseam_carving/seam_carving/carver.hpp b/libseam_carving/seam_carving/carver.hpp index 1334699..52ba057 100644 --- a/libseam_carving/seam_carving/carver.hpp +++ b/libseam_carving/seam_carving/carver.hpp @@ -15,13 +15,14 @@ // std #include #include +#include namespace seam_carving { /** * Base class for all carvers */ class Carver { - public: + protected: /** * @param img the image to find the optimal seam in * @returns the optimal seam to be removed @@ -30,9 +31,9 @@ namespace seam_carving { static Seam FindHorizontalSeam(cv::InputArray img); /** - * @param seam the seam to be removed - * @param img the target image - */ + * @param seam the seam to be removed + * @param img the target image + */ static void RemoveVerticalSeam(const Seam &seam, cv::InputArray input, cv::OutputArray output); static void RemoveHorizontalSeam(const Seam &seam, cv::InputArray input, cv::OutputArray output); @@ -43,6 +44,49 @@ namespace seam_carving { static void InsertVerticalSeam(const Seam &seam, cv::InputArray input, cv::OutputArray output); static void InsertHorizontalSeam(const Seam &seam, cv::InputArray input, cv::OutputArray output); + public: + /** + * Finds the first k vertical/horizontal seams for removal. + * + * @param k the number of seams to find + * @param input the image to find the seams in + * @return a vector of the first k seams for removal + */ + static std::vector FindVerticalSeams(const int& k, cv::InputArray input); + static std::vector FindHorizontalSeams(const int& k, cv::InputArray input); + + /** + * Inserts k vertical/horizontal seams. + * @param k the number of seams to insert + * @param input the image to find seams in + * @param output the image to insert seams into + */ + static void InsertVerticalSeams(const int& k, cv::InputArray input, cv::OutputArray output); + static void InsertHorizontalSeams(const int& k, cv::InputArray input, cv::OutputArray output); + + /** + * Inserts the specified seams, regardless of direction, into the image appropriately. + * @param seams the seams to be inserted + * @param output the image to insert seams into + */ + static void InsertSeams(const std::vector& seams, cv::InputOutputArray output); + + /** + * Removes k vertical/horizontal seams. + * @param k the number of seams to remove + * @param input the image to find seams in + * @param output the image to remove seams from + */ + static void RemoveVerticalSeams(const int& k, cv::InputArray input, cv::OutputArray output); + static void RemoveHorizontalSeams(const int& k, cv::InputArray input, cv::OutputArray output); + + /** + * Removes the specified seams, regardless of direction, from the image appropriately. + * @param seams the seams to be removed + * @param output the image to remove seams from + */ + static void RemoveSeams(const std::vector& seams, cv::InputOutputArray output); + /** * @param rows the target number of rows for the new image * @param cols the target number of cols for the new image From d0f07aaad25751dc612aabe59c1596d7717b978a Mon Sep 17 00:00:00 2001 From: Andy Mina Date: Sat, 4 Nov 2023 11:33:41 -0400 Subject: [PATCH 2/2] adjust carver tests to use convenience methods --- tests/unit/carver.test.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/unit/carver.test.cpp b/tests/unit/carver.test.cpp index b6e87d2..e7494dd 100644 --- a/tests/unit/carver.test.cpp +++ b/tests/unit/carver.test.cpp @@ -30,33 +30,33 @@ INSTANTIATE_TEST_SUITE_P( ) ); -TEST_P(CarverTest, FindVerticalSeam) { +TEST_P(CarverTest, FindVerticalSeams) { sct::CarverData carver_data = GetParam(); cv::Mat input = carver_data.original_matrix; sc::Seam expected = carver_data.vertical_seam; - sc::Seam actual = sc::Carver::FindVerticalSeam(input); + sc::Seam actual = sc::Carver::FindVerticalSeams(1, input)[0]; EXPECT_EQ(expected, actual) << sct::PrintWithLabel(expected, "expected") << "\n" << sct::PrintWithLabel(actual, "actual"); } -TEST_P(CarverTest, FindHorizontalSeam) { +TEST_P(CarverTest, FindHorizontalSeams) { sct::CarverData carver_data = GetParam(); cv::Mat input = carver_data.original_matrix; sc::Seam expected = carver_data.horizontal_seam; - sc::Seam actual = sc::Carver::FindHorizontalSeam(input); + sc::Seam actual = sc::Carver::FindHorizontalSeams(1, input)[0]; EXPECT_EQ(expected, actual) << sct::PrintWithLabel(expected, "expected") << "\n" << sct::PrintWithLabel(actual, "actual"); } -TEST_P(CarverTest, RemoveVerticalSeam) { +TEST_P(CarverTest, RemoveVerticalSeams) { sct::CarverData carver_data = GetParam(); cv::Mat input = carver_data.original_matrix; @@ -64,14 +64,14 @@ TEST_P(CarverTest, RemoveVerticalSeam) { cv::Mat actual; sc::Seam seam = carver_data.vertical_seam; - sc::Carver::RemoveVerticalSeam(seam, input, actual); + sc::Carver::RemoveVerticalSeams(1, input, actual); EXPECT_TRUE(sct::equalMatrices(expected, actual)) << sct::PrintWithLabel(expected, "expected") << "\n" << sct::PrintWithLabel(actual, "actual"); } -TEST_P(CarverTest, RemoveHorizontalSeam) { +TEST_P(CarverTest, RemoveHorizontalSeams) { sct::CarverData carver_data = GetParam(); cv::Mat input = carver_data.original_matrix; @@ -79,7 +79,7 @@ TEST_P(CarverTest, RemoveHorizontalSeam) { cv::Mat actual; sc::Seam seam = carver_data.horizontal_seam; - sc::Carver::RemoveHorizontalSeam(seam, input, actual); + sc::Carver::RemoveHorizontalSeams(1, input, actual); EXPECT_TRUE(sct::equalMatrices(expected, actual)) << sct::PrintWithLabel(expected, "expected") << "\n" @@ -94,7 +94,7 @@ TEST_P(CarverTest, InsertVerticalSeam) { cv::Mat actual; sc::Seam seam = carver_data.vertical_seam; - sc::Carver::InsertVerticalSeam(seam, input, actual); + sc::Carver::InsertVerticalSeams(1, input, actual); EXPECT_TRUE(sct::equalMatrices(expected, actual)) << sct::PrintWithLabel(expected, "expected") << "\n" @@ -109,7 +109,7 @@ TEST_P(CarverTest, InsertHorizontalSeam) { cv::Mat actual; sc::Seam seam = carver_data.horizontal_seam; - sc::Carver::InsertHorizontalSeam(seam, input, actual); + sc::Carver::InsertHorizontalSeams(1, input, actual); EXPECT_TRUE(sct::equalMatrices(expected, actual)) << sct::PrintWithLabel(expected, "expected") << "\n"