Use qdx to infer padding.

The border is unused for now.

I set padding to a specific color.
This commit is contained in:
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 \ HEADERS = image.h \
pnm.h pnm.h
OBJS = $(patsubst %.cpp,%.o,$(SRC)) OBJS = $(patsubst %.cpp,%.o,$(SRC))
IMG = img/lena_3000.pgm IMG = img/lena_64.pgm
all: $(OBJS) all: $(OBJS)
$(CXX) $(CXXFLAGS) $(LFLAGS) $(OBJS) -o $(BUILD_DIR)/rotation $(CXX) $(CXXFLAGS) $(LFLAGS) $(OBJS) -o $(BUILD_DIR)/rotation

View file

@ -161,104 +161,184 @@ bool fequal(float a, float b, float sigma)
// Padding // Padding
// //
uint16_t* generate_padding_table(Image const& src, uint16_t* generate_padding_table(Image const& rotated,
Image const& rotated, Point src_rotated_origin,
double rotation, Point const& qdx, Point const& qdy,
int q_pos) int src_qwidth, int src_qheight)
{ {
uint16_t* padding_table = new uint16_t[rotated.height]; uint16_t* padding_table = new uint16_t[rotated.height];
// We suppose the image is square. // We suppose the image is square.
double const sigma = 1.0e-5; if (qdx.x == 0 || qdx.y == 0)
if (fequal(rotation, 0, sigma)
|| fequal(rotation, M_PI / 2, sigma)
|| fequal(rotation, M_PI, sigma)
|| fequal(rotation, 3 * M_PI / 2, sigma))
{ {
memset(padding_table, 0, sizeof (uint16_t) * rotated.height); memset(padding_table, 0, sizeof (uint16_t) * rotated.height);
return padding_table; return padding_table;
} }
double padding_rotation = 0.0; for (unsigned int i = 0; i < rotated.height; ++i)
if (rotation < M_PI / 2)
{ {
padding_rotation = rotation; int y_range = 0;
} else if (rotation < M_PI) if (src_rotated_origin.y < 0)
{ {
padding_rotation = rotation - M_PI / 2; y_range = ceil((-src_rotated_origin.y) / (float) qdx.y);
} else if (rotation < 3 * M_PI / 2) }
{ else if (src_rotated_origin.y >= src_qheight)
padding_rotation = rotation - M_PI; {
} y_range = ceil((float) (src_rotated_origin.y - src_qheight + 1) / (float) (-qdx.y));
else }
{ if (y_range < 0)
padding_rotation = rotation - 3 * M_PI / 2; {
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 return padding_table;
// 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);
DPoint const top_right_grid = get_mapped_point(src, Point(src.width - 1, 0), padding_rotation); uint16_t* generate_padding_table_back_q(Image const& rotated,
DPoint const top_right = convert_img_coord_precision(rotated, top_right_grid); Point src_rotated_origin,
Point const q_top_right(top_right.x * q_pos, top_right.y * q_pos); Point const& qdx,
Point const& qdy,
DPoint const bottom_left_grid = get_mapped_point(src, Point(0, src.height), padding_rotation); int src_qwidth,
DPoint const bottom_left = convert_img_coord_precision(rotated, bottom_left_grid); int src_qheight,
Point const q_bottom_left(bottom_left.x * q_pos, bottom_left.y * q_pos); uint16_t const* front_padding)
{
int i = 0; uint16_t* padding_table = new uint16_t[rotated.height];
int const q_top_width = q_top_right.x; // We suppose the image is square.
int const q_top_step = q_top_width / top_left.y; if (qdx.x == 0 || qdx.y == 0)
int previous_padding = 0;
for (; i <= top_left.y; ++i)
{ {
padding_table[i] = (q_top_width - i * q_top_step) / q_pos; memset(padding_table, 0, sizeof (uint16_t) * rotated.height);
previous_padding = padding_table[i]; return padding_table;
} }
int const remaining_height = rotated.height - 1 - i; src_rotated_origin.x = (rotated.width - 1) * qdx.x;
int const q_bottom_width = q_bottom_left.x; src_rotated_origin.y = (rotated.width - 1) * qdx.y;
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]);
}
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; return padding_table;
} }
void print_padding_table(uint16_t const* padding_table, void print_padding_table(uint16_t const* padding_table,
uint16_t const* border_table, uint16_t const* border_table,
unsigned int size) Image const& image)
{ {
cout << "Padding table:" << endl; 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_padding = padding_table[i];
int left_border = border_table[i]; int left_border = border_table[i];
int right_padding = padding_table[size - 1 - i]; int right_padding = padding_table[image.height - 1 - i];
int right_border = border_table[size - 1 - i]; int right_border = border_table[image.height - 1 - i];
int core_pixels = size - left_padding - right_padding - left_border - right_border; int core_pixels = image.width - left_padding - right_padding - left_border - right_border;
if (core_pixels < 0) if (core_pixels < 0)
{ {
cout << "Too much padding + border at line " << i << endl; cout << "Too much padding + border at line " << i << endl;
cout << " left padding = " << left_padding << endl; cout << " left padding = " << left_padding << endl;
cout << " left border = " << left_border << endl; cout << " left border = " << left_border << endl;
cout << " right padding = " << right_padding << endl;
cout << " right border = " << right_border << 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 << " total = " << left_padding + left_border + right_border + right_padding << endl;
cout << " max size = " << size << endl; cout << " width = " << image.width << endl;
abort(); abort();
} }
cout << " ["; cout << " " << i << " [";
for (int j = 0; j < left_padding; ++j) for (int j = 0; j < left_padding; ++j)
cout << " "; cout << " ";
for (int j = 0; j < left_border; ++j) for (int j = 0; j < left_border; ++j)
@ -280,39 +360,68 @@ void print_padding_table(uint16_t const* padding_table,
// Border // 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]; uint16_t* border_table = new uint16_t[image.height];
border_table[0] = 0; if (image.width - padding_table[0] - padding_table[image.height - 1] == 0)
for (int i = 1; i < size - 1; ++i)
{ {
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]; border_table[i] = 1;
if (padding_table[i - 1] != padding_table[i])
border_table[i] += 1;
} }
else else
{ {
border_table[i] = 1; if (padding_table[i - 1] > padding_table[i])
if (padding_table[i - 1] != padding_table[i]) {
border_table[i - 1] += 1; 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 // 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] if (padding_table[i] + border_table[i]
+ padding_table[size - 1 - i] + border_table[size - 1 - i] + padding_table[image.height - 1 - i] + border_table[image.height - 1 - i]
> size) > (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; return border_table;
} }
@ -329,7 +438,7 @@ void rotate_pixel(Image const& src,
Point const& src_rotated_point, Point const& src_rotated_point,
unsigned int const src_limit, unsigned int const src_limit,
pvalue_t* rotate_buffer, unsigned int rot_index, pvalue_t* rotate_buffer, unsigned int rot_index,
unsigned int q_pow) int q_pow)
{ {
// Quantize on a 8x8 grid // Quantize on a 8x8 grid
int const q_inter_pow = 3; 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; unsigned int const src_limit = src.width * src.height * src.pixel_size;
int const width = rotated->width; int const width = rotated->width;
int const height = rotated->height; 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, Point src_rotated_origin(rot_origin_in_src.x * q_pos + q_pos / 2,
rot_origin_in_src.y * q_pos); rot_origin_in_src.y * q_pos + q_pos / 2);
// Padding // Padding
uint16_t* padding_table = generate_padding_table(src, *rotated, rotation, q_pos); uint16_t* padding_table = generate_padding_table(*rotated, src_rotated_origin,
uint16_t* border_table = generate_border_table(padding_table, rotated->height); qdx, qdy,
//print_padding_table(padding_table, border_table, height, true); 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) for (int y = 0; y < height; ++y)
{ {
Point src_rotated_point = src_rotated_origin;
// TODO: compact these structure to increase locality // TODO: compact these structure to increase locality
int const left_padding = padding_table[y]; int const left_padding = padding_table[y];
int const left_border = border_table[y]; int const left_border = 0;
int const right_padding = padding_table[height - 1 - y]; int const right_padding = 0;
int const right_border = border_table[height - 1 - y]; int const right_border = padding_table[height - 1 - y];
int const core_pixels = width - left_padding - left_border - right_border - right_padding; int const core_pixels = width - left_padding - left_border - right_border - right_padding;
// Left padding // Left padding
for (int x = 0; x < left_padding; ++x, ++buffer_index) for (int x = 0; x < left_padding; ++x, ++buffer_index)
{ {
// Set to black value // Set to black value
buffer[buffer_index] = 0; // TODO: memset
src_rotated_point += qdx; buffer[buffer_index] = 50;
} }
// Border // Border
for (int x = 0; x < left_border; ++x, ++buffer_index) for (int x = 0; x < left_border; ++x, ++buffer_index)
{ {
buffer[buffer_index] = 0; // TODO: handle border 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 // Body
for (int x = 0; x < core_pixels; ++x, ++buffer_index) 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; 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) for (int x = 0; x < right_padding; ++x, ++buffer_index)
{ {
// Set to black value // Set to black value
buffer[buffer_index] = 0; // TODO: memset
buffer[buffer_index] = 100;
} }
src_rotated_origin += qdy; src_rotated_origin += qdy;
} }
// cout << endl;
return rotated; return rotated;
} }
@ -798,9 +941,9 @@ int main(int argc, char* argv[])
} }
} }
double const step = 15; double const step = 5;
bool save_output_img = false; bool save_output_img = true;
bool print_each_run = false; bool print_each_run = true;
bool test_tile = false; bool test_tile = false;
// No tile // No tile