Skip to content
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

docs(#52): update README to have demo and new build instructions #72

Merged
merged 3 commits into from
Nov 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 9 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,12 @@ add_subdirectory(libseam_carving)
enable_testing()
include(GoogleTest)
add_subdirectory(tests)

# demo
add_executable(demo demo.cpp)
target_include_directories(demo
PRIVATE
${LIBRARY_TEST_DIR}/include)
target_link_libraries(demo
PRIVATE
seam_carving ${OPENCV_LIBS})
33 changes: 21 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,30 @@ content-aware image resizing](https://doi.org/10.1145/1275808.1276390). Learn mo

## Getting Started

It is recommended to make a virtual environment as the setup command will install pip packages.
This project uses [vcpkg](https://github.com/microsoft/vcpkg) as its C++ package manager and
[CMake](https://cmake.org) as the build-system.
The seam carving library can be built using CMake. The available targets are:

Run `make setup` from the root directory to set up the project. This will create and populate a `build/` directory and create a new `out/` directory where output files will
go by default.
- `seam_carving` - builds the dylib
- `demo` - runs the demo at `./demo.cpp`
- `carver_unit/energy_unit` - runs the unit tests at `tests/unit/[carver/energy].test.cpp` respectively

The following `make` commands are currently available:
### Running the demo

- `make demo`: builds a C++17 executable to demo seam carving. Sample images are provided in the
`samples/` directory
- `make py`: exports the existing C++ seam carving code to a Python 3.10 package called `seam_carving`
- `make clean`: cleans the project and removes any build files
1. Configure the CMake project. The code sample below uses Ninja as the generator. There are presets in `CMakePresets.json`
available to use.
2. Build the `demo` target.
3. Run the demo target with a path to an image (sample images are provided in `samples/`), and the target size

```
# step 1 - from the root folder of the repo
cmake -B {PATH_TO_BUILD_DIR} -S {PATH_TO_REPO_ROOT} -G Ninja --preset default

# step 2
cmake --build {PATH_TO_BUILD_DIR} --target demo

# step 3
./demo {PATH_TO_IMG} {TARGET COLS} {TARGET ROWS}
```

## Seam Carving Shell (SCS)

The Seam Carving Shell can be run from the `cli.py` file at the root: `python cli.py`. The cli
requires at least Python 3.10.
The Seam Carving Shell (SCS) is undergoing major reconstruction and is not supported in v2.0.0.
71 changes: 66 additions & 5 deletions demo.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,71 @@
//
// Created by Andy Mina on 3/7/23.
//
/**
* Andy Mina
*
* File to test SeamCarver in C++ implementation. Given a path to an image, the target number of
* rows, and the target number of cols, carves the image and displays the result.
*
* Args:
* {path to img}
* {target rows}
* {target cols}
*/
#include "timer.hpp"
#include <seam_carving/carver.hpp>

#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>

#include <iostream>
#include <string>
#include <chrono>

namespace sc = seam_carving;

template <class Duration = std::chrono::milliseconds, class Clock = std::chrono::steady_clock>
class Timer {
using time_pt = typename Clock::time_point;

time_pt _start = Clock::now();
time_pt _end = {};

public:
void tick() { _start = Clock::now(); }
void tock() { _end = Clock::now(); }

template <class T = Duration>
auto duration() const {
return std::chrono::duration_cast<T>(_end - _start).count();
}
};

int main(int argc, char **argv) {
if (argc != 4) {
std::cout << "Usage: " << argv[0] << " {path to img} {target cols} {target rows}\n";
return -1;
}

const std::string input_path(argv[1]);
const int target_cols(std::stoi(argv[2]));
const int target_rows(std::stoi(argv[3]));

cv::Mat img = cv::imread(input_path);
std::cout << "Original size: " << img.cols << "x" << img.rows << "\n";

cv::Mat res = img;
Timer carver_timer;

std::cout << "Starting carving...\n";

carver_timer.tick();
sc::Carver::Carve(target_rows, target_cols, img, res);
carver_timer.tock();

std::cout << "Carved size: " << res.cols << "x" << res.rows << "\n";
std::cout << "Carving took " << carver_timer.duration() << " ms\n";

int main() {
std::cout << "hello world\n";
cv::imshow("Original", img);
cv::imshow("Carved", res);
int k = cv::waitKey(0);
return 0;
}
71 changes: 71 additions & 0 deletions libseam_carving/carver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,4 +249,75 @@ namespace seam_carving {

res.copyTo(output);
}

void Carver::Carve(const int& rows, const int& cols, cv::InputArray input, cv::OutputArray output) {
// (0, 0)
if (rows == 0 && cols == 0) {
input.copyTo(output);
return;
}

// prepare result
cv::Mat res;
input.copyTo(res);

// Difference between target size and current size.
// Positive to insert seams, negative to remove.
int row_diff = rows - res.rows;
int col_diff = cols - res.cols;

/** HANDLE ALL CASES WHERE ONE DIMENSION IS POSITIVE */
// (+, +)
while (row_diff > 0 && col_diff > 0) {
const Seam verticalSeam = FindVerticalSeam(res);
InsertVerticalSeam(verticalSeam, res, res);
col_diff--; // update the remaining difference

const Seam horizontalSeam = FindHorizontalSeam(res);
InsertHorizontalSeam(horizontalSeam, 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/-)
while (row_diff > 0) {
const Seam horizontalSeam = FindHorizontalSeam(res);
InsertHorizontalSeam(horizontalSeam, res, res);
row_diff--;
}

/** HANDLE ALL CASES WHERE ONE DIMENSION IS NEGATIVE */
// (-, -)
while (row_diff < 0 && col_diff < 0) {
const Seam verticalSeam = FindVerticalSeam(res);
RemoveVerticalSeam(verticalSeam, res, res);
col_diff++; // update the remaining difference

const Seam horizontalSeam = FindHorizontalSeam(res);
RemoveHorizontalSeam(horizontalSeam, 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/+)
while (row_diff < 0) {
const Seam horizontalSeam = FindHorizontalSeam(res);
RemoveHorizontalSeam(horizontalSeam, res, res);
row_diff++;
}

res.copyTo(output);
}
}
10 changes: 9 additions & 1 deletion libseam_carving/seam_carving/carver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace seam_carving {
* Base class for all carvers
*/
class Carver {
protected:
public:
/**
* @param img the image to find the optimal seam in
* @returns the optimal seam to be removed
Expand All @@ -42,6 +42,14 @@ 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);

/**
* @param rows the target number of rows for the new image
* @param cols the target number of cols for the new image
* @param input the image to be carved
* @param output a carved version of input
*/
static void Carve(const int& rows, const int& cols, cv::InputArray input, cv::OutputArray output);
};
}

Expand Down
40 changes: 0 additions & 40 deletions tests/include/dummy_carver.hpp

This file was deleted.

21 changes: 10 additions & 11 deletions tests/unit/carver.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@
// Created by Andy Mina on 3/7/23.
//

// project
#include <seam_carving/carver.hpp>
#include <seam_carving/seam.hpp>

// test
#include "print_utils.hpp"
#include "matrix_utils.hpp"
#include "json_utils.hpp"
#include "carver_data.hpp"
#include "dummy_carver.hpp"

// project
#include <seam_carving/carver.hpp>
#include <seam_carving/seam.hpp>

// 3rd party
#include <gtest/gtest.h>
Expand All @@ -37,7 +36,7 @@ TEST_P(CarverTest, FindVerticalSeam) {
cv::Mat input = carver_data.original_matrix;
sc::Seam expected = carver_data.vertical_seam;

sc::Seam actual = sct::DummyCarver::FindVerticalSeam(input);
sc::Seam actual = sc::Carver::FindVerticalSeam(input);

EXPECT_EQ(expected, actual)
<< sct::PrintWithLabel(expected, "expected") << "\n"
Expand All @@ -50,7 +49,7 @@ TEST_P(CarverTest, FindHorizontalSeam) {
cv::Mat input = carver_data.original_matrix;
sc::Seam expected = carver_data.horizontal_seam;

sc::Seam actual = sct::DummyCarver::FindHorizontalSeam(input);
sc::Seam actual = sc::Carver::FindHorizontalSeam(input);

EXPECT_EQ(expected, actual)
<< sct::PrintWithLabel(expected, "expected") << "\n"
Expand All @@ -65,7 +64,7 @@ TEST_P(CarverTest, RemoveVerticalSeam) {
cv::Mat actual;

sc::Seam seam = carver_data.vertical_seam;
sct::DummyCarver::RemoveVerticalSeam(seam, input, actual);
sc::Carver::RemoveVerticalSeam(seam, input, actual);

EXPECT_TRUE(sct::equalMatrices(expected, actual))
<< sct::PrintWithLabel(expected, "expected") << "\n"
Expand All @@ -80,7 +79,7 @@ TEST_P(CarverTest, RemoveHorizontalSeam) {
cv::Mat actual;

sc::Seam seam = carver_data.horizontal_seam;
sct::DummyCarver::RemoveHorizontalSeam(seam, input, actual);
sc::Carver::RemoveHorizontalSeam(seam, input, actual);

EXPECT_TRUE(sct::equalMatrices(expected, actual))
<< sct::PrintWithLabel(expected, "expected") << "\n"
Expand All @@ -95,7 +94,7 @@ TEST_P(CarverTest, InsertVerticalSeam) {
cv::Mat actual;

sc::Seam seam = carver_data.vertical_seam;
sct::DummyCarver::InsertVerticalSeam(seam, input, actual);
sc::Carver::InsertVerticalSeam(seam, input, actual);

EXPECT_TRUE(sct::equalMatrices(expected, actual))
<< sct::PrintWithLabel(expected, "expected") << "\n"
Expand All @@ -110,7 +109,7 @@ TEST_P(CarverTest, InsertHorizontalSeam) {
cv::Mat actual;

sc::Seam seam = carver_data.horizontal_seam;
sct::DummyCarver::InsertHorizontalSeam(seam, input, actual);
sc::Carver::InsertHorizontalSeam(seam, input, actual);

EXPECT_TRUE(sct::equalMatrices(expected, actual))
<< sct::PrintWithLabel(expected, "expected") << "\n"
Expand Down
3 changes: 0 additions & 3 deletions tests/unit/coord.test.cpp

This file was deleted.

3 changes: 0 additions & 3 deletions tests/unit/seam.test.cpp

This file was deleted.