diff --git a/Makefile b/Makefile index 10c1a11..c2bdf66 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ SRC = rotation.cpp \ HEADERS = image.h \ pnm.h OBJS = $(patsubst %.cpp,%.o,$(SRC)) -IMG = img/lena_3000.pgm +IMG = img/lena_64.pgm all: $(OBJS) $(CXX) $(CXXFLAGS) $(LFLAGS) $(OBJS) -o $(BUILD_DIR)/rotation diff --git a/rotation.cpp b/rotation.cpp index a5abdd1..7fefb59 100644 --- a/rotation.cpp +++ b/rotation.cpp @@ -161,104 +161,184 @@ bool fequal(float a, float b, float sigma) // Padding // -uint16_t* generate_padding_table(Image const& src, - Image const& rotated, - double rotation, - int q_pos) +uint16_t* generate_padding_table(Image const& rotated, + Point src_rotated_origin, + Point const& qdx, Point const& qdy, + int src_qwidth, int src_qheight) { uint16_t* padding_table = new uint16_t[rotated.height]; - // We suppose the image is square. - double const sigma = 1.0e-5; - if (fequal(rotation, 0, sigma) - || fequal(rotation, M_PI / 2, sigma) - || fequal(rotation, M_PI, sigma) - || fequal(rotation, 3 * M_PI / 2, sigma)) + if (qdx.x == 0 || qdx.y == 0) { memset(padding_table, 0, sizeof (uint16_t) * rotated.height); return padding_table; } - double padding_rotation = 0.0; - if (rotation < M_PI / 2) + for (unsigned int i = 0; i < rotated.height; ++i) { - padding_rotation = rotation; - } else if (rotation < M_PI) - { - padding_rotation = rotation - M_PI / 2; - } else if (rotation < 3 * M_PI / 2) - { - padding_rotation = rotation - M_PI; - } - else - { - padding_rotation = rotation - 3 * M_PI / 2; + int y_range = 0; + if (src_rotated_origin.y < 0) + { + y_range = ceil((-src_rotated_origin.y) / (float) qdx.y); + } + else if (src_rotated_origin.y >= src_qheight) + { + y_range = ceil((float) (src_rotated_origin.y - src_qheight + 1) / (float) (-qdx.y)); + } + if (y_range < 0) + { + cout << "Negative Y range" << endl; + abort(); + } + + int x_range = 0; + if (src_rotated_origin.x < 0) + { + x_range = ceil((-src_rotated_origin.x) / (float) qdx.x); + } + else if (src_rotated_origin.x >= src_qwidth) + { + x_range = ceil((float) (src_rotated_origin.x - src_qwidth + 1) / (float) (-qdx.x)); + } + if (x_range < 0) + { + cout << "Negative X range" << endl; + abort(); + } + + padding_table[i] = max(x_range, y_range); + + { + Point test(src_rotated_origin.x + padding_table[i] * qdx.x, + src_rotated_origin.y + padding_table[i] * qdx.y); + if (test.x < 0 || test.y < 0 + || test.x >= src_qwidth || test.y >= src_qheight) + { + cout << "Padding issue at line " << i << endl; + cout << " src: " << src_rotated_origin << endl; + cout << " test: " << test << endl; + cout << " q dim: " << src_qwidth << " x " << src_qheight << endl; + cout << " " << padding_table[i] << " x " << qdx << endl; + cout << " x diff = " << src_rotated_origin.x - src_qwidth + 1 << endl; + cout << " x coef = " << (float) (src_rotated_origin.x - src_qwidth + 1) / (float) (-qdx.x) << endl; + abort(); + } + } + + src_rotated_origin += qdy; } - // Quantized delta for padding - // TODO: we should be able to infer these values from qdx and qdy - DPoint const top_left_grid = get_mapped_point(src, Point(0, 0), padding_rotation); - Point const top_left = convert_img_coord(rotated, top_left_grid); + return padding_table; +} - DPoint const top_right_grid = get_mapped_point(src, Point(src.width - 1, 0), padding_rotation); - DPoint const top_right = convert_img_coord_precision(rotated, top_right_grid); - Point const q_top_right(top_right.x * q_pos, top_right.y * q_pos); - - DPoint const bottom_left_grid = get_mapped_point(src, Point(0, src.height), padding_rotation); - DPoint const bottom_left = convert_img_coord_precision(rotated, bottom_left_grid); - Point const q_bottom_left(bottom_left.x * q_pos, bottom_left.y * q_pos); - - int i = 0; - int const q_top_width = q_top_right.x; - int const q_top_step = q_top_width / top_left.y; - int previous_padding = 0; - for (; i <= top_left.y; ++i) +uint16_t* generate_padding_table_back_q(Image const& rotated, + Point src_rotated_origin, + Point const& qdx, + Point const& qdy, + int src_qwidth, + int src_qheight, + uint16_t const* front_padding) +{ + uint16_t* padding_table = new uint16_t[rotated.height]; + // We suppose the image is square. + if (qdx.x == 0 || qdx.y == 0) { - padding_table[i] = (q_top_width - i * q_top_step) / q_pos; - previous_padding = padding_table[i]; + memset(padding_table, 0, sizeof (uint16_t) * rotated.height); + return padding_table; } - int const remaining_height = rotated.height - 1 - i; - int const q_bottom_width = q_bottom_left.x; - int const q_bottom_step = q_bottom_width / remaining_height; - int remaining_index = 1; - for (; i < (int) rotated.height; ++i, ++remaining_index) - { - padding_table[i] = min((unsigned int) (remaining_index * q_bottom_step) / q_pos, - (unsigned int) rotated.height - 1 - padding_table[rotated.height - 1 - i]); - } + src_rotated_origin.x = (rotated.width - 1) * qdx.x; + src_rotated_origin.y = (rotated.width - 1) * qdx.y; + for (unsigned int i = 0; i < rotated.height; ++i) + { + int y_range = 0; + if (src_rotated_origin.y < 0) + { + y_range = ceil((-src_rotated_origin.y) / (float) qdx.y); + } + else if (src_rotated_origin.y >= src_qheight) + { + y_range = ceil((float) (src_rotated_origin.y - src_qheight + 1) / (float) (qdx.y)); + } + if (y_range < 0) + { + cout << "Negative back Y range at line " << i << endl; + abort(); + } + + int x_range = 0; + if (src_rotated_origin.x < 0) + { + x_range = ceil((-src_rotated_origin.x) / (float) qdx.x); + } + else if (src_rotated_origin.x >= src_qwidth) + { + x_range = ceil((float) (src_rotated_origin.x - src_qwidth + 1) / abs(qdx.x)); + } + if (x_range < 0) + { + cout << "Negative back X range at line " << i << endl; + cout << " src origin: " << src_rotated_origin << endl; + cout << " q dim: " << src_qwidth << " x " << src_qheight << endl; + abort(); + } + + padding_table[i] = max(x_range, y_range); + + { + Point test(src_rotated_origin.x - padding_table[i] * qdx.x, + src_rotated_origin.y - padding_table[i] * qdx.y); + if (test.x < 0 || test.y < 0 + || test.x >= src_qwidth || test.y >= src_qheight) + { + padding_table[i] = rotated.width - front_padding[i]; +// cout << "Back padding issue at line " << i << endl; +// cout << " src origin: " << src_rotated_origin << endl; +// cout << " test: " << test << endl; +// cout << " q dim: " << src_qwidth << " x " << src_qheight << endl; +// cout << " " << padding_table[i] << " x " << qdx << endl; +// cout << " X range " << x_range << endl; +// cout << " Y range " << y_range << endl; +// cout << " height diff = " << src_rotated_origin.y - src_qheight + 1 << endl; +// cout << " coef = " << (float) (src_rotated_origin.y - src_qheight + 1) / (float) qdx.y << endl; +// abort(); + } + } + + src_rotated_origin += qdy; + } return padding_table; } void print_padding_table(uint16_t const* padding_table, uint16_t const* border_table, - unsigned int size) + Image const& image) { cout << "Padding table:" << endl; - for (unsigned int i = 0; i < size; ++i) + for (unsigned int i = 0; i < image.height; ++i) { int left_padding = padding_table[i]; int left_border = border_table[i]; - int right_padding = padding_table[size - 1 - i]; - int right_border = border_table[size - 1 - i]; - int core_pixels = size - left_padding - right_padding - left_border - right_border; + int right_padding = padding_table[image.height - 1 - i]; + int right_border = border_table[image.height - 1 - i]; + int core_pixels = image.width - left_padding - right_padding - left_border - right_border; if (core_pixels < 0) { cout << "Too much padding + border at line " << i << endl; cout << " left padding = " << left_padding << endl; cout << " left border = " << left_border << endl; - cout << " right padding = " << right_padding << endl; cout << " right border = " << right_border << endl; + cout << " right padding = " << right_padding << endl; cout << " total = " << left_padding + left_border + right_border + right_padding << endl; - cout << " max size = " << size << endl; + cout << " width = " << image.width << endl; abort(); } - cout << " ["; + cout << " " << i << " ["; for (int j = 0; j < left_padding; ++j) cout << " "; for (int j = 0; j < left_border; ++j) @@ -280,39 +360,68 @@ void print_padding_table(uint16_t const* padding_table, // Border // -uint16_t* generate_border_table(uint16_t const* padding_table, int size) +uint16_t* generate_border_table(uint16_t const* padding_table, Image const& image) { - uint16_t* border_table = new uint16_t[size]; - border_table[0] = 0; - - for (int i = 1; i < size - 1; ++i) + uint16_t* border_table = new uint16_t[image.height]; + if (image.width - padding_table[0] - padding_table[image.height - 1] == 0) { - if (padding_table[i - 1] > padding_table[i]) + cout << "No room for top border" << endl; + border_table[0] = 0; + } + else + border_table[0] = 1; + + for (unsigned int i = 1; i < image.height - 1; ++i) + { + if (padding_table[i] == padding_table[i - 1]) { - border_table[i] = padding_table[i - 1] - padding_table[i]; - if (padding_table[i - 1] != padding_table[i]) - border_table[i] += 1; + border_table[i] = 1; } else { - border_table[i] = 1; - if (padding_table[i - 1] != padding_table[i]) - border_table[i - 1] += 1; + if (padding_table[i - 1] > padding_table[i]) + { + border_table[i] = padding_table[i - 1] - padding_table[i] + 1; + } + else + { + border_table[i - 1] = padding_table[i] - padding_table[i - 1] + 1; + border_table[i] = 1; + } } } // Check that we don't add too much border - for (int i = 1; i < size - 1; ++i) + for (unsigned int i = 1; i < image.height - 1; ++i) { if (padding_table[i] + border_table[i] - + padding_table[size - 1 - i] + border_table[size - 1 - i] - > size) + + padding_table[image.height - 1 - i] + border_table[image.height - 1 - i] + > (int) image.width) { - border_table[i] -= 1; + cout << "Too much border!" << endl; + cout << " border[" << i << "]: " << border_table[i] << endl; + cout << " border[" << image.height - 1 - i << "]: " << border_table[image.height - 1 - i] << endl; + if (border_table[i] > border_table[image.height - 1 - i]) + border_table[i] -= 1; + else + border_table[image.height - 1 - i] -= 1; } } - border_table[size - 1] = size - padding_table[0] - padding_table[size - 1]; + border_table[image.height - 1] = image.width - padding_table[0] - padding_table[image.height - 1] - border_table[0]; + if (border_table[image.height - 1] > image.width) + { + cout << "That shit cray" << endl; + cout << " width = " << image.width << endl; + cout << " left padding = " << padding_table[0] << endl; + cout << " left border = " << border_table[0] << endl; + cout << " right border = " << border_table[image.height - 1] << endl; + cout << " right padding = " << padding_table[image.height - 1] << endl; + cout << " ~ " << image.width << endl; + cout << " ~ " << image.width - padding_table[0] << endl; + cout << " ~ " << image.width - padding_table[0] - padding_table[image.height - 1] << endl; + cout << " ~ " << image.width - padding_table[0] - padding_table[image.height - 1] - border_table[0] << endl; + } return border_table; } @@ -329,7 +438,7 @@ void rotate_pixel(Image const& src, Point const& src_rotated_point, unsigned int const src_limit, pvalue_t* rotate_buffer, unsigned int rot_index, - unsigned int q_pow) + int q_pow) { // Quantize on a 8x8 grid int const q_inter_pow = 3; @@ -428,44 +537,76 @@ Image* rotate(Image const& src, double angle) unsigned int const src_limit = src.width * src.height * src.pixel_size; int const width = rotated->width; int const height = rotated->height; + int const& src_qwidth = src.width * q_pos; + int const& src_qheight = src.height * q_pos; - Point src_rotated_origin(rot_origin_in_src.x * q_pos, - rot_origin_in_src.y * q_pos); + Point src_rotated_origin(rot_origin_in_src.x * q_pos + q_pos / 2, + rot_origin_in_src.y * q_pos + q_pos / 2); // Padding - uint16_t* padding_table = generate_padding_table(src, *rotated, rotation, q_pos); - uint16_t* border_table = generate_border_table(padding_table, rotated->height); - //print_padding_table(padding_table, border_table, height, true); + uint16_t* padding_table = generate_padding_table(*rotated, src_rotated_origin, + qdx, qdy, + src_qwidth, src_qheight); + // uint16_t* back_padding_table = generate_padding_table_back_q(*rotated, src_rotated_origin, + // qdx, qdy, + // src_qwidth, src_qheight, + // padding_table); + //uint16_t* border_table = generate_border_table(padding_table, *rotated); + //print_padding_table(padding_table, border_table, *rotated); for (int y = 0; y < height; ++y) { - Point src_rotated_point = src_rotated_origin; // TODO: compact these structure to increase locality int const left_padding = padding_table[y]; - int const left_border = border_table[y]; - int const right_padding = padding_table[height - 1 - y]; - int const right_border = border_table[height - 1 - y]; + int const left_border = 0; + int const right_padding = 0; + int const right_border = padding_table[height - 1 - y]; int const core_pixels = width - left_padding - left_border - right_border - right_padding; // Left padding for (int x = 0; x < left_padding; ++x, ++buffer_index) { // Set to black value - buffer[buffer_index] = 0; - src_rotated_point += qdx; + // TODO: memset + buffer[buffer_index] = 50; } // Border for (int x = 0; x < left_border; ++x, ++buffer_index) { buffer[buffer_index] = 0; // TODO: handle border - src_rotated_point += qdx; } + Point src_rotated_point(src_rotated_origin.x + (left_padding + left_border) * qdx.x, + src_rotated_origin.y + (left_padding + left_border) * qdx.y); + // Body for (int x = 0; x < core_pixels; ++x, ++buffer_index) { - rotate_pixel(src, src_rotated_point, src_limit, buffer, buffer_index, q_pos_pow); + if (src_rotated_point.x < 0 || src_rotated_point.y < 0 + || src_rotated_point.x >= src_qwidth || src_rotated_point.y >= src_qheight) + { +// cout << "Point too low!" << endl; +// cout << " x: " << x << endl; +// cout << " src_rotated_point: " << src_rotated_point << endl; +// cout << " qdx: " << qdx << endl; +// cout << " q_pos: " << q_pos << endl; +// cout << " rotated point: (" << x + left_padding + left_border << ", " << y << ")" << endl; +// cout << " src point: (" << (src_rotated_point.x >> q_pos_pow) << ", " << (src_rotated_point.y >> q_pos_pow) << ")" << endl; +// cout << " src point: (" << (src_rotated_point.x / q_pos) << ", " << (src_rotated_point.y / q_pos) << ")" << endl; +// cout << " width: " << width << endl; +// cout << " left padding: " << left_padding << endl; +// cout << " left border: " << left_border << endl; +// cout << " core pixels: " << core_pixels << endl; +// cout << " right border: " << right_border << endl; +// cout << " right padding: " << right_padding << endl; + buffer[buffer_index] = 255; + } + else + { + rotate_pixel(src, src_rotated_point, src_limit, buffer, buffer_index, q_pos_pow); + } + src_rotated_point += qdx; } @@ -480,11 +621,13 @@ Image* rotate(Image const& src, double angle) for (int x = 0; x < right_padding; ++x, ++buffer_index) { // Set to black value - buffer[buffer_index] = 0; + // TODO: memset + buffer[buffer_index] = 100; } src_rotated_origin += qdy; } +// cout << endl; return rotated; } @@ -798,9 +941,9 @@ int main(int argc, char* argv[]) } } - double const step = 15; - bool save_output_img = false; - bool print_each_run = false; + double const step = 5; + bool save_output_img = true; + bool print_each_run = true; bool test_tile = false; // No tile