From 7e152c29fc285d0576a02e2d93752b354cc88f97 Mon Sep 17 00:00:00 2001 From: Fabien Freling Date: Sun, 20 Jul 2014 16:34:45 +0200 Subject: [PATCH] Add support for PGM format. The code has been split into different source files. This breaks for now rotation for tiled images and PPM format. The focus is now on the PGM format. --- .gitignore | 2 + Makefile | 22 ++- image.cpp | 154 ++++++++++++++++ image.h | 289 +++++++++++++++++++++++++++++ pnm.cpp | 86 +++++++++ pnm.h | 16 ++ rotation.cpp | 512 +++++---------------------------------------------- 7 files changed, 612 insertions(+), 469 deletions(-) create mode 100644 image.cpp create mode 100644 image.h create mode 100644 pnm.cpp create mode 100644 pnm.h diff --git a/.gitignore b/.gitignore index 91e3764..dd09683 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ .DS_Store *.dSYM *.swp +*.o rotated*.ppm +rotated*.pnm *.png diff --git a/Makefile b/Makefile index 6b1eb5d..bf5e679 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,24 @@ CXX = clang++ CXXFLAGS = -std=c++11 -W -Wall -O3 -ffast-math -g -Werror -DEFINES = -DSIMD +LFLAGS = -flto +DEFINES = #-DSIMD BUILD_DIR = /tmp -IMG = img/lena.ppm +SRC = rotation.cpp \ + image.cpp \ + pnm.cpp +HEADERS = image.h \ + pnm.h +OBJS = $(patsubst %.cpp,%.o,$(SRC)) +IMG = img/lena_3000.pgm -all: rotation.cpp - $(CXX) $(CXXFLAGS) $(DEFINES) $< -o $(BUILD_DIR)/rotation +all: $(OBJS) + $(CXX) $(CXXFLAGS) $(DEFINES) $(LFLAGS) $(OBJS) -o $(BUILD_DIR)/rotation + +%.o: %.cpp $(HEADERS) + $(CXX) $(CXXFLAGS) $(DEFINES) $< -c -o $@ clean: - @rm -f *~ *.o .*.swp *.ppm cachegrind.out.* + @rm -f *~ *.o .*.swp *.ppm *.pgm *.pnm cachegrind.out.* run: all $(BUILD_DIR)/rotation $(IMG) @@ -17,4 +27,4 @@ debug: all lldb $(BUILD_DIR)/rotation $(IMG) cachegrind: all - valgrind --tool=cachegrind $(BUILD_DIR)/rotation $(IMG) + valgrind --tool=cachegrind --dsymutil=yes $(BUILD_DIR)/rotation $(IMG) diff --git a/image.cpp b/image.cpp new file mode 100644 index 0000000..55e9bc6 --- /dev/null +++ b/image.cpp @@ -0,0 +1,154 @@ +#include "image.h" +#include "pnm.h" + +Image::Image() +: width(0) +, height(0) +, buffer(NULL) +, pixel_size(0) +{} + +Image::~Image() +{ + delete [] buffer; +} + +Image::Image(unsigned int w, unsigned int h, pnm::Format type) +{ + this->width = w; + this->height = h; + this->type = type; + + switch (this->type) + { + case pnm::Format::PGM: + { + this->pixel_size = 1; + } + break; + + case pnm::Format::PPM: + { + this->pixel_size = 4; + } + break; + } + + buffer = new pvalue_t[width * height * pixel_size]; + memset(buffer, 0, width * height * pixel_size * sizeof (pvalue_t)); +} + +Image::Image(string const& path) +: Image() +{ + ifstream is(path); + if (!is.is_open()) + { + cerr << "Cannot open file '" << path << "'" << endl; + abort(); + } + + if (!pnm::read_header(is, this->type, this->width, this->height)) + { + cerr << "Invalid header." << endl; + abort(); + } + + switch (this->type) + { + case pnm::Format::PGM: + { + this->pixel_size = 1; + } + break; + + case pnm::Format::PPM: + { + this->pixel_size = 4; + } + break; + } + + + if (!this->read_body(is)) + { + delete buffer; + buffer = nullptr; + + cerr << "Invalid header." << endl; + abort(); + } +} + +bool Image::save(string const& path) const +{ + ofstream os(path); + if (!os.is_open()) + { + cerr << "Cannot open file '" << path << "'" << endl; + return false; + } + pnm::write_header(os, this->type, this->width, this->height); + this->write_body(os); + return true; +} + +bool Image::read_body(std::ifstream& istr) +{ + unsigned int const nb_pixels = width * height; + buffer = new pvalue_t[nb_pixels * pixel_size]; + + pvalue_t* pixel = buffer; + for (unsigned int i = 0; i < nb_pixels; ++i) + { + switch (this->type) + { + case pnm::Format::PGM: + { + pixel[0] = istr.get(); + } + break; + + case pnm::Format::PPM: + { + pixel[0] = istr.get(); + pixel[1] = istr.get(); + pixel[2] = istr.get(); + } + break; + } + + pixel += pixel_size; + } + + return true; +} + +bool Image::write_body(std::ofstream& ostr) const +{ + unsigned int const nb_pixels = width * height; + pvalue_t* pixel = buffer; + for (unsigned int i = 0; i < nb_pixels; ++i) + { + switch (this->type) + { + case pnm::Format::PGM: + { + ostr << (char) pixel[0]; + } + break; + + case pnm::Format::PPM: + { + ostr << (char) pixel[0]; + ostr << (char) pixel[1]; + ostr << (char) pixel[2]; + } + break; + } + + pixel += pixel_size; + } + + return true; +} diff --git a/image.h b/image.h new file mode 100644 index 0000000..09d6d90 --- /dev/null +++ b/image.h @@ -0,0 +1,289 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pnm.h" + +using namespace std; + + +// +// +// Point +// + +template +struct TPoint { + T x; + T y; + + TPoint(T a, T b) + : x(a) + , y(b) + {} +}; + +typedef TPoint Point; +typedef TPoint DPoint; // absolute point, can be negative +template + +std::basic_ostream& operator << (std::basic_ostream& o, TPoint const& p) +{ + o << "(" << p.x << ", " << p.y << ")"; + return o; +} + + + +// +// +// Pixel +// + +typedef uint16_t pvalue_t; // pixel value type + + + +// +// +// Image +// + +struct Image { + unsigned int width; + unsigned int height; + pvalue_t* buffer; + pnm::Format type; + size_t pixel_size; + + Image(); + Image(unsigned int w, unsigned int h, pnm::Format type); + Image(string const& path); + virtual ~Image(); + + bool save(string const& path) const; + + protected: + virtual bool read_body(std::ifstream& istr); + virtual bool write_body(std::ofstream& ostr) const; +}; + +template +struct TiledImage : public Image { + pvalue_t* tiles; + unsigned int static const tile_w = W; + unsigned int static const tile_h = H; + + // two lines overlap, bottom + right + unsigned int static const tile_size = (W + 1) * (H + 1); + unsigned int nb_col_tile; + unsigned int nb_row_tile; + + TiledImage() + : Image() + , tiles(NULL) + , nb_col_tile(0) + , nb_row_tile(0) + {} + + ~TiledImage() + { + delete [] tiles; + } + + TiledImage(unsigned int w, unsigned int h) + { + allocate_memory(w, h); + } + + TiledImage(string const& path) + : TiledImage() + { + ifstream is(path); + if (!is.is_open()) + { + cerr << "Cannot open file '" << path << "'" << endl; + abort(); + } + + if (!pnm::read_header(is, this->type, this->width, this->height)) + { + cerr << "Invalid header." << endl; + abort(); + } + + if (!this->read_body(is)) + { + // TODO: delete tiles + cerr << "Invalid header." << endl; + abort(); + } + } + + pvalue_t const* + get_tile(unsigned int index) const + { + if (index >= nb_col_tile * nb_row_tile) + return nullptr; + + return tiles + index * tile_size * pixel_size; + } + + pvalue_t* + get_tile(unsigned int index) + { + if (index >= nb_col_tile * nb_row_tile) + return nullptr; + + return tiles + index * tile_size * pixel_size; + } + + pvalue_t* + access_pixel(unsigned int x, unsigned int y) + { + if (x >= width || y >= height) + return nullptr; + + unsigned int const tile_width = (tile_w + 1) * pixel_size; + + unsigned int const tile_index = (y / tile_h) * nb_col_tile + (x / tile_w); + pvalue_t* tile = this->get_tile(tile_index); + unsigned int const tile_j = y % tile_h; + unsigned int const tile_i = x % tile_w; + return tile + tile_j * tile_width + (tile_i * pixel_size); + } + + pvalue_t const* + access_pixel(unsigned int x, unsigned int y) const + { + if (x >= width || y >= height) + return nullptr; + + unsigned int const tile_width = (tile_w + 1) * pixel_size; + + unsigned int const tile_index = (y / tile_h) * nb_col_tile + (x / tile_w); + const pvalue_t* tile = this->get_tile(tile_index); + unsigned int const tile_j = y % tile_h; + unsigned int const tile_i = x % tile_w; + return tile + tile_j * tile_width + (tile_i * pixel_size); + } + + void + print_tile(unsigned int index) const + { + cout << "Tile[" << index << "]" << endl; + pvalue_t const* tile = this->get_tile(index); + unsigned int const tile_width = (tile_w + 1) * pixel_size; + for (unsigned int j = 0; j < tile_h + 1; ++j) + { + for (unsigned int i = 0; i < tile_w + 1; ++i) + { + if (i != 0) + cout << ", "; + pvalue_t const* p = tile + j * tile_width + i * pixel_size; + cout << (int) *p << " " << (int) *(p + 1) << " " << (int) *(p + 2); + + } + cout << endl; + } + cout << endl; + } + + void fill_overlap() + { + unsigned int const tile_width = (W + 1) * pixel_size; + + for (int j = nb_row_tile - 1; j >= 0; --j) + for (unsigned int i = 0; i < nb_col_tile; ++i) + { + // copy last line overlap + if (j != (int) nb_row_tile - 1) + { + pvalue_t const* tile_src = this->access_pixel(i * W, (j + 1) * H); + pvalue_t* tile_dst = this->access_pixel(i * W, j * H); + tile_dst += H * tile_width; + memcpy(tile_dst, tile_src, tile_width * sizeof (pvalue_t)); + } + + // copy last col overlap + if (i != nb_col_tile - 1) + { + pvalue_t* tile_src = this->get_tile(i + 1 + j * nb_col_tile); + pvalue_t* tile_dst = this->get_tile(i + j * nb_col_tile); + tile_dst += W * pixel_size; + for (unsigned int y = 0; y < H; ++y) + { + memcpy(tile_dst, tile_src, pixel_size * sizeof (pvalue_t)); + tile_src += tile_width; + tile_dst += tile_width; + } + } + } + } + + + protected: + void allocate_memory(unsigned int w, unsigned int h) + { + width = w; + height = h; + + nb_col_tile = width / tile_w; + if (width % tile_w != 0) + ++nb_col_tile; + + nb_row_tile = height / tile_h; + if (height % tile_h != 0) + ++nb_row_tile; + + unsigned int const nb_tiles = nb_col_tile * nb_row_tile; + tiles = new pvalue_t[nb_tiles * tile_size * pixel_size]; + memset(tiles, 0, nb_tiles * tile_size * pixel_size * sizeof (pvalue_t)); + } + + virtual bool read_body(std::ifstream& istr) override + { + this->allocate_memory(width, height); + + // Pixel loading + for (unsigned int j = 0; j < height; ++j) + for (unsigned int i = 0; i < width; ++i) + { + pvalue_t* tile = this->access_pixel(i, j); + tile[0] = istr.get(); + tile[1] = istr.get(); + tile[2] = istr.get(); + + tile += pixel_size; + } + + this->fill_overlap(); + + return true; + } + + virtual bool write_body(std::ofstream& ostr) const override + { + for (unsigned int j = 0; j < height; ++j) + for (unsigned int i = 0; i < width; ++i) + { + pvalue_t const* tile = this->access_pixel(i, j); + ostr << (char) tile[0]; + ostr << (char) tile[1]; + ostr << (char) tile[2]; + + tile += pixel_size; + } + + return true; + } + +}; diff --git a/pnm.cpp b/pnm.cpp new file mode 100644 index 0000000..a2c5d42 --- /dev/null +++ b/pnm.cpp @@ -0,0 +1,86 @@ +#include +#include +#include + +#include "pnm.h" + +using namespace std; + +namespace pnm +{ + + bool read_header(std::ifstream& istr, Format& type, unsigned int& width, unsigned int& height) + { + // check magic + if (istr.get() != 'P' ) + { + return false; + } + + char c_type = static_cast(istr.get()); + if (c_type == '6') + { + type = Format::PPM; + } + else if (c_type == '5') + { + type = Format::PGM; + } + else + { + cerr << "Invalid PNM format." << endl; + return false; + } + + if (istr.get() != '\n') + { + return false; + } + + // skip comments + while (istr.peek() == '#') + { + std::string line; + std::getline(istr, line); + } + + // get size + istr >> width >> height; + if (width == 0 || height == 0) + { + return false; + } + + // get maxvalue + if (istr.get() != '\n') + { + return false; + } + + int max_value = -1; + istr >> max_value; + if (max_value > 255) + { + return false; + } + + if (istr.get() != '\n') + { + return false; + } + + return true; + } + + bool write_header(std::ofstream& ostr, Format type, unsigned int width, unsigned int height) + { + if (type == Format::PGM) + ostr << "P5" << endl; + if (type == Format::PPM) + ostr << "P6" << endl; + ostr << width << " " << height << endl; + ostr << "255" << endl; + return true; + } + +} // end of namespace pnm diff --git a/pnm.h b/pnm.h new file mode 100644 index 0000000..af90ea4 --- /dev/null +++ b/pnm.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace pnm +{ + + enum class Format { + PGM, + PPM + }; + + bool read_header(std::ifstream& istr, Format& type, unsigned int& width, unsigned int& height); + bool write_header(std::ofstream& ostr, Format type, unsigned int width, unsigned int height); + +} diff --git a/rotation.cpp b/rotation.cpp index 1acccde..57f2830 100644 --- a/rotation.cpp +++ b/rotation.cpp @@ -12,428 +12,10 @@ #include #include +#include "image.h" + using namespace std; -// -// -// Point -// - -template -struct TPoint { - T x; - T y; - - TPoint(T a, T b) - : x(a) - , y(b) - {} -}; - -typedef TPoint Point; -typedef TPoint DPoint; // absolute point, can be negative -template - -std::basic_ostream& operator << (std::basic_ostream& o, TPoint const& p) -{ - o << "(" << p.x << ", " << p.y << ")"; - return o; -} - - - -// -// -// Pixel -// - -typedef uint16_t pvalue_t; // pixel value type -#define PIXEL_SIZE 4 - - - -// -// -// Image -// - -struct Image { - unsigned int width; - unsigned int height; - pvalue_t* buffer; - - Image() - : width(0) - , height(0) - , buffer(NULL) - {} - - virtual ~Image() - { - delete [] buffer; - } - - Image(unsigned int w, unsigned int h) - { - this->width = w; - this->height = h; - buffer = new pvalue_t[width * height * PIXEL_SIZE]; - memset(buffer, 0, width * height * PIXEL_SIZE * sizeof (pvalue_t)); - } - - Image(string const& path) - : Image() - { - ifstream is(path); - if (!is.is_open()) - { - cerr << "Cannot open file '" << path << "'" << endl; - abort(); - } - - if (!this->read_header(is)) - { - cerr << "Invalid header." << endl; - abort(); - } - - if (!this->read_body(is)) - { - delete buffer; - buffer = nullptr; - - cerr << "Invalid header." << endl; - abort(); - } - } - - bool save(string const& path) const - { - ofstream os(path); - if (!os.is_open()) - { - cerr << "Cannot open file '" << path << "'" << endl; - return false; - } - this->write_header(os); - this->write_body(os); - return true; - } - - - protected: - bool read_header(std::ifstream& istr) - { - // check magic - if (istr.get() != 'P' ) - { - return false; - } - - char type = static_cast(istr.get()); - if (type != '6') - { - return false; - } - - if (istr.get() != '\n') - { - return false; - } - - // skip comments - while (istr.peek() == '#') - { - std::string line; - std::getline(istr, line); - } - - // get size - istr >> width >> height; - if (width == 0 || height == 0) - { - return false; - } - - // get maxvalue - if (istr.get() != '\n') - { - return false; - } - - int max_value = -1; - istr >> max_value; - if (max_value > 255) - { - return false; - } - - if (istr.get() != '\n') - { - return false; - } - - // cout << "width: " << width << endl; - // cout << "height: " << height << endl; - - return true; - } - - bool write_header(std::ofstream& ostr) const - { - ostr << "P6" << endl; - ostr << width << " " << height << endl; - ostr << "255" << endl; - return true; - } - - virtual bool read_body(std::ifstream& istr) - { - unsigned int const nb_pixels = width * height; - buffer = new pvalue_t[nb_pixels * PIXEL_SIZE]; - - pvalue_t* pixel = buffer; - for (unsigned int i = 0; i < nb_pixels; ++i) - { - pixel[0] = istr.get(); - pixel[1] = istr.get(); - pixel[2] = istr.get(); - - pixel += PIXEL_SIZE; - } - - return true; - } - - virtual bool write_body(std::ofstream& ostr) const - { - unsigned int const nb_pixels = width * height; - pvalue_t* pixel = buffer; - for (unsigned int i = 0; i < nb_pixels; ++i) - { - ostr << (char) pixel[0]; - ostr << (char) pixel[1]; - ostr << (char) pixel[2]; - - pixel += PIXEL_SIZE; - } - - return true; - } -}; - -template -struct TiledImage : public Image { - pvalue_t* tiles; - unsigned int static const tile_w = W; - unsigned int static const tile_h = H; - - // two lines overlap, bottom + right - unsigned int static const tile_size = (W + 1) * (H + 1); - unsigned int nb_col_tile; - unsigned int nb_row_tile; - - TiledImage() - : Image() - , tiles(NULL) - , nb_col_tile(0) - , nb_row_tile(0) - {} - - ~TiledImage() - { - delete [] tiles; - } - - TiledImage(unsigned int w, unsigned int h) - { - allocate_memory(w, h); - } - - TiledImage(string const& path) - : TiledImage() - { - ifstream is(path); - if (!is.is_open()) - { - cerr << "Cannot open file '" << path << "'" << endl; - abort(); - } - - if (!this->read_header(is)) - { - cerr << "Invalid header." << endl; - abort(); - } - - if (!this->read_body(is)) - { - // TODO: delete tiles - cerr << "Invalid header." << endl; - abort(); - } - } - - pvalue_t const* - get_tile(unsigned int index) const - { - if (index >= nb_col_tile * nb_row_tile) - return nullptr; - - return tiles + index * tile_size * PIXEL_SIZE; - } - - pvalue_t* - get_tile(unsigned int index) - { - if (index >= nb_col_tile * nb_row_tile) - return nullptr; - - return tiles + index * tile_size * PIXEL_SIZE; - } - - pvalue_t* - access_pixel(unsigned int x, unsigned int y) - { - if (x >= width || y >= height) - return nullptr; - - unsigned int const tile_width = (tile_w + 1) * PIXEL_SIZE; - - unsigned int const tile_index = (y / tile_h) * nb_col_tile + (x / tile_w); - pvalue_t* tile = this->get_tile(tile_index); - unsigned int const tile_j = y % tile_h; - unsigned int const tile_i = x % tile_w; - return tile + tile_j * tile_width + (tile_i * PIXEL_SIZE); - } - - pvalue_t const* - access_pixel(unsigned int x, unsigned int y) const - { - if (x >= width || y >= height) - return nullptr; - - unsigned int const tile_width = (tile_w + 1) * PIXEL_SIZE; - - unsigned int const tile_index = (y / tile_h) * nb_col_tile + (x / tile_w); - const pvalue_t* tile = this->get_tile(tile_index); - unsigned int const tile_j = y % tile_h; - unsigned int const tile_i = x % tile_w; - return tile + tile_j * tile_width + (tile_i * PIXEL_SIZE); - } - - void - print_tile(unsigned int index) const - { - cout << "Tile[" << index << "]" << endl; - pvalue_t const* tile = this->get_tile(index); - unsigned int const tile_width = (tile_w + 1) * PIXEL_SIZE; - for (unsigned int j = 0; j < tile_h + 1; ++j) - { - for (unsigned int i = 0; i < tile_w + 1; ++i) - { - if (i != 0) - cout << ", "; - pvalue_t const* p = tile + j * tile_width + i * PIXEL_SIZE; - cout << (int) *p << " " << (int) *(p + 1) << " " << (int) *(p + 2); - - } - cout << endl; - } - cout << endl; - } - - void fill_overlap() - { - unsigned int const tile_width = (W + 1) * PIXEL_SIZE; - - for (int j = nb_row_tile - 1; j >= 0; --j) - for (unsigned int i = 0; i < nb_col_tile; ++i) - { - // copy last line overlap - if (j != (int) nb_row_tile - 1) - { - pvalue_t const* tile_src = this->access_pixel(i * W, (j + 1) * H); - pvalue_t* tile_dst = this->access_pixel(i * W, j * H); - tile_dst += H * tile_width; - memcpy(tile_dst, tile_src, tile_width * sizeof (pvalue_t)); - } - - // copy last col overlap - if (i != nb_col_tile - 1) - { - pvalue_t* tile_src = this->get_tile(i + 1 + j * nb_col_tile); - pvalue_t* tile_dst = this->get_tile(i + j * nb_col_tile); - tile_dst += W * PIXEL_SIZE; - for (unsigned int y = 0; y < H; ++y) - { - memcpy(tile_dst, tile_src, PIXEL_SIZE * sizeof (pvalue_t)); - tile_src += tile_width; - tile_dst += tile_width; - } - } - } - } - - - protected: - void allocate_memory(unsigned int w, unsigned int h) - { - width = w; - height = h; - - nb_col_tile = width / tile_w; - if (width % tile_w != 0) - ++nb_col_tile; - - nb_row_tile = height / tile_h; - if (height % tile_h != 0) - ++nb_row_tile; - - unsigned int const nb_tiles = nb_col_tile * nb_row_tile; - tiles = new pvalue_t[nb_tiles * tile_size * PIXEL_SIZE]; - memset(tiles, 0, nb_tiles * tile_size * PIXEL_SIZE * sizeof (pvalue_t)); - } - - virtual bool read_body(std::ifstream& istr) override - { - this->allocate_memory(width, height); - - // Pixel loading - for (unsigned int j = 0; j < height; ++j) - for (unsigned int i = 0; i < width; ++i) - { - pvalue_t* tile = this->access_pixel(i, j); - tile[0] = istr.get(); - tile[1] = istr.get(); - tile[2] = istr.get(); - - tile += PIXEL_SIZE; - } - - this->fill_overlap(); - - return true; - } - - virtual bool write_body(std::ofstream& ostr) const override - { - for (unsigned int j = 0; j < height; ++j) - for (unsigned int i = 0; i < width; ++i) - { - pvalue_t const* tile = this->access_pixel(i, j); - ostr << (char) tile[0]; - ostr << (char) tile[1]; - ostr << (char) tile[2]; - - tile += PIXEL_SIZE; - } - - return true; - } - -}; - // @@ -589,12 +171,12 @@ void rotate_pixel(Image const& src, int const src_x = src_rotated_point.x >> 3; int const src_y = src_rotated_point.y >> 3; - unsigned int src_index = (src_y * src.width + src_x) * PIXEL_SIZE; + unsigned int src_index = (src_y * src.width + src_x) * src.pixel_size; // Bilinear interpolation unsigned int src_index_1 = src_index; - unsigned int src_index_3 = src_index_1 + PIXEL_SIZE * src.width; - unsigned int src_index_4 = src_index_3 + PIXEL_SIZE; + unsigned int src_index_3 = src_index_1 + src.pixel_size * src.width; + unsigned int src_index_4 = src_index_3 + src.pixel_size; // Out-of-bounds check if (src_index_4 >= src_limit) @@ -607,14 +189,14 @@ void rotate_pixel(Image const& src, #ifndef SIMD - unsigned int src_index_2 = src_index_1 + PIXEL_SIZE; + unsigned int src_index_2 = src_index_1 + src.pixel_size; rotate_buffer[rot_index] = ((src.buffer[src_index_1] * inv_x + src.buffer[src_index_2] * x_delta) * inv_y + (src.buffer[src_index_3] * inv_x + src.buffer[src_index_4] * x_delta) * y_delta) >> 6; - rotate_buffer[rot_index + 1] = ((src.buffer[src_index_1 + 1] * inv_x + src.buffer[src_index_2 + 1] * x_delta) * inv_y - + (src.buffer[src_index_3 + 1] * inv_x + src.buffer[src_index_4 + 1] * x_delta) * y_delta) >> 6; - rotate_buffer[rot_index + 2] = ((src.buffer[src_index_1 + 2] * inv_x + src.buffer[src_index_2 + 2] * x_delta) * inv_y - + (src.buffer[src_index_3 + 2] * inv_x + src.buffer[src_index_4 + 2] * x_delta) * y_delta) >> 6; + // rotate_buffer[rot_index + 1] = ((src.buffer[src_index_1 + 1] * inv_x + src.buffer[src_index_2 + 1] * x_delta) * inv_y + // + (src.buffer[src_index_3 + 1] * inv_x + src.buffer[src_index_4 + 1] * x_delta) * y_delta) >> 6; + // rotate_buffer[rot_index + 2] = ((src.buffer[src_index_1 + 2] * inv_x + src.buffer[src_index_2 + 2] * x_delta) * inv_y + // + (src.buffer[src_index_3 + 2] * inv_x + src.buffer[src_index_4 + 2] * x_delta) * y_delta) >> 6; #else @@ -635,8 +217,8 @@ void rotate_pixel(Image const& src, top = _mm_srli_epi16(top, 6); rotate_buffer[rot_index] = _mm_extract_epi16(top, 0) + _mm_extract_epi16(top, 4); - rotate_buffer[rot_index + 1] = _mm_extract_epi16(top, 1) + _mm_extract_epi16(top, 5); - rotate_buffer[rot_index + 2] = _mm_extract_epi16(top, 2) + _mm_extract_epi16(top, 6); + // rotate_buffer[rot_index + 1] = _mm_extract_epi16(top, 1) + _mm_extract_epi16(top, 5); + // rotate_buffer[rot_index + 2] = _mm_extract_epi16(top, 2) + _mm_extract_epi16(top, 6); #endif // ! SIMD @@ -648,7 +230,7 @@ Image* rotate(Image const& src, double angle) unsigned int w = 0; unsigned int h = 0; compute_output_size(src, rotation, w, h); - Image* rotated = new Image(w, h); + Image* rotated = new Image(w, h, src.type); // corner points in rotated image // TODO: add one ligne for smooth border @@ -672,7 +254,7 @@ Image* rotate(Image const& src, double angle) round_if_very_small(src_delta_y.x); round_if_very_small(src_delta_y.y); - unsigned int const src_limit = src.width * src.height * PIXEL_SIZE; + unsigned int const src_limit = src.width * src.height * src.pixel_size; DPoint const rot_origin_in_src_grid = get_mapped_point(*rotated, Point(0, 0), -rotation); DPoint const rot_origin_in_src = convert_img_coord_precision(src, rot_origin_in_src_grid); @@ -702,7 +284,7 @@ Image* rotate(Image const& src, double angle) buffer, buffer_index); } - buffer_index += PIXEL_SIZE; + buffer_index += rotated->pixel_size; } } @@ -725,7 +307,7 @@ void rotate_pixel(TiledImage const& src, int const src_y = src_rotated_point.y >> 3; pvalue_t const* src_index_1 = src.access_pixel(src_x, src_y); - pvalue_t const* src_index_3 = src_index_1 + (W + 1) * PIXEL_SIZE; + pvalue_t const* src_index_3 = src_index_1 + (W + 1) * src.pixel_size; unsigned int x_delta = src_rotated_point.x & 0x07;; unsigned int y_delta = src_rotated_point.y & 0x07; @@ -734,8 +316,8 @@ void rotate_pixel(TiledImage const& src, #ifndef SIMD - pvalue_t const* src_index_2 = src_index_1 + PIXEL_SIZE; - pvalue_t const* src_index_4 = src_index_3 + PIXEL_SIZE; + pvalue_t const* src_index_2 = src_index_1 + src.pixel_size; + pvalue_t const* src_index_4 = src_index_3 + src.pixel_size; rot_tile[0] = ((src_index_1[0] * inv_x + src_index_2[0] * x_delta) * inv_y + (src_index_3[0] * inv_x + src_index_4[0] * x_delta) * y_delta) >> 6; @@ -824,11 +406,11 @@ rotate(TiledImage const& src, double angle) rotate_pixel(src, src_runner, runner); } - runner += PIXEL_SIZE; + runner += rotated->pixel_size; } // Jump overlapping pixel - runner += PIXEL_SIZE; + runner += rotated->pixel_size; } } } @@ -847,7 +429,7 @@ rotate(TiledImage const& src, double angle) bool check_points() { - Image five(5, 5); + Image five(5, 5, pnm::Format::PGM); Point origin(0, 0); DPoint d1 = convert_grid_coord(five, origin); assert(d1.x == -2); @@ -858,7 +440,7 @@ bool check_points() bool check_trigo() { - Image square(500, 500); + Image square(500, 500, pnm::Format::PGM); double const ratio = compute_ratio(square); double const sigma = 1.0e-2; if (!fequal(ratio, 1 / 707.106, sigma)) @@ -903,7 +485,7 @@ bool check_trigo() } - Image rotated(w, h); + Image rotated(w, h, pnm::Format::PGM); DPoint const a_p45 = convert_abs_coord(angle + rotation, ratio); Point const p45 = convert_img_coord(rotated, a_p45); @@ -953,9 +535,9 @@ bool check_90(string const& path) { for (unsigned int x = 0; x < rotated->width; ++x) { - unsigned rot_index = (y * rotated->width + x) * 3; - unsigned src_index = (x * src.width + (src.width - 1 - y)) * 3; - if (memcmp(&rotated->buffer[rot_index], &src.buffer[src_index], 3 * sizeof (uint8_t)) != 0) + unsigned rot_index = (y * rotated->width + x) * rotated->pixel_size; + unsigned src_index = (x * src.width + (src.width - 1 - y)) * src.pixel_size; + if (memcmp(&rotated->buffer[rot_index], &src.buffer[src_index], src.pixel_size * sizeof (pvalue_t)) != 0) { Point r(x, y); Point s((src.width - 1 - y), x); @@ -988,7 +570,7 @@ string get_save_path(string const& base, unsigned int i) filename << "0"; if (i < 10) filename << "0"; - filename << i << ".ppm"; + filename << i << ".pnm"; return filename.str(); } @@ -1021,6 +603,7 @@ int main(int argc, char* argv[]) double const step = 15; bool save_output_img = false; bool print_each_run = false; + bool test_tile = false; // No tile Image img(argv[1]); @@ -1048,29 +631,32 @@ int main(int argc, char* argv[]) cout << " average: " << average / i << "ms" << endl << endl; // Tile - TiledImage<32, 32> tiled_img(argv[1]); - average = 0.0; - i = 0; - cout << "Tiled image" << endl; - for (double rotation = 0; rotation < 360; rotation += step) + if (test_tile) { - auto const before = chrono::high_resolution_clock::now(); - auto const rotated = rotate(tiled_img, rotation); - auto const after = chrono::high_resolution_clock::now(); - auto const duration_ms = std::chrono::duration_cast(after - before); - average += duration_ms.count(); + TiledImage<32, 32> tiled_img(argv[1]); + average = 0.0; + i = 0; + cout << "Tiled image" << endl; + for (double rotation = 0; rotation < 360; rotation += step) + { + auto const before = chrono::high_resolution_clock::now(); + auto const rotated = rotate(tiled_img, rotation); + auto const after = chrono::high_resolution_clock::now(); + auto const duration_ms = std::chrono::duration_cast(after - before); + average += duration_ms.count(); - if (print_each_run) - cout << "rotate tiled(" << rotation << "): " << duration_ms.count() << " ms" << endl; + if (print_each_run) + cout << "rotate tiled(" << rotation << "): " << duration_ms.count() << " ms" << endl; - if (save_output_img) - rotated->save(get_save_path("rotated_tiled", rotation)); + if (save_output_img) + rotated->save(get_save_path("rotated_tiled", rotation)); - delete rotated; - ++i; + delete rotated; + ++i; + } + cout << "---------" << endl; + cout << " average: " << average / i << "ms" << endl; } - cout << "---------" << endl; - cout << " average: " << average / i << "ms" << endl; return 0; }