Compute src position in quantified coordinates.

Instead of relying on floating values for the position in the
source image, we quantify all positions with a power of 2.

We lose some precision and the delta step is less accurate, leading in
some offset at the end.

For now the rotation is not correct.
This commit is contained in:
Fabien Freling 2014-07-23 23:44:14 +02:00
parent 9cdea5bcc3
commit e7802e30fd

View file

@ -88,7 +88,7 @@ void compute_output_size(Image const& src, double const rotation, unsigned int&
Point p(0, 0);
double angle = convert_radian(src, p, ratio);
DPoint tl = convert_abs_coord(angle + rotation, ratio);
DPoint const tl = convert_abs_coord(angle + rotation, ratio);
min_w = min(min_w, tl.x);
max_w = max(max_w, tl.x);
min_h = min(min_h, tl.y);
@ -96,7 +96,7 @@ void compute_output_size(Image const& src, double const rotation, unsigned int&
p = Point(src.width - 1, 0);
angle = convert_radian(src, p, ratio);
DPoint tr = convert_abs_coord(angle + rotation, ratio);
DPoint const tr = convert_abs_coord(angle + rotation, ratio);
min_w = min(min_w, tr.x);
max_w = max(max_w, tr.x);
min_h = min(min_h, tr.y);
@ -104,7 +104,7 @@ void compute_output_size(Image const& src, double const rotation, unsigned int&
p = Point(0, src.height - 1);
angle = convert_radian(src, p, ratio);
DPoint bl = convert_abs_coord(angle + rotation, ratio);
DPoint const bl = convert_abs_coord(angle + rotation, ratio);
min_w = min(min_w, bl.x);
max_w = max(max_w, bl.x);
min_h = min(min_h, bl.y);
@ -112,7 +112,7 @@ void compute_output_size(Image const& src, double const rotation, unsigned int&
p = Point(src.width - 1, src.height - 1);
angle = convert_radian(src, p, ratio);
DPoint br = convert_abs_coord(angle + rotation, ratio);
DPoint const br = convert_abs_coord(angle + rotation, ratio);
min_w = min(min_w, br.x);
max_w = max(max_w, br.x);
min_h = min(min_h, br.y);
@ -164,12 +164,11 @@ inline
void rotate_pixel(Image const& src,
Point const& src_rotated_point,
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, unsigned int q)
{
unsigned int const quantize = 8;
int const src_x = src_rotated_point.x >> 3;
int const src_y = src_rotated_point.y >> 3;
int const src_x = src_rotated_point.x >> q_pow;
int const src_y = src_rotated_point.y >> q_pow;
unsigned int src_index = (src_y * src.width + src_x) * src.pixel_size;
@ -182,17 +181,17 @@ void rotate_pixel(Image const& src,
if (src_index_4 >= src_limit)
return;
unsigned int x_delta = src_rotated_point.x & 0x07;;
unsigned int y_delta = src_rotated_point.y & 0x07;
unsigned int const inv_x = quantize - x_delta;
unsigned int const inv_y = quantize - y_delta;
unsigned int x_delta = src_rotated_point.x & 0x0f;
unsigned int y_delta = src_rotated_point.y & 0x0f;
unsigned int const inv_x = q - x_delta;
unsigned int const inv_y = q - y_delta;
#ifndef SIMD
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;
+ (src.buffer[src_index_3] * inv_x + src.buffer[src_index_4] * x_delta) * y_delta) >> (2 * q_pow);
// 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
@ -214,7 +213,7 @@ void rotate_pixel(Image const& src,
bottom = _mm_mullo_epi16(bottom, coef);
top = _mm_add_epi16(top, bottom);
top = _mm_srli_epi16(top, 6);
top = _mm_srli_epi16(top, 2 * q_pow);
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);
@ -232,29 +231,20 @@ Image* rotate(Image const& src, double angle)
compute_output_size(src, rotation, w, h);
Image* rotated = new Image(w, h, src.type);
// corner points in rotated image
// TODO: add one ligne for smooth border
DPoint const tl_grid = get_mapped_point(src, Point(0, 0), rotation);
Point const tl = convert_img_coord(*rotated, tl_grid);
// corner points in source image
DPoint src_tl = get_mapped_point(*rotated, tl, -rotation);
src_tl = convert_img_coord_precision(src, src_tl);
DPoint const src_origin = get_mapped_point(*rotated, Point(0, 0), -rotation);
DPoint src_delta_x = get_mapped_point(*rotated, Point(1, 0), -rotation);
DPoint src_delta_y = get_mapped_point(*rotated, Point(0, 1), -rotation);
DPoint src_delta_x = get_mapped_point(*rotated, Point(src.width - 1, 0), -rotation);
DPoint src_delta_y = get_mapped_point(*rotated, Point(0, src.height - 1), -rotation);
src_delta_x.x = src_delta_x.x - src_origin.x;
src_delta_x.y = src_delta_x.y - src_origin.y;
round_if_very_small(src_delta_x.x);
round_if_very_small(src_delta_x.y);
src_delta_y.x = src_delta_y.x - src_origin.x;
src_delta_y.y = src_delta_y.y - src_origin.y;
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 * src.pixel_size;
// Quantized delta
unsigned int const q_pow = 4;
int const q = pow(2, q_pow);
// TODO: we could have only one delta and deduce the other one
Point const qdx((src_delta_x.x * q) / src.width, (src_delta_x.y * q) / src.width);
Point const qdy((src_delta_y.x * q) / src.height, (src_delta_y.y * q) / src.height);
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);
@ -262,28 +252,30 @@ Image* rotate(Image const& src, double angle)
unsigned int buffer_index = 0;
pvalue_t* buffer = rotated->buffer;
unsigned int const quantize = 8;
int const& src_qwidth = src.width * quantize;
int const& src_qheight = src.height * quantize;
int const src_qwidth = src.width * q;
int const src_qheight = src.height * q;
for (unsigned int y = 0; y < rotated->height; ++y)
unsigned int const src_limit = src_qwidth * src_qheight * src.pixel_size;
for (int y = 0; y < (int) rotated->height; ++y)
{
Point const src_rotated_point((rot_origin_in_src.x + y * src_delta_y.x) * quantize,
(rot_origin_in_src.y + y * src_delta_y.y) * quantize);
Point src_rotated_point((rot_origin_in_src.x * q) + y * qdy.x,
(rot_origin_in_src.y * q) + y * qdy.y);
for (unsigned int x = 0; x < rotated->width; ++x)
{
Point const src_runner(src_rotated_point.x + x * src_delta_x.x * quantize,
src_rotated_point.y + x * src_delta_x.y * quantize);
if (src_runner.x >= 0 && src_runner.x < src_qwidth
&& src_runner.y >= 0 && src_runner.y < src_qheight)
if (src_rotated_point.x >= 0 && src_rotated_point.x < src_qwidth
&& src_rotated_point.y >= 0 && src_rotated_point.y < src_qheight)
{
rotate_pixel(src, src_runner,
rotate_pixel(src, src_rotated_point,
src_limit,
buffer, buffer_index);
buffer, buffer_index,
q_pow, q);
}
src_rotated_point.x += qdx.x;
src_rotated_point.y += qdx.y;
buffer_index += rotated->pixel_size;
}
}