Content-Aware-Image-Resizer / tests / processing_public_tests.cpp
processing_public_tests.cpp
Raw

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cassert>
#include <cstring>
#include "Image.h"
#include "processing.h"
#include "Matrix_test_helpers.h"
#include "Image_test_helpers.h"

using namespace std;

void test_all(string prefix, int sizes[], int num_sizes);
void test_rotate(const Image *img, string prefix);
void test_energy(const Matrix *energy_mat, string prefix);
void test_cost(const Matrix *cost_mat, string prefix);
void test_find_seam(const int seam[], int n, string prefix);
void test_remove_seam(const Image* img, const int seam[],
                             string prefix);
void test_seam_carve(const Image *img, string prefix,
                            int new_width, int new_height);

static void load_matrix(Matrix* mat, string filename);
static void write_matrix(const Matrix* mat, string filename);
static void load_image(Image* img, string filename);
static void write_image(const Image* img, string filename);
static void load_seam(int seam[], string filename);
static void write_seam(const int seam[], int len, string filename);

const string OUT_PPM_EXT = ".out.ppm";
const string OUT_TXT_EXT = ".out.txt";

int main(int argc, char *argv[]){
  if (argc > 2 ||
      (argc == 2&&
       strcmp(argv[1], "dog") &&
       strcmp(argv[1], "crabster") &&
       strcmp(argv[1], "horses"))) {
    cout << "Usage: " << argv[0] << " [dog|crabster|horses]" << endl;
    return 1;
  }

  string which_test = argc == 2 ? argv[1] : "all";

  if (which_test == "all" || which_test == "dog") {
    int dog_sizes[] = {4, 5};
    test_all("dog", dog_sizes, 1);
  }
  if (which_test == "all" || which_test == "crabster") {
    int crabster_sizes[] = {50, 45, 70, 35};
    test_all("crabster", crabster_sizes, 2);
  }
  if (which_test == "all" || which_test == "horses") {
    int horses_sizes[] = {300, 382, 400, 250};
    test_all("horses", horses_sizes, 2);
  }
}

void test_all(string prefix, int sizes[], int num_sizes){
  Image* img = new Image;
  load_image(img, prefix + ".ppm");

  // Test rotate
  test_rotate(img, prefix);

  // Test energy
  Matrix* energy = new Matrix;
  compute_energy_matrix(img, energy);
  test_energy(energy, prefix);

  // Test cost
  Matrix*  cost = new Matrix;
  compute_vertical_cost_matrix(energy, cost);
  test_cost(cost, prefix);

  // Test find seam
  int seam[MAX_MATRIX_HEIGHT];
  find_minimal_vertical_seam(cost, seam);
  test_find_seam(seam, Matrix_height(cost), prefix);

  // Test remove seam
  test_remove_seam(img, seam, prefix);

  // Test full seam carving algorithm on various sizes
  for(int i = 0; i < num_sizes; ++i){
    test_seam_carve(img, prefix, sizes[2*i], sizes[2*i + 1]);
  }

  cout << prefix << " tests PASS" << endl << endl;

  delete cost;
  delete energy;
  delete img;
}

void test_rotate(const Image *img, string prefix){
  Image* rotated_img = new Image;
  Image* rotated_img_correct = new Image;

  // Test left rotation
  cout << "Testing " << prefix << " rotate left..." << flush;
  *rotated_img = *img;
  rotate_left(rotated_img);
  write_image(rotated_img, prefix + "_left" + OUT_PPM_EXT);

  load_image(rotated_img_correct, prefix + "_left.correct.ppm");
  assert(Image_equal(rotated_img, rotated_img_correct));
  cout << "PASS" << endl;

  // Test right rotation
  cout << "Testing " << prefix << " rotate right...";
  *rotated_img = *img;
  rotate_right(rotated_img);
  write_image(rotated_img, prefix + "_right" + OUT_PPM_EXT);

  load_image(rotated_img_correct, prefix + "_right.correct.ppm");
  assert(Image_equal(rotated_img, rotated_img_correct));
  cout << "PASS" << endl;

  delete rotated_img_correct;
  delete rotated_img;
}

void test_energy(const Matrix *energy_mat, string prefix){
  cout << "Testing " << prefix << " energy..." << flush;

  write_matrix(energy_mat, prefix + "_energy" + OUT_TXT_EXT);

  Matrix* energy_mat_correct = new Matrix;
  load_matrix(energy_mat_correct, prefix + "_energy_correct.txt");

  assert(Matrix_equal(energy_mat, energy_mat_correct));
  cout << "PASS" << endl;

  delete energy_mat_correct;
}


void test_cost(const Matrix *cost_mat, string prefix){
  cout << "Testing " << prefix << " cost..." << flush;

  write_matrix(cost_mat, prefix + "_cost" + OUT_TXT_EXT);

  Matrix* cost_mat_correct = new Matrix;
  load_matrix(cost_mat_correct, prefix + "_cost_correct.txt");

  assert(Matrix_equal(cost_mat, cost_mat_correct));
  cout << "PASS" << endl;

  delete cost_mat_correct;
}

void test_find_seam(const int seam[], int n, string prefix){
  cout << "Testing " << prefix << " find seam..." << flush;
  write_seam(seam, n, prefix + "_seam" + OUT_TXT_EXT);

  int seam_correct[MAX_MATRIX_HEIGHT];
  load_seam(seam_correct, prefix + "_seam_correct.txt");

  assert(array_equal(seam, seam_correct, n));
  cout << "PASS" << endl;
}

void test_remove_seam(const Image* img, const int seam[],
                             string prefix){
  cout << "Testing " << prefix << " remove seam..." << flush;

  Image* removed_img = new Image(*img);
  remove_vertical_seam(removed_img, seam);
  write_image(removed_img, prefix + "_removed" + OUT_PPM_EXT);

  Image* removed_img_correct = new Image;
  load_image(removed_img_correct, prefix + "_removed.correct.ppm");

  assert(Image_equal(removed_img, removed_img_correct));
  cout << "PASS" << endl;

  delete removed_img_correct;
  delete removed_img;
}

void test_seam_carve(const Image *img, string prefix,
                            int new_width, int new_height){
  cout << "Testing " << prefix << " seam carve ";
  cout << new_width << "x" << new_height << "..." << flush;
  Image* carved_img = new Image(*img);
  seam_carve(carved_img, new_width, new_height);
  write_image(carved_img,
    prefix + "_" + to_string(new_width) +
    "x" + to_string(new_height) + OUT_PPM_EXT);

  Image* carved_img_correct = new Image;
  load_image(carved_img_correct,
    prefix + "_" + to_string(new_width) +
    "x" + to_string(new_height) + ".correct.ppm");

  assert(Image_equal(carved_img, carved_img_correct));
  cout << "PASS" << endl;

  delete carved_img_correct;
  delete carved_img;
}

static void load_matrix(Matrix* mat, string filename){
  ifstream fin;
  fin.open(filename.c_str());

  if (!fin.is_open()){
    cout << "Unable to open " << filename << endl;
    exit(EXIT_FAILURE);
  }

  int width, height;
  fin >> width >> height;
  Matrix_init(mat, width, height);

  for (int r = 0; r < height; ++r) {
    for (int c = 0; c < width; ++c) {
      fin >> *Matrix_at(mat, r, c);
    }
  }
}

static void write_matrix(const Matrix* mat, string filename){
  ofstream fout(filename.c_str());
  Matrix_print(mat, fout);
}

static void load_image(Image* img, string filename){
  ifstream fin;
  fin.open(filename.c_str());

  if (!fin.is_open()){
    cout << "Unable to open " << filename << endl;
    exit(EXIT_FAILURE);
  }

  Image_init(img, fin);
}

static void write_image(const Image* img, string filename){
  ofstream fout(filename.c_str());
  Image_print(img, fout);
}

static void load_seam(int seam[], string filename){
  ifstream fin;
  fin.open(filename.c_str());

  if (!fin.is_open()){
    cout << "Unable to open " << filename << endl;
    exit(EXIT_FAILURE);
  }

  for(int i = 0, column; fin >> column; ++i){
    seam[i] = column;
  }
}

static void write_seam(const int seam[], int len, string filename){
  ofstream fout(filename.c_str());
  for(int i = 0; i < len; ++i){
    fout << seam[i] << endl;
  }
}