|
|
@@ -4,46 +4,192 @@ |
|
|
|
#include <jpeglib.h> |
|
|
|
#include <omp.h> |
|
|
|
|
|
|
|
static int blur_radius = 15; |
|
|
|
static int blur_times = 5; |
|
|
|
|
|
|
|
static void blur_h( |
|
|
|
unsigned char *dest, unsigned char *src, |
|
|
|
int stride, int width, int height, int radius) { |
|
|
|
double coeff = 1.0 / (radius * 2 + 1); |
|
|
|
|
|
|
|
#pragma omp parallel for |
|
|
|
for (int i = 0; i < height; ++i) { |
|
|
|
int iwidth = i * stride * 3; |
|
|
|
double r_acc = 0.0; |
|
|
|
double g_acc = 0.0; |
|
|
|
double b_acc = 0.0; |
|
|
|
for (int j = -radius; j < width; ++j) { |
|
|
|
if (j - radius - 1 >= 0) { |
|
|
|
int index = iwidth + (j - radius - 1) * 3; |
|
|
|
r_acc -= coeff * src[index + 0]; |
|
|
|
g_acc -= coeff * src[index + 1]; |
|
|
|
b_acc -= coeff * src[index + 2]; |
|
|
|
} |
|
|
|
if (j + radius < width) { |
|
|
|
int index = iwidth + (j + radius) * 3; |
|
|
|
r_acc += coeff * src[index + 0]; |
|
|
|
g_acc += coeff * src[index + 1]; |
|
|
|
b_acc += coeff * src[index + 2]; |
|
|
|
} |
|
|
|
if (j < 0) |
|
|
|
continue; |
|
|
|
int index = iwidth + j * 3; |
|
|
|
dest[index + 0] = r_acc + 0.5; |
|
|
|
dest[index + 1] = g_acc + 0.5; |
|
|
|
dest[index + 2] = b_acc + 0.5; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void blur_v( |
|
|
|
unsigned char *dest, unsigned char *src, |
|
|
|
int stride, int width, int height, int radius) { |
|
|
|
double coeff = 1.0 / (radius * 2 + 1); |
|
|
|
|
|
|
|
#pragma omp parallel for |
|
|
|
for (int j = 0; j < width; ++j) { |
|
|
|
double r_acc = 0.0; |
|
|
|
double g_acc = 0.0; |
|
|
|
double b_acc = 0.0; |
|
|
|
for (int i = -radius; i < height; ++i) { |
|
|
|
if (i - radius - 1 >= 0) { |
|
|
|
int index = (i - radius - 1) * stride * 3 + j * 3; |
|
|
|
r_acc -= coeff * src[index + 0]; |
|
|
|
g_acc -= coeff * src[index + 1]; |
|
|
|
b_acc -= coeff * src[index + 2]; |
|
|
|
} |
|
|
|
if (i + radius < height) { |
|
|
|
int index = (i + radius) * stride * 3 + j * 3; |
|
|
|
r_acc += coeff * src[index + 0]; |
|
|
|
g_acc += coeff * src[index + 1]; |
|
|
|
b_acc += coeff * src[index + 2]; |
|
|
|
} |
|
|
|
if (i < 0) |
|
|
|
continue; |
|
|
|
int index = i * stride * 3 + j * 3; |
|
|
|
dest[index + 0] = r_acc + 0.5; |
|
|
|
dest[index + 1] = g_acc + 0.5; |
|
|
|
dest[index + 2] = b_acc + 0.5; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void blur_once( |
|
|
|
unsigned char *dest, unsigned char *src, unsigned char *scratch, |
|
|
|
int stride, int width, int height, int radius) { |
|
|
|
blur_h(scratch, src, stride, width, height, radius); |
|
|
|
blur_v(dest, scratch, stride, width, height, radius); |
|
|
|
} |
|
|
|
|
|
|
|
void blur_rect( |
|
|
|
unsigned char *image, unsigned char *scratch, unsigned char *scratch2, |
|
|
|
int stride, int x, int y, int w, int h, int radius, int times) { |
|
|
|
if (w == 0 || h == 0) |
|
|
|
return; |
|
|
|
|
|
|
|
unsigned char *orig = image; |
|
|
|
int idx = y * stride * 3 + x * 3; |
|
|
|
for (int i = 0; i < times; ++i) { |
|
|
|
blur_once(scratch + idx, image + idx, scratch2, stride, w, h, radius); |
|
|
|
if (i != times - 1) { |
|
|
|
unsigned char *tmp = image; |
|
|
|
image = scratch; |
|
|
|
scratch = tmp; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (image != orig) |
|
|
|
memcpy(scratch + idx, image + idx, stride * h * 3); |
|
|
|
} |
|
|
|
|
|
|
|
unsigned char *process_image( |
|
|
|
unsigned char *input_image, int input_width, int input_height, |
|
|
|
int desired_width, int desired_height) { |
|
|
|
unsigned char *output = calloc(3, desired_width * desired_height); |
|
|
|
unsigned char *output_image = calloc(3, desired_width * desired_height); |
|
|
|
|
|
|
|
double scale_w = (double)desired_width / (double)input_width; |
|
|
|
double scale_h = (double)desired_height / (double)input_height; |
|
|
|
double scale; |
|
|
|
printf("scales are %fx%f\n", scale_w, scale_h); |
|
|
|
|
|
|
|
int rect_x, rect_y, rect_w, rect_h; |
|
|
|
if (scale_w < scale_h) { |
|
|
|
printf("too wide?\n"); |
|
|
|
if (scale_w < scale_h) |
|
|
|
scale = scale_w; |
|
|
|
} else { |
|
|
|
printf("too tall?\n"); |
|
|
|
else |
|
|
|
scale = scale_h; |
|
|
|
} |
|
|
|
|
|
|
|
rect_w = input_width * scale; |
|
|
|
rect_h = input_height * scale; |
|
|
|
rect_x = (desired_width - rect_w) / 2.0; |
|
|
|
rect_y = (desired_height - rect_h) / 2.0; |
|
|
|
|
|
|
|
printf("rect is %ix%i:%i,%i\n", rect_w, rect_h, rect_x, rect_y); |
|
|
|
|
|
|
|
// Write main image |
|
|
|
#pragma omp parallel for |
|
|
|
for (int y = 0; y < rect_h; ++y) { |
|
|
|
for (int x = 0; x < rect_w; ++x) { |
|
|
|
int input_y = y / scale; |
|
|
|
int input_x = x / scale; |
|
|
|
int input_idx = input_y * input_width * 3 + input_x * 3; |
|
|
|
int output_idx = (y + rect_y) * desired_width * 3 + (x + rect_x) * 3; |
|
|
|
output[output_idx + 0] = input_image[input_idx + 0]; |
|
|
|
output[output_idx + 1] = input_image[input_idx + 1]; |
|
|
|
output[output_idx + 2] = input_image[input_idx + 2]; |
|
|
|
output_image[output_idx + 0] = input_image[input_idx + 0]; |
|
|
|
output_image[output_idx + 1] = input_image[input_idx + 1]; |
|
|
|
output_image[output_idx + 2] = input_image[input_idx + 2]; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Top/bottom |
|
|
|
for (int y = 0; y < rect_y; ++y) { |
|
|
|
for (int x = 0; x < rect_w; ++x) { |
|
|
|
int input_idx = (y + rect_y) * desired_width * 3 + (x + rect_x) * 3; |
|
|
|
int output_idx = y * desired_width * 3 + (x + rect_x) * 3; |
|
|
|
output_image[output_idx + 0] = output_image[input_idx + 0]; |
|
|
|
output_image[output_idx + 1] = output_image[input_idx + 1]; |
|
|
|
output_image[output_idx + 2] = output_image[input_idx + 2]; |
|
|
|
|
|
|
|
input_idx = (y + rect_h) * desired_width * 3 + (x + rect_x) * 3; |
|
|
|
output_idx = (y + rect_h + rect_y) * desired_width * 3 + (x + rect_x) * 3; |
|
|
|
output_image[output_idx + 0] = output_image[input_idx + 0]; |
|
|
|
output_image[output_idx + 1] = output_image[input_idx + 1]; |
|
|
|
output_image[output_idx + 2] = output_image[input_idx + 2]; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return output; |
|
|
|
// Left/right |
|
|
|
for (int x = 0; x < rect_x; ++x) { |
|
|
|
for (int y = 0; y < rect_h; ++y) { |
|
|
|
int input_idx_l = (y + rect_y) * desired_width * 3 + (x + rect_x) * 3; |
|
|
|
int output_idx_l = y * desired_width * 3 + (x) * 3; |
|
|
|
int input_idx_r = (y + rect_y) * desired_width * 3 + (x + rect_w) * 3; |
|
|
|
int output_idx_r = y * desired_width * 3 + (x + rect_w + rect_x) * 3; |
|
|
|
|
|
|
|
output_image[output_idx_l + 0] = output_image[input_idx_l + 0]; |
|
|
|
output_image[output_idx_l + 1] = output_image[input_idx_l + 1]; |
|
|
|
output_image[output_idx_l + 2] = output_image[input_idx_l + 2]; |
|
|
|
|
|
|
|
output_image[output_idx_r + 0] = output_image[input_idx_r + 0]; |
|
|
|
output_image[output_idx_r + 1] = output_image[input_idx_r + 1]; |
|
|
|
output_image[output_idx_r + 2] = output_image[input_idx_r + 2]; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Blur |
|
|
|
unsigned char *scratch = calloc(3, desired_width * desired_height); |
|
|
|
unsigned char *scratch2 = calloc(3, desired_width * desired_height); |
|
|
|
blur_rect( |
|
|
|
output_image, scratch, scratch2, desired_width, |
|
|
|
0, 0, desired_width, rect_y, blur_radius, blur_times); |
|
|
|
blur_rect( |
|
|
|
output_image, scratch, scratch2, desired_width, |
|
|
|
0, rect_y + rect_h, desired_width, rect_y, blur_radius, blur_times); |
|
|
|
blur_rect( |
|
|
|
output_image, scratch, scratch2, desired_width, |
|
|
|
0, 0, rect_x, desired_height, blur_radius, blur_times); |
|
|
|
blur_rect( |
|
|
|
output_image, scratch, scratch2, desired_width, |
|
|
|
rect_x + rect_w, 0, rect_x, desired_height, blur_radius, blur_times); |
|
|
|
free(scratch); |
|
|
|
free(scratch2); |
|
|
|
|
|
|
|
return output_image; |
|
|
|
} |
|
|
|
|
|
|
|
unsigned char *read_jpg(FILE *in, int *width, int *height) { |
|
|
@@ -85,7 +231,6 @@ void write_jpg(FILE *out, unsigned char *image, int width, int height) { |
|
|
|
jpeg_create_compress(&cinfo); |
|
|
|
jpeg_stdio_dest(&cinfo, out); |
|
|
|
|
|
|
|
printf("writing %ix%i\n", width, height); |
|
|
|
cinfo.image_width = width; |
|
|
|
cinfo.image_height = height; |
|
|
|
cinfo.input_components = 3; |