Use qdx to infer padding.

The border is unused for now.

I set padding to a specific color.
master
Fabien Freling 2014-08-06 21:49:40 +02:00
parent 43208cea90
commit 593352bc45
2 changed files with 238 additions and 95 deletions

View File

@ -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

View File

@ -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