mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
152 lines
4.8 KiB
152 lines
4.8 KiB
// Copyright 2012 Google Inc. All Rights Reserved. |
|
// |
|
// This code is licensed under the same terms as WebM: |
|
// Software License Agreement: http://www.webmproject.org/license/software/ |
|
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ |
|
// ----------------------------------------------------------------------------- |
|
// |
|
// Rescaling functions |
|
// |
|
// Author: Skal (pascal.massimino@gmail.com) |
|
|
|
#include <assert.h> |
|
#include <stdlib.h> |
|
#include "./rescaler.h" |
|
|
|
//------------------------------------------------------------------------------ |
|
|
|
#if defined(__cplusplus) || defined(c_plusplus) |
|
extern "C" { |
|
#endif |
|
|
|
#define RFIX 30 |
|
#define MULT_FIX(x,y) (((int64_t)(x) * (y) + (1 << (RFIX - 1))) >> RFIX) |
|
|
|
void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height, |
|
uint8_t* const dst, int dst_width, int dst_height, |
|
int dst_stride, int num_channels, int x_add, int x_sub, |
|
int y_add, int y_sub, int32_t* const work) { |
|
wrk->x_expand = (src_width < dst_width); |
|
wrk->src_width = src_width; |
|
wrk->src_height = src_height; |
|
wrk->dst_width = dst_width; |
|
wrk->dst_height = dst_height; |
|
wrk->dst = dst; |
|
wrk->dst_stride = dst_stride; |
|
wrk->num_channels = num_channels; |
|
// for 'x_expand', we use bilinear interpolation |
|
wrk->x_add = wrk->x_expand ? (x_sub - 1) : x_add - x_sub; |
|
wrk->x_sub = wrk->x_expand ? (x_add - 1) : x_sub; |
|
wrk->y_accum = y_add; |
|
wrk->y_add = y_add; |
|
wrk->y_sub = y_sub; |
|
wrk->fx_scale = (1 << RFIX) / x_sub; |
|
wrk->fy_scale = (1 << RFIX) / y_sub; |
|
wrk->fxy_scale = wrk->x_expand ? |
|
((int64_t)dst_height << RFIX) / (x_sub * src_height) : |
|
((int64_t)dst_height << RFIX) / (x_add * src_height); |
|
wrk->irow = work; |
|
wrk->frow = work + num_channels * dst_width; |
|
} |
|
|
|
void WebPRescalerImportRow(WebPRescaler* const wrk, |
|
const uint8_t* const src, int channel) { |
|
const int x_stride = wrk->num_channels; |
|
const int x_out_max = wrk->dst_width * wrk->num_channels; |
|
int x_in = channel; |
|
int x_out; |
|
int accum = 0; |
|
if (!wrk->x_expand) { |
|
int sum = 0; |
|
for (x_out = channel; x_out < x_out_max; x_out += x_stride) { |
|
accum += wrk->x_add; |
|
for (; accum > 0; accum -= wrk->x_sub) { |
|
sum += src[x_in]; |
|
x_in += x_stride; |
|
} |
|
{ // Emit next horizontal pixel. |
|
const int32_t base = src[x_in]; |
|
const int32_t frac = base * (-accum); |
|
x_in += x_stride; |
|
wrk->frow[x_out] = (sum + base) * wrk->x_sub - frac; |
|
// fresh fractional start for next pixel |
|
sum = (int)MULT_FIX(frac, wrk->fx_scale); |
|
} |
|
} |
|
} else { // simple bilinear interpolation |
|
int left = src[channel], right = src[channel]; |
|
for (x_out = channel; x_out < x_out_max; x_out += x_stride) { |
|
if (accum < 0) { |
|
left = right; |
|
x_in += x_stride; |
|
right = src[x_in]; |
|
accum += wrk->x_add; |
|
} |
|
wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum; |
|
accum -= wrk->x_sub; |
|
} |
|
} |
|
// Accumulate the new row's contribution |
|
for (x_out = channel; x_out < x_out_max; x_out += x_stride) { |
|
wrk->irow[x_out] += wrk->frow[x_out]; |
|
} |
|
} |
|
|
|
uint8_t* WebPRescalerExportRow(WebPRescaler* const wrk) { |
|
if (wrk->y_accum <= 0) { |
|
int x_out; |
|
uint8_t* const dst = wrk->dst; |
|
int32_t* const irow = wrk->irow; |
|
const int32_t* const frow = wrk->frow; |
|
const int yscale = wrk->fy_scale * (-wrk->y_accum); |
|
const int x_out_max = wrk->dst_width * wrk->num_channels; |
|
|
|
for (x_out = 0; x_out < x_out_max; ++x_out) { |
|
const int frac = (int)MULT_FIX(frow[x_out], yscale); |
|
const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale); |
|
dst[x_out] = (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255; |
|
irow[x_out] = frac; // new fractional start |
|
} |
|
wrk->y_accum += wrk->y_add; |
|
wrk->dst += wrk->dst_stride; |
|
return dst; |
|
} else { |
|
return NULL; |
|
} |
|
} |
|
|
|
#undef MULT_FIX |
|
#undef RFIX |
|
|
|
//------------------------------------------------------------------------------ |
|
// all-in-one calls |
|
|
|
int WebPRescalerImport(WebPRescaler* const wrk, int num_lines, |
|
const uint8_t* src, int src_stride) { |
|
int total_imported = 0; |
|
while (total_imported < num_lines && wrk->y_accum > 0) { |
|
int channel; |
|
for (channel = 0; channel < wrk->num_channels; ++channel) { |
|
WebPRescalerImportRow(wrk, src, channel); |
|
} |
|
src += src_stride; |
|
++total_imported; |
|
wrk->y_accum -= wrk->y_sub; |
|
} |
|
return total_imported; |
|
} |
|
|
|
int WebPRescalerExport(WebPRescaler* const rescaler) { |
|
int total_exported = 0; |
|
while (WebPRescalerHasPendingOutput(rescaler)) { |
|
WebPRescalerExportRow(rescaler); |
|
++total_exported; |
|
} |
|
return total_exported; |
|
} |
|
|
|
//------------------------------------------------------------------------------ |
|
|
|
#if defined(__cplusplus) || defined(c_plusplus) |
|
} // extern "C" |
|
#endif
|
|
|