Use qdx to infer padding.
The border is unused for now. I set padding to a specific color.
This commit is contained in:
parent
43208cea90
commit
593352bc45
2
Makefile
2
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
|
||||
|
|
331
rotation.cpp
331
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
|
||||
|
|
Loading…
Reference in a new issue