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:
parent
9cdea5bcc3
commit
e7802e30fd
82
rotation.cpp
82
rotation.cpp
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue