Merge commit '638ecc4cde79b0296f2e04f683ca4cb881c28f36' as 'rtengine/libraw'
This commit is contained in:
113
rtengine/libraw/src/postprocessing/aspect_ratio.cpp
Normal file
113
rtengine/libraw/src/postprocessing/aspect_ratio.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
/* -*- C++ -*-
|
||||
* Copyright 2019-2021 LibRaw LLC (info@libraw.org)
|
||||
*
|
||||
LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder,
|
||||
dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net.
|
||||
LibRaw do not use RESTRICTED code from dcraw.c
|
||||
|
||||
LibRaw is free software; you can redistribute it and/or modify
|
||||
it under the terms of the one of two licenses as you choose:
|
||||
|
||||
1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
|
||||
(See file LICENSE.LGPL provided in LibRaw distribution archive for details).
|
||||
|
||||
2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
|
||||
(See file LICENSE.CDDL provided in LibRaw distribution archive for details).
|
||||
|
||||
*/
|
||||
|
||||
#include "../../internal/dcraw_defs.h"
|
||||
|
||||
void LibRaw::fuji_rotate()
|
||||
{
|
||||
int i, row, col;
|
||||
double step;
|
||||
float r, c, fr, fc;
|
||||
unsigned ur, uc;
|
||||
ushort wide, high, (*img)[4], (*pix)[4];
|
||||
|
||||
if (!fuji_width)
|
||||
return;
|
||||
fuji_width = (fuji_width - 1 + shrink) >> shrink;
|
||||
step = sqrt(0.5);
|
||||
wide = fuji_width / step;
|
||||
high = (height - fuji_width) / step;
|
||||
|
||||
// All real fuji/rotated images are small, so check against max_raw_memory_mb here is safe
|
||||
if (INT64(wide) * INT64(high) * INT64(sizeof(*img)) >
|
||||
INT64(imgdata.rawparams.max_raw_memory_mb) * INT64(1024 * 1024))
|
||||
throw LIBRAW_EXCEPTION_TOOBIG;
|
||||
|
||||
img = (ushort(*)[4])calloc(high, wide * sizeof *img);
|
||||
|
||||
RUN_CALLBACK(LIBRAW_PROGRESS_FUJI_ROTATE, 0, 2);
|
||||
|
||||
for (row = 0; row < high; row++)
|
||||
for (col = 0; col < wide; col++)
|
||||
{
|
||||
ur = r = fuji_width + (row - col) * step;
|
||||
uc = c = (row + col) * step;
|
||||
if (ur > (unsigned)height - 2 || uc > (unsigned)width - 2)
|
||||
continue;
|
||||
fr = r - ur;
|
||||
fc = c - uc;
|
||||
pix = image + ur * width + uc;
|
||||
for (i = 0; i < colors; i++)
|
||||
img[row * wide + col][i] =
|
||||
(pix[0][i] * (1 - fc) + pix[1][i] * fc) * (1 - fr) +
|
||||
(pix[width][i] * (1 - fc) + pix[width + 1][i] * fc) * fr;
|
||||
}
|
||||
|
||||
free(image);
|
||||
width = wide;
|
||||
height = high;
|
||||
image = img;
|
||||
fuji_width = 0;
|
||||
RUN_CALLBACK(LIBRAW_PROGRESS_FUJI_ROTATE, 1, 2);
|
||||
}
|
||||
|
||||
void LibRaw::stretch()
|
||||
{
|
||||
ushort newdim, (*img)[4], *pix0, *pix1;
|
||||
int row, col, c;
|
||||
double rc, frac;
|
||||
|
||||
if (pixel_aspect == 1)
|
||||
return;
|
||||
RUN_CALLBACK(LIBRAW_PROGRESS_STRETCH, 0, 2);
|
||||
if (pixel_aspect < 1)
|
||||
{
|
||||
newdim = height / pixel_aspect + 0.5;
|
||||
img = (ushort(*)[4])calloc(width, newdim * sizeof *img);
|
||||
for (rc = row = 0; row < newdim; row++, rc += pixel_aspect)
|
||||
{
|
||||
frac = rc - (c = rc);
|
||||
pix0 = pix1 = image[c * width];
|
||||
if (c + 1 < height)
|
||||
pix1 += width * 4;
|
||||
for (col = 0; col < width; col++, pix0 += 4, pix1 += 4)
|
||||
FORCC img[row * width + col][c] =
|
||||
pix0[c] * (1 - frac) + pix1[c] * frac + 0.5;
|
||||
}
|
||||
height = newdim;
|
||||
}
|
||||
else
|
||||
{
|
||||
newdim = width * pixel_aspect + 0.5;
|
||||
img = (ushort(*)[4])calloc(height, newdim * sizeof *img);
|
||||
for (rc = col = 0; col < newdim; col++, rc += 1 / pixel_aspect)
|
||||
{
|
||||
frac = rc - (c = rc);
|
||||
pix0 = pix1 = image[c];
|
||||
if (c + 1 < width)
|
||||
pix1 += 4;
|
||||
for (row = 0; row < height; row++, pix0 += width * 4, pix1 += width * 4)
|
||||
FORCC img[row * newdim + col][c] =
|
||||
pix0[c] * (1 - frac) + pix1[c] * frac + 0.5;
|
||||
}
|
||||
width = newdim;
|
||||
}
|
||||
free(image);
|
||||
image = img;
|
||||
RUN_CALLBACK(LIBRAW_PROGRESS_STRETCH, 1, 2);
|
||||
}
|
259
rtengine/libraw/src/postprocessing/dcraw_process.cpp
Normal file
259
rtengine/libraw/src/postprocessing/dcraw_process.cpp
Normal file
@@ -0,0 +1,259 @@
|
||||
/* -*- C++ -*-
|
||||
* Copyright 2019-2021 LibRaw LLC (info@libraw.org)
|
||||
*
|
||||
LibRaw is free software; you can redistribute it and/or modify
|
||||
it under the terms of the one of two licenses as you choose:
|
||||
|
||||
1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
|
||||
(See file LICENSE.LGPL provided in LibRaw distribution archive for details).
|
||||
|
||||
2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
|
||||
(See file LICENSE.CDDL provided in LibRaw distribution archive for details).
|
||||
|
||||
*/
|
||||
|
||||
#include "../../internal/libraw_cxx_defs.h"
|
||||
|
||||
int LibRaw::dcraw_process(void)
|
||||
{
|
||||
int quality, i;
|
||||
|
||||
int iterations = -1, dcb_enhance = 1, noiserd = 0;
|
||||
float preser = 0;
|
||||
float expos = 1.0;
|
||||
|
||||
CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW);
|
||||
// CHECK_ORDER_HIGH(LIBRAW_PROGRESS_PRE_INTERPOLATE);
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
int no_crop = 1;
|
||||
|
||||
if (~O.cropbox[2] && ~O.cropbox[3])
|
||||
no_crop = 0;
|
||||
|
||||
libraw_decoder_info_t di;
|
||||
get_decoder_info(&di);
|
||||
|
||||
bool is_bayer = (imgdata.idata.filters || P1.colors == 1);
|
||||
int subtract_inline =
|
||||
!O.bad_pixels && !O.dark_frame && is_bayer && !IO.zero_is_bad;
|
||||
|
||||
int rc = raw2image_ex(subtract_inline); // allocate imgdata.image and copy data!
|
||||
if (rc != LIBRAW_SUCCESS)
|
||||
return rc;
|
||||
|
||||
// Adjust sizes
|
||||
|
||||
int save_4color = O.four_color_rgb;
|
||||
|
||||
if (IO.zero_is_bad)
|
||||
{
|
||||
remove_zeroes();
|
||||
SET_PROC_FLAG(LIBRAW_PROGRESS_REMOVE_ZEROES);
|
||||
}
|
||||
|
||||
if (O.bad_pixels && no_crop)
|
||||
{
|
||||
bad_pixels(O.bad_pixels);
|
||||
SET_PROC_FLAG(LIBRAW_PROGRESS_BAD_PIXELS);
|
||||
}
|
||||
|
||||
if (O.dark_frame && no_crop)
|
||||
{
|
||||
subtract(O.dark_frame);
|
||||
SET_PROC_FLAG(LIBRAW_PROGRESS_DARK_FRAME);
|
||||
}
|
||||
/* pre subtract black callback: check for it above to disable subtract
|
||||
* inline */
|
||||
|
||||
if (callbacks.pre_subtractblack_cb)
|
||||
(callbacks.pre_subtractblack_cb)(this);
|
||||
|
||||
quality = 2 + !IO.fuji_width;
|
||||
|
||||
if (O.user_qual >= 0)
|
||||
quality = O.user_qual;
|
||||
|
||||
if (!subtract_inline || !C.data_maximum)
|
||||
{
|
||||
adjust_bl();
|
||||
subtract_black_internal();
|
||||
}
|
||||
|
||||
if (!(di.decoder_flags & LIBRAW_DECODER_FIXEDMAXC))
|
||||
adjust_maximum();
|
||||
|
||||
if (O.user_sat > 0)
|
||||
C.maximum = O.user_sat;
|
||||
|
||||
if (P1.is_foveon)
|
||||
{
|
||||
if (load_raw == &LibRaw::x3f_load_raw)
|
||||
{
|
||||
// Filter out zeroes
|
||||
for (int q = 0; q < S.height * S.width; q++)
|
||||
{
|
||||
for (int c = 0; c < 4; c++)
|
||||
if ((short)imgdata.image[q][c] < 0)
|
||||
imgdata.image[q][c] = 0;
|
||||
}
|
||||
}
|
||||
SET_PROC_FLAG(LIBRAW_PROGRESS_FOVEON_INTERPOLATE);
|
||||
}
|
||||
|
||||
if (O.green_matching && !O.half_size)
|
||||
{
|
||||
green_matching();
|
||||
}
|
||||
|
||||
if (callbacks.pre_scalecolors_cb)
|
||||
(callbacks.pre_scalecolors_cb)(this);
|
||||
|
||||
if (!O.no_auto_scale)
|
||||
{
|
||||
scale_colors();
|
||||
SET_PROC_FLAG(LIBRAW_PROGRESS_SCALE_COLORS);
|
||||
}
|
||||
|
||||
if (callbacks.pre_preinterpolate_cb)
|
||||
(callbacks.pre_preinterpolate_cb)(this);
|
||||
|
||||
pre_interpolate();
|
||||
|
||||
SET_PROC_FLAG(LIBRAW_PROGRESS_PRE_INTERPOLATE);
|
||||
|
||||
if (O.dcb_iterations >= 0)
|
||||
iterations = O.dcb_iterations;
|
||||
if (O.dcb_enhance_fl >= 0)
|
||||
dcb_enhance = O.dcb_enhance_fl;
|
||||
if (O.fbdd_noiserd >= 0)
|
||||
noiserd = O.fbdd_noiserd;
|
||||
|
||||
/* pre-exposure correction callback */
|
||||
|
||||
if (O.exp_correc > 0)
|
||||
{
|
||||
expos = O.exp_shift;
|
||||
preser = O.exp_preser;
|
||||
exp_bef(expos, preser);
|
||||
}
|
||||
|
||||
if (callbacks.pre_interpolate_cb)
|
||||
(callbacks.pre_interpolate_cb)(this);
|
||||
|
||||
/* post-exposure correction fallback */
|
||||
if (P1.filters && !O.no_interpolation)
|
||||
{
|
||||
if (noiserd > 0 && P1.colors == 3 && P1.filters > 1000)
|
||||
fbdd(noiserd);
|
||||
|
||||
if (P1.filters > 1000 && callbacks.interpolate_bayer_cb)
|
||||
(callbacks.interpolate_bayer_cb)(this);
|
||||
else if (P1.filters == 9 && callbacks.interpolate_xtrans_cb)
|
||||
(callbacks.interpolate_xtrans_cb)(this);
|
||||
else if (quality == 0)
|
||||
lin_interpolate();
|
||||
else if (quality == 1 || P1.colors > 3)
|
||||
vng_interpolate();
|
||||
else if (quality == 2 && P1.filters > 1000)
|
||||
ppg_interpolate();
|
||||
else if (P1.filters == LIBRAW_XTRANS)
|
||||
{
|
||||
// Fuji X-Trans
|
||||
xtrans_interpolate(quality > 2 ? 3 : 1);
|
||||
}
|
||||
else if (quality == 3)
|
||||
ahd_interpolate(); // really don't need it here due to fallback op
|
||||
else if (quality == 4)
|
||||
dcb(iterations, dcb_enhance);
|
||||
|
||||
else if (quality == 11)
|
||||
dht_interpolate();
|
||||
else if (quality == 12)
|
||||
aahd_interpolate();
|
||||
// fallback to AHD
|
||||
else
|
||||
{
|
||||
ahd_interpolate();
|
||||
imgdata.process_warnings |= LIBRAW_WARN_FALLBACK_TO_AHD;
|
||||
}
|
||||
|
||||
SET_PROC_FLAG(LIBRAW_PROGRESS_INTERPOLATE);
|
||||
}
|
||||
if (IO.mix_green)
|
||||
{
|
||||
for (P1.colors = 3, i = 0; i < S.height * S.width; i++)
|
||||
imgdata.image[i][1] = (imgdata.image[i][1] + imgdata.image[i][3]) >> 1;
|
||||
SET_PROC_FLAG(LIBRAW_PROGRESS_MIX_GREEN);
|
||||
}
|
||||
|
||||
if (callbacks.post_interpolate_cb)
|
||||
(callbacks.post_interpolate_cb)(this);
|
||||
else if (!P1.is_foveon && P1.colors == 3 && O.med_passes > 0)
|
||||
{
|
||||
median_filter();
|
||||
SET_PROC_FLAG(LIBRAW_PROGRESS_MEDIAN_FILTER);
|
||||
}
|
||||
|
||||
if (O.highlight == 2)
|
||||
{
|
||||
blend_highlights();
|
||||
SET_PROC_FLAG(LIBRAW_PROGRESS_HIGHLIGHTS);
|
||||
}
|
||||
|
||||
if (O.highlight > 2)
|
||||
{
|
||||
recover_highlights();
|
||||
SET_PROC_FLAG(LIBRAW_PROGRESS_HIGHLIGHTS);
|
||||
}
|
||||
|
||||
if (O.use_fuji_rotate)
|
||||
{
|
||||
fuji_rotate();
|
||||
SET_PROC_FLAG(LIBRAW_PROGRESS_FUJI_ROTATE);
|
||||
}
|
||||
|
||||
if (!libraw_internal_data.output_data.histogram)
|
||||
{
|
||||
libraw_internal_data.output_data.histogram =
|
||||
(int(*)[LIBRAW_HISTOGRAM_SIZE])malloc(
|
||||
sizeof(*libraw_internal_data.output_data.histogram) * 4);
|
||||
}
|
||||
#ifndef NO_LCMS
|
||||
if (O.camera_profile)
|
||||
{
|
||||
apply_profile(O.camera_profile, O.output_profile);
|
||||
SET_PROC_FLAG(LIBRAW_PROGRESS_APPLY_PROFILE);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (callbacks.pre_converttorgb_cb)
|
||||
(callbacks.pre_converttorgb_cb)(this);
|
||||
|
||||
convert_to_rgb();
|
||||
SET_PROC_FLAG(LIBRAW_PROGRESS_CONVERT_RGB);
|
||||
|
||||
if (callbacks.post_converttorgb_cb)
|
||||
(callbacks.post_converttorgb_cb)(this);
|
||||
|
||||
if (O.use_fuji_rotate)
|
||||
{
|
||||
stretch();
|
||||
SET_PROC_FLAG(LIBRAW_PROGRESS_STRETCH);
|
||||
}
|
||||
O.four_color_rgb = save_4color; // also, restore
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch (const std::bad_alloc&)
|
||||
{
|
||||
recycle();
|
||||
return LIBRAW_UNSUFFICIENT_MEMORY;
|
||||
}
|
||||
catch (const LibRaw_exceptions& err)
|
||||
{
|
||||
EXCEPTION_HANDLER(err);
|
||||
}
|
||||
}
|
292
rtengine/libraw/src/postprocessing/mem_image.cpp
Normal file
292
rtengine/libraw/src/postprocessing/mem_image.cpp
Normal file
@@ -0,0 +1,292 @@
|
||||
/* -*- C++ -*-
|
||||
* Copyright 2019-2021 LibRaw LLC (info@libraw.org)
|
||||
*
|
||||
LibRaw is free software; you can redistribute it and/or modify
|
||||
it under the terms of the one of two licenses as you choose:
|
||||
|
||||
1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
|
||||
(See file LICENSE.LGPL provided in LibRaw distribution archive for details).
|
||||
|
||||
2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
|
||||
(See file LICENSE.CDDL provided in LibRaw distribution archive for details).
|
||||
|
||||
*/
|
||||
|
||||
#include "../../internal/libraw_cxx_defs.h"
|
||||
|
||||
libraw_processed_image_t *LibRaw::dcraw_make_mem_thumb(int *errcode)
|
||||
{
|
||||
if (!T.thumb)
|
||||
{
|
||||
if (!ID.toffset && !(imgdata.thumbnail.tlength > 0 &&
|
||||
load_raw == &LibRaw::broadcom_load_raw) // RPi
|
||||
)
|
||||
{
|
||||
if (errcode)
|
||||
*errcode = LIBRAW_NO_THUMBNAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (errcode)
|
||||
*errcode = LIBRAW_OUT_OF_ORDER_CALL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (T.tlength < 64u)
|
||||
{
|
||||
if (errcode)
|
||||
*errcode = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (INT64(T.tlength) > 1024ULL * 1024ULL * LIBRAW_MAX_THUMBNAIL_MB)
|
||||
{
|
||||
if (errcode)
|
||||
*errcode = LIBRAW_TOO_BIG;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (T.tformat == LIBRAW_THUMBNAIL_BITMAP)
|
||||
{
|
||||
libraw_processed_image_t *ret = (libraw_processed_image_t *)::malloc(
|
||||
sizeof(libraw_processed_image_t) + T.tlength);
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
if (errcode)
|
||||
*errcode = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(ret, 0, sizeof(libraw_processed_image_t));
|
||||
ret->type = LIBRAW_IMAGE_BITMAP;
|
||||
ret->height = T.theight;
|
||||
ret->width = T.twidth;
|
||||
if (T.tcolors > 0 && T.tcolors < 4)
|
||||
ret->colors = T.tcolors;
|
||||
else
|
||||
ret->colors = 3; // defaults
|
||||
ret->bits = 8;
|
||||
ret->data_size = T.tlength;
|
||||
memmove(ret->data, T.thumb, T.tlength);
|
||||
if (errcode)
|
||||
*errcode = 0;
|
||||
return ret;
|
||||
}
|
||||
else if (T.tformat == LIBRAW_THUMBNAIL_JPEG)
|
||||
{
|
||||
ushort exif[5];
|
||||
int mk_exif = 0;
|
||||
if (strcmp(T.thumb + 6, "Exif"))
|
||||
mk_exif = 1;
|
||||
|
||||
int dsize = T.tlength + mk_exif * (sizeof(exif) + sizeof(tiff_hdr));
|
||||
|
||||
libraw_processed_image_t *ret = (libraw_processed_image_t *)::malloc(
|
||||
sizeof(libraw_processed_image_t) + dsize);
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
if (errcode)
|
||||
*errcode = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(ret, 0, sizeof(libraw_processed_image_t));
|
||||
|
||||
ret->type = LIBRAW_IMAGE_JPEG;
|
||||
ret->data_size = dsize;
|
||||
|
||||
ret->data[0] = 0xff;
|
||||
ret->data[1] = 0xd8;
|
||||
if (mk_exif)
|
||||
{
|
||||
struct tiff_hdr th;
|
||||
memcpy(exif, "\xff\xe1 Exif\0\0", 10);
|
||||
exif[1] = htons(8 + sizeof th);
|
||||
memmove(ret->data + 2, exif, sizeof(exif));
|
||||
tiff_head(&th, 0);
|
||||
memmove(ret->data + (2 + sizeof(exif)), &th, sizeof(th));
|
||||
memmove(ret->data + (2 + sizeof(exif) + sizeof(th)), T.thumb + 2,
|
||||
T.tlength - 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
memmove(ret->data + 2, T.thumb + 2, T.tlength - 2);
|
||||
}
|
||||
if (errcode)
|
||||
*errcode = 0;
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (errcode)
|
||||
*errcode = LIBRAW_UNSUPPORTED_THUMBNAIL;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// jlb
|
||||
// macros for copying pixels to either BGR or RGB formats
|
||||
#define FORBGR for (c = P1.colors - 1; c >= 0; c--)
|
||||
#define FORRGB for (c = 0; c < P1.colors; c++)
|
||||
|
||||
void LibRaw::get_mem_image_format(int *width, int *height, int *colors,
|
||||
int *bps) const
|
||||
|
||||
{
|
||||
*width = S.width;
|
||||
*height = S.height;
|
||||
if (imgdata.progress_flags < LIBRAW_PROGRESS_FUJI_ROTATE)
|
||||
{
|
||||
if (O.use_fuji_rotate)
|
||||
{
|
||||
if (IO.fuji_width)
|
||||
{
|
||||
int fuji_width = (IO.fuji_width - 1 + IO.shrink) >> IO.shrink;
|
||||
*width = (ushort)(fuji_width / sqrt(0.5));
|
||||
*height = (ushort)((*height - fuji_width) / sqrt(0.5));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (S.pixel_aspect < 0.995)
|
||||
*height = (ushort)(*height / S.pixel_aspect + 0.5);
|
||||
if (S.pixel_aspect > 1.005)
|
||||
*width = (ushort)(*width * S.pixel_aspect + 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (S.flip & 4)
|
||||
{
|
||||
std::swap(*width, *height);
|
||||
}
|
||||
*colors = P1.colors;
|
||||
*bps = O.output_bps;
|
||||
}
|
||||
|
||||
int LibRaw::copy_mem_image(void *scan0, int stride, int bgr)
|
||||
|
||||
{
|
||||
// the image memory pointed to by scan0 is assumed to be in the format
|
||||
// returned by get_mem_image_format
|
||||
if ((imgdata.progress_flags & LIBRAW_PROGRESS_THUMB_MASK) <
|
||||
LIBRAW_PROGRESS_PRE_INTERPOLATE)
|
||||
return LIBRAW_OUT_OF_ORDER_CALL;
|
||||
|
||||
if (libraw_internal_data.output_data.histogram)
|
||||
{
|
||||
int perc, val, total, t_white = 0x2000, c;
|
||||
perc = S.width * S.height * O.auto_bright_thr;
|
||||
if (IO.fuji_width)
|
||||
perc /= 2;
|
||||
if (!((O.highlight & ~2) || O.no_auto_bright))
|
||||
for (t_white = c = 0; c < P1.colors; c++)
|
||||
{
|
||||
for (val = 0x2000, total = 0; --val > 32;)
|
||||
if ((total += libraw_internal_data.output_data.histogram[c][val]) >
|
||||
perc)
|
||||
break;
|
||||
if (t_white < val)
|
||||
t_white = val;
|
||||
}
|
||||
gamma_curve(O.gamm[0], O.gamm[1], 2, (t_white << 3) / O.bright);
|
||||
}
|
||||
|
||||
int s_iheight = S.iheight;
|
||||
int s_iwidth = S.iwidth;
|
||||
int s_width = S.width;
|
||||
int s_hwight = S.height;
|
||||
|
||||
S.iheight = S.height;
|
||||
S.iwidth = S.width;
|
||||
|
||||
if (S.flip & 4)
|
||||
SWAP(S.height, S.width);
|
||||
uchar *ppm;
|
||||
ushort *ppm2;
|
||||
int c, row, col, soff, rstep, cstep;
|
||||
|
||||
soff = flip_index(0, 0);
|
||||
cstep = flip_index(0, 1) - soff;
|
||||
rstep = flip_index(1, 0) - flip_index(0, S.width);
|
||||
|
||||
for (row = 0; row < S.height; row++, soff += rstep)
|
||||
{
|
||||
uchar *bufp = ((uchar *)scan0) + row * stride;
|
||||
ppm2 = (ushort *)(ppm = bufp);
|
||||
// keep trivial decisions in the outer loop for speed
|
||||
if (bgr)
|
||||
{
|
||||
if (O.output_bps == 8)
|
||||
{
|
||||
for (col = 0; col < S.width; col++, soff += cstep)
|
||||
FORBGR *ppm++ = imgdata.color.curve[imgdata.image[soff][c]] >> 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (col = 0; col < S.width; col++, soff += cstep)
|
||||
FORBGR *ppm2++ = imgdata.color.curve[imgdata.image[soff][c]];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (O.output_bps == 8)
|
||||
{
|
||||
for (col = 0; col < S.width; col++, soff += cstep)
|
||||
FORRGB *ppm++ = imgdata.color.curve[imgdata.image[soff][c]] >> 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (col = 0; col < S.width; col++, soff += cstep)
|
||||
FORRGB *ppm2++ = imgdata.color.curve[imgdata.image[soff][c]];
|
||||
}
|
||||
}
|
||||
|
||||
// bufp += stride; // go to the next line
|
||||
}
|
||||
|
||||
S.iheight = s_iheight;
|
||||
S.iwidth = s_iwidth;
|
||||
S.width = s_width;
|
||||
S.height = s_hwight;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#undef FORBGR
|
||||
#undef FORRGB
|
||||
|
||||
libraw_processed_image_t *LibRaw::dcraw_make_mem_image(int *errcode)
|
||||
|
||||
{
|
||||
int width, height, colors, bps;
|
||||
get_mem_image_format(&width, &height, &colors, &bps);
|
||||
int stride = width * (bps / 8) * colors;
|
||||
unsigned ds = height * stride;
|
||||
libraw_processed_image_t *ret = (libraw_processed_image_t *)::malloc(
|
||||
sizeof(libraw_processed_image_t) + ds);
|
||||
if (!ret)
|
||||
{
|
||||
if (errcode)
|
||||
*errcode = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
memset(ret, 0, sizeof(libraw_processed_image_t));
|
||||
|
||||
// metadata init
|
||||
ret->type = LIBRAW_IMAGE_BITMAP;
|
||||
ret->height = height;
|
||||
ret->width = width;
|
||||
ret->colors = colors;
|
||||
ret->bits = bps;
|
||||
ret->data_size = ds;
|
||||
copy_mem_image(ret->data, stride, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void LibRaw::dcraw_clear_mem(libraw_processed_image_t *p)
|
||||
{
|
||||
if (p)
|
||||
::free(p);
|
||||
}
|
406
rtengine/libraw/src/postprocessing/postprocessing_aux.cpp
Normal file
406
rtengine/libraw/src/postprocessing/postprocessing_aux.cpp
Normal file
@@ -0,0 +1,406 @@
|
||||
/* -*- C++ -*-
|
||||
* Copyright 2019-2021 LibRaw LLC (info@libraw.org)
|
||||
*
|
||||
LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder,
|
||||
dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net.
|
||||
LibRaw do not use RESTRICTED code from dcraw.c
|
||||
|
||||
LibRaw is free software; you can redistribute it and/or modify
|
||||
it under the terms of the one of two licenses as you choose:
|
||||
|
||||
1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
|
||||
(See file LICENSE.LGPL provided in LibRaw distribution archive for details).
|
||||
|
||||
2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
|
||||
(See file LICENSE.CDDL provided in LibRaw distribution archive for details).
|
||||
|
||||
*/
|
||||
|
||||
#include "../../internal/dcraw_defs.h"
|
||||
|
||||
void LibRaw::hat_transform(float *temp, float *base, int st, int size, int sc)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < sc; i++)
|
||||
temp[i] = 2 * base[st * i] + base[st * (sc - i)] + base[st * (i + sc)];
|
||||
for (; i + sc < size; i++)
|
||||
temp[i] = 2 * base[st * i] + base[st * (i - sc)] + base[st * (i + sc)];
|
||||
for (; i < size; i++)
|
||||
temp[i] = 2 * base[st * i] + base[st * (i - sc)] +
|
||||
base[st * (2 * size - 2 - (i + sc))];
|
||||
}
|
||||
|
||||
#if !defined(LIBRAW_USE_OPENMP)
|
||||
void LibRaw::wavelet_denoise()
|
||||
{
|
||||
float *fimg = 0, *temp, thold, mul[2], avg, diff;
|
||||
int scale = 1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2];
|
||||
ushort *window[4];
|
||||
static const float noise[] = {0.8002f, 0.2735f, 0.1202f, 0.0585f,
|
||||
0.0291f, 0.0152f, 0.0080f, 0.0044f};
|
||||
|
||||
|
||||
while (maximum << scale < 0x10000)
|
||||
scale++;
|
||||
maximum <<= --scale;
|
||||
black <<= scale;
|
||||
FORC4 cblack[c] <<= scale;
|
||||
if ((size = iheight * iwidth) < 0x15550000)
|
||||
fimg = (float *)malloc((size * 3 + iheight + iwidth + 128) * sizeof *fimg);
|
||||
temp = fimg + size * 3;
|
||||
if ((nc = colors) == 3 && filters)
|
||||
nc++;
|
||||
FORC(nc)
|
||||
{ /* denoise R,G1,B,G3 individually */
|
||||
for (i = 0; i < size; i++)
|
||||
fimg[i] = 256 * sqrt((double)(image[i][c] << scale));
|
||||
for (hpass = lev = 0; lev < 5; lev++)
|
||||
{
|
||||
lpass = size * ((lev & 1) + 1);
|
||||
for (row = 0; row < iheight; row++)
|
||||
{
|
||||
hat_transform(temp, fimg + hpass + row * iwidth, 1, iwidth, 1 << lev);
|
||||
for (col = 0; col < iwidth; col++)
|
||||
fimg[lpass + row * iwidth + col] = temp[col] * 0.25;
|
||||
}
|
||||
for (col = 0; col < iwidth; col++)
|
||||
{
|
||||
hat_transform(temp, fimg + lpass + col, iwidth, iheight, 1 << lev);
|
||||
for (row = 0; row < iheight; row++)
|
||||
fimg[lpass + row * iwidth + col] = temp[row] * 0.25;
|
||||
}
|
||||
thold = threshold * noise[lev];
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
fimg[hpass + i] -= fimg[lpass + i];
|
||||
if (fimg[hpass + i] < -thold)
|
||||
fimg[hpass + i] += thold;
|
||||
else if (fimg[hpass + i] > thold)
|
||||
fimg[hpass + i] -= thold;
|
||||
else
|
||||
fimg[hpass + i] = 0;
|
||||
if (hpass)
|
||||
fimg[i] += fimg[hpass + i];
|
||||
}
|
||||
hpass = lpass;
|
||||
}
|
||||
for (i = 0; i < size; i++)
|
||||
image[i][c] = CLIP(SQR(fimg[i] + fimg[lpass + i]) / 0x10000);
|
||||
}
|
||||
if (filters && colors == 3)
|
||||
{ /* pull G1 and G3 closer together */
|
||||
for (row = 0; row < 2; row++)
|
||||
{
|
||||
mul[row] = 0.125 * pre_mul[FC(row + 1, 0) | 1] / pre_mul[FC(row, 0) | 1];
|
||||
blk[row] = cblack[FC(row, 0) | 1];
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
window[i] = (ushort *)fimg + width * i;
|
||||
for (wlast = -1, row = 1; row < height - 1; row++)
|
||||
{
|
||||
while (wlast < row + 1)
|
||||
{
|
||||
for (wlast++, i = 0; i < 4; i++)
|
||||
window[(i + 3) & 3] = window[i];
|
||||
for (col = FC(wlast, 1) & 1; col < width; col += 2)
|
||||
window[2][col] = BAYER(wlast, col);
|
||||
}
|
||||
thold = threshold / 512;
|
||||
for (col = (FC(row, 0) & 1) + 1; col < width - 1; col += 2)
|
||||
{
|
||||
avg = (window[0][col - 1] + window[0][col + 1] + window[2][col - 1] +
|
||||
window[2][col + 1] - blk[~row & 1] * 4) *
|
||||
mul[row & 1] +
|
||||
(window[1][col] + blk[row & 1]) * 0.5;
|
||||
avg = avg < 0 ? 0 : sqrt(avg);
|
||||
diff = sqrt((double)BAYER(row, col)) - avg;
|
||||
if (diff < -thold)
|
||||
diff += thold;
|
||||
else if (diff > thold)
|
||||
diff -= thold;
|
||||
else
|
||||
diff = 0;
|
||||
BAYER(row, col) = CLIP(SQR(avg + diff) + 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(fimg);
|
||||
}
|
||||
#else /* LIBRAW_USE_OPENMP */
|
||||
void LibRaw::wavelet_denoise()
|
||||
{
|
||||
float *fimg = 0, *temp, thold, mul[2], avg, diff;
|
||||
int scale = 1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2];
|
||||
ushort *window[4];
|
||||
static const float noise[] = {0.8002, 0.2735, 0.1202, 0.0585,
|
||||
0.0291, 0.0152, 0.0080, 0.0044};
|
||||
|
||||
while (maximum << scale < 0x10000)
|
||||
scale++;
|
||||
maximum <<= --scale;
|
||||
black <<= scale;
|
||||
FORC4 cblack[c] <<= scale;
|
||||
if ((size = iheight * iwidth) < 0x15550000)
|
||||
fimg = (float *)malloc((size * 3 + iheight + iwidth) * sizeof *fimg);
|
||||
temp = fimg + size * 3;
|
||||
if ((nc = colors) == 3 && filters)
|
||||
nc++;
|
||||
#pragma omp parallel default(shared) private( \
|
||||
i, col, row, thold, lev, lpass, hpass, temp, c) firstprivate(scale, size)
|
||||
{
|
||||
temp = (float *)malloc((iheight + iwidth) * sizeof *fimg);
|
||||
FORC(nc)
|
||||
{ /* denoise R,G1,B,G3 individually */
|
||||
#pragma omp for
|
||||
for (i = 0; i < size; i++)
|
||||
fimg[i] = 256 * sqrt((double)(image[i][c] << scale));
|
||||
for (hpass = lev = 0; lev < 5; lev++)
|
||||
{
|
||||
lpass = size * ((lev & 1) + 1);
|
||||
#pragma omp for
|
||||
for (row = 0; row < iheight; row++)
|
||||
{
|
||||
hat_transform(temp, fimg + hpass + row * iwidth, 1, iwidth, 1 << lev);
|
||||
for (col = 0; col < iwidth; col++)
|
||||
fimg[lpass + row * iwidth + col] = temp[col] * 0.25;
|
||||
}
|
||||
#pragma omp for
|
||||
for (col = 0; col < iwidth; col++)
|
||||
{
|
||||
hat_transform(temp, fimg + lpass + col, iwidth, iheight, 1 << lev);
|
||||
for (row = 0; row < iheight; row++)
|
||||
fimg[lpass + row * iwidth + col] = temp[row] * 0.25;
|
||||
}
|
||||
thold = threshold * noise[lev];
|
||||
#pragma omp for
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
fimg[hpass + i] -= fimg[lpass + i];
|
||||
if (fimg[hpass + i] < -thold)
|
||||
fimg[hpass + i] += thold;
|
||||
else if (fimg[hpass + i] > thold)
|
||||
fimg[hpass + i] -= thold;
|
||||
else
|
||||
fimg[hpass + i] = 0;
|
||||
if (hpass)
|
||||
fimg[i] += fimg[hpass + i];
|
||||
}
|
||||
hpass = lpass;
|
||||
}
|
||||
#pragma omp for
|
||||
for (i = 0; i < size; i++)
|
||||
image[i][c] = CLIP(SQR(fimg[i] + fimg[lpass + i]) / 0x10000);
|
||||
}
|
||||
free(temp);
|
||||
} /* end omp parallel */
|
||||
/* the following loops are hard to parallelize, no idea yes,
|
||||
* problem is wlast which is carrying dependency
|
||||
* second part should be easier, but did not yet get it right.
|
||||
*/
|
||||
if (filters && colors == 3)
|
||||
{ /* pull G1 and G3 closer together */
|
||||
for (row = 0; row < 2; row++)
|
||||
{
|
||||
mul[row] = 0.125 * pre_mul[FC(row + 1, 0) | 1] / pre_mul[FC(row, 0) | 1];
|
||||
blk[row] = cblack[FC(row, 0) | 1];
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
window[i] = (ushort *)fimg + width * i;
|
||||
for (wlast = -1, row = 1; row < height - 1; row++)
|
||||
{
|
||||
while (wlast < row + 1)
|
||||
{
|
||||
for (wlast++, i = 0; i < 4; i++)
|
||||
window[(i + 3) & 3] = window[i];
|
||||
for (col = FC(wlast, 1) & 1; col < width; col += 2)
|
||||
window[2][col] = BAYER(wlast, col);
|
||||
}
|
||||
thold = threshold / 512;
|
||||
for (col = (FC(row, 0) & 1) + 1; col < width - 1; col += 2)
|
||||
{
|
||||
avg = (window[0][col - 1] + window[0][col + 1] + window[2][col - 1] +
|
||||
window[2][col + 1] - blk[~row & 1] * 4) *
|
||||
mul[row & 1] +
|
||||
(window[1][col] + blk[row & 1]) * 0.5;
|
||||
avg = avg < 0 ? 0 : sqrt(avg);
|
||||
diff = sqrt((double)BAYER(row, col)) - avg;
|
||||
if (diff < -thold)
|
||||
diff += thold;
|
||||
else if (diff > thold)
|
||||
diff -= thold;
|
||||
else
|
||||
diff = 0;
|
||||
BAYER(row, col) = CLIP(SQR(avg + diff) + 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(fimg);
|
||||
}
|
||||
|
||||
#endif
|
||||
void LibRaw::median_filter()
|
||||
{
|
||||
ushort(*pix)[4];
|
||||
int pass, c, i, j, k, med[9];
|
||||
static const uchar opt[] = /* Optimal 9-element median search */
|
||||
{1, 2, 4, 5, 7, 8, 0, 1, 3, 4, 6, 7, 1, 2, 4, 5, 7, 8, 0,
|
||||
3, 5, 8, 4, 7, 3, 6, 1, 4, 2, 5, 4, 7, 4, 2, 6, 4, 4, 2};
|
||||
|
||||
for (pass = 1; pass <= med_passes; pass++)
|
||||
{
|
||||
RUN_CALLBACK(LIBRAW_PROGRESS_MEDIAN_FILTER, pass - 1, med_passes);
|
||||
for (c = 0; c < 3; c += 2)
|
||||
{
|
||||
for (pix = image; pix < image + width * height; pix++)
|
||||
pix[0][3] = pix[0][c];
|
||||
for (pix = image + width; pix < image + width * (height - 1); pix++)
|
||||
{
|
||||
if ((pix - image + 1) % width < 2)
|
||||
continue;
|
||||
for (k = 0, i = -width; i <= width; i += width)
|
||||
for (j = i - 1; j <= i + 1; j++)
|
||||
med[k++] = pix[j][3] - pix[j][1];
|
||||
for (i = 0; i < int(sizeof opt); i += 2)
|
||||
if (med[opt[i]] > med[opt[i + 1]])
|
||||
SWAP(med[opt[i]], med[opt[i + 1]]);
|
||||
pix[0][c] = CLIP(med[4] + pix[0][1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LibRaw::blend_highlights()
|
||||
{
|
||||
int clip = INT_MAX, row, col, c, i, j;
|
||||
static const float trans[2][4][4] = {
|
||||
{{1, 1, 1}, {1.7320508f, -1.7320508f, 0}, {-1, -1, 2}},
|
||||
{{1, 1, 1, 1}, {1, -1, 1, -1}, {1, 1, -1, -1}, {1, -1, -1, 1}}};
|
||||
static const float itrans[2][4][4] = {
|
||||
{{1, 0.8660254f, -0.5}, {1, -0.8660254f, -0.5}, {1, 0, 1}},
|
||||
{{1, 1, 1, 1}, {1, -1, 1, -1}, {1, 1, -1, -1}, {1, -1, -1, 1}}};
|
||||
float cam[2][4], lab[2][4], sum[2], chratio;
|
||||
|
||||
if ((unsigned)(colors - 3) > 1)
|
||||
return;
|
||||
RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS, 0, 2);
|
||||
FORCC if (clip > (i = 65535 * pre_mul[c])) clip = i;
|
||||
for (row = 0; row < height; row++)
|
||||
for (col = 0; col < width; col++)
|
||||
{
|
||||
FORCC if (image[row * width + col][c] > clip) break;
|
||||
if (c == colors)
|
||||
continue;
|
||||
FORCC
|
||||
{
|
||||
cam[0][c] = image[row * width + col][c];
|
||||
cam[1][c] = MIN(cam[0][c], clip);
|
||||
}
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
FORCC for (lab[i][c] = j = 0; j < colors; j++) lab[i][c] +=
|
||||
trans[colors - 3][c][j] * cam[i][j];
|
||||
for (sum[i] = 0, c = 1; c < colors; c++)
|
||||
sum[i] += SQR(lab[i][c]);
|
||||
}
|
||||
chratio = sqrt(sum[1] / sum[0]);
|
||||
for (c = 1; c < colors; c++)
|
||||
lab[0][c] *= chratio;
|
||||
FORCC for (cam[0][c] = j = 0; j < colors; j++) cam[0][c] +=
|
||||
itrans[colors - 3][c][j] * lab[0][j];
|
||||
FORCC image[row * width + col][c] = cam[0][c] / colors;
|
||||
}
|
||||
RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS, 1, 2);
|
||||
}
|
||||
|
||||
#define SCALE (4 >> shrink)
|
||||
void LibRaw::recover_highlights()
|
||||
{
|
||||
float *map, sum, wgt, grow;
|
||||
int hsat[4], count, spread, change, val, i;
|
||||
unsigned high, wide, mrow, mcol, row, col, kc, c, d, y, x;
|
||||
ushort *pixel;
|
||||
static const signed char dir[8][2] = {{-1, -1}, {-1, 0}, {-1, 1}, {0, 1},
|
||||
{1, 1}, {1, 0}, {1, -1}, {0, -1}};
|
||||
|
||||
grow = pow(2.0, 4 - highlight);
|
||||
FORC(unsigned(colors)) hsat[c] = 32000 * pre_mul[c];
|
||||
for (kc = 0, c = 1; c < (unsigned)colors; c++)
|
||||
if (pre_mul[kc] < pre_mul[c])
|
||||
kc = c;
|
||||
high = height / SCALE;
|
||||
wide = width / SCALE;
|
||||
map = (float *)calloc(high, wide * sizeof *map);
|
||||
FORC(unsigned(colors)) if (c != kc)
|
||||
{
|
||||
RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS, c - 1, colors - 1);
|
||||
memset(map, 0, high * wide * sizeof *map);
|
||||
for (mrow = 0; mrow < high; mrow++)
|
||||
for (mcol = 0; mcol < wide; mcol++)
|
||||
{
|
||||
sum = wgt = count = 0;
|
||||
for (row = mrow * SCALE; row < (mrow + 1) * SCALE; row++)
|
||||
for (col = mcol * SCALE; col < (mcol + 1) * SCALE; col++)
|
||||
{
|
||||
pixel = image[row * width + col];
|
||||
if (pixel[c] / hsat[c] == 1 && pixel[kc] > 24000)
|
||||
{
|
||||
sum += pixel[c];
|
||||
wgt += pixel[kc];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count == SCALE * SCALE)
|
||||
map[mrow * wide + mcol] = sum / wgt;
|
||||
}
|
||||
for (spread = 32 / grow; spread--;)
|
||||
{
|
||||
for (mrow = 0; mrow < high; mrow++)
|
||||
for (mcol = 0; mcol < wide; mcol++)
|
||||
{
|
||||
if (map[mrow * wide + mcol])
|
||||
continue;
|
||||
sum = count = 0;
|
||||
for (d = 0; d < 8; d++)
|
||||
{
|
||||
y = mrow + dir[d][0];
|
||||
x = mcol + dir[d][1];
|
||||
if (y < high && x < wide && map[y * wide + x] > 0)
|
||||
{
|
||||
sum += (1 + (d & 1)) * map[y * wide + x];
|
||||
count += 1 + (d & 1);
|
||||
}
|
||||
}
|
||||
if (count > 3)
|
||||
map[mrow * wide + mcol] = -(sum + grow) / (count + grow);
|
||||
}
|
||||
for (change = i = 0; i < int(high * wide); i++)
|
||||
if (map[i] < 0)
|
||||
{
|
||||
map[i] = -map[i];
|
||||
change = 1;
|
||||
}
|
||||
if (!change)
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < int(high * wide); i++)
|
||||
if (map[i] == 0)
|
||||
map[i] = 1;
|
||||
for (mrow = 0; mrow < high; mrow++)
|
||||
for (mcol = 0; mcol < wide; mcol++)
|
||||
{
|
||||
for (row = mrow * SCALE; row < (mrow + 1) * SCALE; row++)
|
||||
for (col = mcol * SCALE; col < (mcol + 1) * SCALE; col++)
|
||||
{
|
||||
pixel = image[row * width + col];
|
||||
if (pixel[c] / hsat[c] > 1)
|
||||
{
|
||||
val = pixel[kc] * map[mrow * wide + mcol];
|
||||
if (pixel[c] < val)
|
||||
pixel[c] = CLIP(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(map);
|
||||
}
|
||||
#undef SCALE
|
31
rtengine/libraw/src/postprocessing/postprocessing_ph.cpp
Normal file
31
rtengine/libraw/src/postprocessing/postprocessing_ph.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
/* -*- C++ -*-
|
||||
* Copyright 2019-2021 LibRaw LLC (info@libraw.org)
|
||||
*
|
||||
Placeholder functions to build LibRaw w/o postprocessing tools
|
||||
|
||||
LibRaw is free software; you can redistribute it and/or modify
|
||||
it under the terms of the one of two licenses as you choose:
|
||||
|
||||
1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
|
||||
(See file LICENSE.LGPL provided in LibRaw distribution archive for details).
|
||||
|
||||
2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
|
||||
(See file LICENSE.CDDL provided in LibRaw distribution archive for details).
|
||||
|
||||
*/
|
||||
|
||||
#include "../../internal/libraw_cxx_defs.h"
|
||||
|
||||
int LibRaw::dcraw_process(void)
|
||||
{
|
||||
return LIBRAW_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
void LibRaw::fuji_rotate() {}
|
||||
void LibRaw::convert_to_rgb_loop(float /*out_cam*/ [3][4]) {}
|
||||
libraw_processed_image_t *LibRaw::dcraw_make_mem_image(int *) {
|
||||
return NULL;
|
||||
}
|
||||
libraw_processed_image_t *LibRaw::dcraw_make_mem_thumb(int *){ return NULL;}
|
||||
void LibRaw::lin_interpolate_loop(int * /*code*/, int /*size*/) {}
|
||||
void LibRaw::scale_colors_loop(float /*scale_mul*/[4]) {}
|
190
rtengine/libraw/src/postprocessing/postprocessing_utils.cpp
Normal file
190
rtengine/libraw/src/postprocessing/postprocessing_utils.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
/* -*- C++ -*-
|
||||
* Copyright 2019-2021 LibRaw LLC (info@libraw.org)
|
||||
*
|
||||
LibRaw is free software; you can redistribute it and/or modify
|
||||
it under the terms of the one of two licenses as you choose:
|
||||
|
||||
1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
|
||||
(See file LICENSE.LGPL provided in LibRaw distribution archive for details).
|
||||
|
||||
2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
|
||||
(See file LICENSE.CDDL provided in LibRaw distribution archive for details).
|
||||
|
||||
*/
|
||||
|
||||
#include "../../internal/libraw_cxx_defs.h"
|
||||
|
||||
#define TBLN 65535
|
||||
|
||||
void LibRaw::exp_bef(float shift, float smooth)
|
||||
{
|
||||
// params limits
|
||||
if (shift > 8)
|
||||
shift = 8;
|
||||
if (shift < 0.25)
|
||||
shift = 0.25;
|
||||
if (smooth < 0.0)
|
||||
smooth = 0.0;
|
||||
if (smooth > 1.0)
|
||||
smooth = 1.0;
|
||||
|
||||
unsigned short *lut = (ushort *)malloc((TBLN + 1) * sizeof(unsigned short));
|
||||
|
||||
if (shift <= 1.0)
|
||||
{
|
||||
for (int i = 0; i <= TBLN; i++)
|
||||
lut[i] = (unsigned short)((float)i * shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
float x1, x2, y1, y2;
|
||||
|
||||
float cstops = log(shift) / log(2.0f);
|
||||
float room = cstops * 2;
|
||||
float roomlin = powf(2.0f, room);
|
||||
x2 = (float)TBLN;
|
||||
x1 = (x2 + 1) / roomlin - 1;
|
||||
y1 = x1 * shift;
|
||||
y2 = x2 * (1 + (1 - smooth) * (shift - 1));
|
||||
float sq3x = powf(x1 * x1 * x2, 1.0f / 3.0f);
|
||||
float B = (y2 - y1 + shift * (3 * x1 - 3.0f * sq3x)) /
|
||||
(x2 + 2.0f * x1 - 3.0f * sq3x);
|
||||
float A = (shift - B) * 3.0f * powf(x1 * x1, 1.0f / 3.0f);
|
||||
float CC = y2 - A * powf(x2, 1.0f / 3.0f) - B * x2;
|
||||
for (int i = 0; i <= TBLN; i++)
|
||||
{
|
||||
float X = (float)i;
|
||||
float Y = A * powf(X, 1.0f / 3.0f) + B * X + CC;
|
||||
if (i < x1)
|
||||
lut[i] = (unsigned short)((float)i * shift);
|
||||
else
|
||||
lut[i] = Y < 0 ? 0 : (Y > TBLN ? TBLN : (unsigned short)(Y));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < S.height * S.width; i++)
|
||||
{
|
||||
imgdata.image[i][0] = lut[imgdata.image[i][0]];
|
||||
imgdata.image[i][1] = lut[imgdata.image[i][1]];
|
||||
imgdata.image[i][2] = lut[imgdata.image[i][2]];
|
||||
imgdata.image[i][3] = lut[imgdata.image[i][3]];
|
||||
}
|
||||
|
||||
if (C.data_maximum <= TBLN)
|
||||
C.data_maximum = lut[C.data_maximum];
|
||||
if (C.maximum <= TBLN)
|
||||
C.maximum = lut[C.maximum];
|
||||
free(lut);
|
||||
}
|
||||
|
||||
void LibRaw::convert_to_rgb_loop(float out_cam[3][4])
|
||||
{
|
||||
int row, col, c;
|
||||
float out[3];
|
||||
ushort *img;
|
||||
memset(libraw_internal_data.output_data.histogram, 0,
|
||||
sizeof(int) * LIBRAW_HISTOGRAM_SIZE * 4);
|
||||
if (libraw_internal_data.internal_output_params.raw_color)
|
||||
{
|
||||
for (img = imgdata.image[0], row = 0; row < S.height; row++)
|
||||
{
|
||||
for (col = 0; col < S.width; col++, img += 4)
|
||||
{
|
||||
for (c = 0; c < imgdata.idata.colors; c++)
|
||||
{
|
||||
libraw_internal_data.output_data.histogram[c][img[c] >> 3]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (imgdata.idata.colors == 3)
|
||||
{
|
||||
for (img = imgdata.image[0], row = 0; row < S.height; row++)
|
||||
{
|
||||
for (col = 0; col < S.width; col++, img += 4)
|
||||
{
|
||||
out[0] = out_cam[0][0] * img[0] + out_cam[0][1] * img[1] +
|
||||
out_cam[0][2] * img[2];
|
||||
out[1] = out_cam[1][0] * img[0] + out_cam[1][1] * img[1] +
|
||||
out_cam[1][2] * img[2];
|
||||
out[2] = out_cam[2][0] * img[0] + out_cam[2][1] * img[1] +
|
||||
out_cam[2][2] * img[2];
|
||||
img[0] = CLIP((int)out[0]);
|
||||
img[1] = CLIP((int)out[1]);
|
||||
img[2] = CLIP((int)out[2]);
|
||||
libraw_internal_data.output_data.histogram[0][img[0] >> 3]++;
|
||||
libraw_internal_data.output_data.histogram[1][img[1] >> 3]++;
|
||||
libraw_internal_data.output_data.histogram[2][img[2] >> 3]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (imgdata.idata.colors == 4)
|
||||
{
|
||||
for (img = imgdata.image[0], row = 0; row < S.height; row++)
|
||||
{
|
||||
for (col = 0; col < S.width; col++, img += 4)
|
||||
{
|
||||
out[0] = out_cam[0][0] * img[0] + out_cam[0][1] * img[1] +
|
||||
out_cam[0][2] * img[2] + out_cam[0][3] * img[3];
|
||||
out[1] = out_cam[1][0] * img[0] + out_cam[1][1] * img[1] +
|
||||
out_cam[1][2] * img[2] + out_cam[1][3] * img[3];
|
||||
out[2] = out_cam[2][0] * img[0] + out_cam[2][1] * img[1] +
|
||||
out_cam[2][2] * img[2] + out_cam[2][3] * img[3];
|
||||
img[0] = CLIP((int)out[0]);
|
||||
img[1] = CLIP((int)out[1]);
|
||||
img[2] = CLIP((int)out[2]);
|
||||
libraw_internal_data.output_data.histogram[0][img[0] >> 3]++;
|
||||
libraw_internal_data.output_data.histogram[1][img[1] >> 3]++;
|
||||
libraw_internal_data.output_data.histogram[2][img[2] >> 3]++;
|
||||
libraw_internal_data.output_data.histogram[3][img[3] >> 3]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LibRaw::scale_colors_loop(float scale_mul[4])
|
||||
{
|
||||
unsigned size = S.iheight * S.iwidth;
|
||||
|
||||
if (C.cblack[4] && C.cblack[5])
|
||||
{
|
||||
int val;
|
||||
for (unsigned i = 0; i < size; i++)
|
||||
{
|
||||
for (unsigned c = 0; c < 4; c++)
|
||||
{
|
||||
if (!(val = imgdata.image[i][c])) continue;
|
||||
val -= C.cblack[6 + i / S.iwidth % C.cblack[4] * C.cblack[5] +
|
||||
i % S.iwidth % C.cblack[5]];
|
||||
val -= C.cblack[c];
|
||||
val *= scale_mul[c];
|
||||
imgdata.image[i][c] = CLIP(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (C.cblack[0] || C.cblack[1] || C.cblack[2] || C.cblack[3])
|
||||
{
|
||||
for (unsigned i = 0; i < size; i++)
|
||||
{
|
||||
for (unsigned c = 0; c < 4; c++)
|
||||
{
|
||||
int val = imgdata.image[i][c];
|
||||
if (!val) continue;
|
||||
val -= C.cblack[c];
|
||||
val *= scale_mul[c];
|
||||
imgdata.image[i][c] = CLIP(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // BL is zero
|
||||
{
|
||||
for (unsigned i = 0; i < size; i++)
|
||||
{
|
||||
for (unsigned c = 0; c < 4; c++)
|
||||
{
|
||||
int val = imgdata.image[i][c];
|
||||
val *= scale_mul[c];
|
||||
imgdata.image[i][c] = CLIP(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,308 @@
|
||||
/* -*- C++ -*-
|
||||
* Copyright 2019-2021 LibRaw LLC (info@libraw.org)
|
||||
*
|
||||
LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder,
|
||||
dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net.
|
||||
LibRaw do not use RESTRICTED code from dcraw.c
|
||||
|
||||
LibRaw is free software; you can redistribute it and/or modify
|
||||
it under the terms of the one of two licenses as you choose:
|
||||
|
||||
1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
|
||||
(See file LICENSE.LGPL provided in LibRaw distribution archive for details).
|
||||
|
||||
2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
|
||||
(See file LICENSE.CDDL provided in LibRaw distribution archive for details).
|
||||
|
||||
*/
|
||||
|
||||
#include "../../internal/dcraw_defs.h"
|
||||
|
||||
void LibRaw::convert_to_rgb()
|
||||
{
|
||||
float out_cam[3][4];
|
||||
double num, inverse[3][3];
|
||||
static const double(*out_rgb[])[3] = {
|
||||
LibRaw_constants::rgb_rgb, LibRaw_constants::adobe_rgb,
|
||||
LibRaw_constants::wide_rgb, LibRaw_constants::prophoto_rgb,
|
||||
LibRaw_constants::xyz_rgb, LibRaw_constants::aces_rgb,
|
||||
LibRaw_constants::dcip3d65_rgb, LibRaw_constants::rec2020_rgb};
|
||||
static const char *name[] = {"sRGB", "Adobe RGB (1998)",
|
||||
"WideGamut D65", "ProPhoto D65",
|
||||
"XYZ", "ACES",
|
||||
"DCI-P3 D65", "Rec. 2020"};
|
||||
static const unsigned phead[] = {
|
||||
1024, 0, 0x2100000, 0x6d6e7472, 0x52474220, 0x58595a20, 0,
|
||||
0, 0, 0x61637370, 0, 0, 0x6e6f6e65, 0,
|
||||
0, 0, 0, 0xf6d6, 0x10000, 0xd32d};
|
||||
unsigned pbody[] = {10, 0x63707274, 0, 36, /* cprt */
|
||||
0x64657363, 0, 60, /* desc, len is strlen(longest_string) + 12 */
|
||||
0x77747074, 0, 20, /* wtpt */
|
||||
0x626b7074, 0, 20, /* bkpt */
|
||||
0x72545243, 0, 14, /* rTRC */
|
||||
0x67545243, 0, 14, /* gTRC */
|
||||
0x62545243, 0, 14, /* bTRC */
|
||||
0x7258595a, 0, 20, /* rXYZ */
|
||||
0x6758595a, 0, 20, /* gXYZ */
|
||||
0x6258595a, 0, 20}; /* bXYZ */
|
||||
static const unsigned pwhite[] = {0xf351, 0x10000, 0x116cc};
|
||||
unsigned pcurve[] = {0x63757276, 0, 1, 0x1000000};
|
||||
|
||||
RUN_CALLBACK(LIBRAW_PROGRESS_CONVERT_RGB, 0, 2);
|
||||
|
||||
gamma_curve(gamm[0], gamm[1], 0, 0);
|
||||
memcpy(out_cam, rgb_cam, sizeof out_cam);
|
||||
raw_color |= colors == 1 || output_color < 1 || output_color > 8;
|
||||
if (!raw_color)
|
||||
{
|
||||
size_t prof_desc_len;
|
||||
std::vector<char> prof_desc;
|
||||
int i, j, k;
|
||||
prof_desc_len = snprintf(NULL, 0, "%s gamma %g toe slope %g", name[output_color - 1],
|
||||
floorf(1000.f / gamm[0] + .5f) / 1000.f, floorf(gamm[1] * 1000.0f + .5f) / 1000.f) +
|
||||
1;
|
||||
prof_desc.resize(prof_desc_len);
|
||||
sprintf(prof_desc.data(), "%s gamma %g toe slope %g", name[output_color - 1], floorf(1000.f / gamm[0] + .5f) / 1000.f,
|
||||
floorf(gamm[1] * 1000.0f + .5f) / 1000.f);
|
||||
|
||||
oprof = (unsigned *)calloc(phead[0], 1);
|
||||
memcpy(oprof, phead, sizeof phead);
|
||||
if (output_color == 5)
|
||||
oprof[4] = oprof[5];
|
||||
oprof[0] = 132 + 12 * pbody[0];
|
||||
for (i = 0; i < (int)pbody[0]; i++)
|
||||
{
|
||||
oprof[oprof[0] / 4] = i ? (i > 1 ? 0x58595a20 : 0x64657363) : 0x74657874;
|
||||
pbody[i * 3 + 2] = oprof[0];
|
||||
oprof[0] += (pbody[i * 3 + 3] + 3) & -4;
|
||||
}
|
||||
memcpy(oprof + 32, pbody, sizeof pbody);
|
||||
oprof[pbody[5] / 4 + 2] = unsigned(prof_desc_len + 1);
|
||||
memcpy((char *)oprof + pbody[8] + 8, pwhite, sizeof pwhite);
|
||||
pcurve[3] = (short)(256 / gamm[5] + 0.5) << 16;
|
||||
for (i = 4; i < 7; i++)
|
||||
memcpy((char *)oprof + pbody[i * 3 + 2], pcurve, sizeof pcurve);
|
||||
pseudoinverse((double(*)[3])out_rgb[output_color - 1], inverse, 3);
|
||||
for (i = 0; i < 3; i++)
|
||||
for (j = 0; j < 3; j++)
|
||||
{
|
||||
for (num = k = 0; k < 3; k++)
|
||||
num += LibRaw_constants::xyzd50_srgb[i][k] * inverse[j][k];
|
||||
oprof[pbody[j * 3 + 23] / 4 + i + 2] = num * 0x10000 + 0.5;
|
||||
}
|
||||
for (i = 0; i < (int)phead[0] / 4; i++)
|
||||
oprof[i] = htonl(oprof[i]);
|
||||
strcpy((char *)oprof + pbody[2] + 8, "auto-generated by dcraw");
|
||||
if (pbody[5] + 12 + prof_desc.size() < phead[0])
|
||||
strcpy((char *)oprof + pbody[5] + 12, prof_desc.data());
|
||||
for (i = 0; i < 3; i++)
|
||||
for (j = 0; j < colors; j++)
|
||||
for (out_cam[i][j] = k = 0; k < 3; k++)
|
||||
out_cam[i][j] += out_rgb[output_color - 1][i][k] * rgb_cam[k][j];
|
||||
}
|
||||
convert_to_rgb_loop(out_cam);
|
||||
|
||||
if (colors == 4 && output_color)
|
||||
colors = 3;
|
||||
|
||||
RUN_CALLBACK(LIBRAW_PROGRESS_CONVERT_RGB, 1, 2);
|
||||
}
|
||||
|
||||
void LibRaw::scale_colors()
|
||||
{
|
||||
unsigned bottom, right, size, row, col, ur, uc, i, x, y, c, sum[8];
|
||||
int val;
|
||||
double dsum[8], dmin, dmax;
|
||||
float scale_mul[4], fr, fc;
|
||||
ushort *img = 0, *pix;
|
||||
|
||||
RUN_CALLBACK(LIBRAW_PROGRESS_SCALE_COLORS, 0, 2);
|
||||
|
||||
if (user_mul[0])
|
||||
memcpy(pre_mul, user_mul, sizeof pre_mul);
|
||||
if (use_auto_wb || (use_camera_wb &&
|
||||
(cam_mul[0] < -0.5 // LibRaw 0.19 and older: fallback to auto only if cam_mul[0] is set to -1
|
||||
|| (cam_mul[0] <= 0.00001f // New default: fallback to auto if no cam_mul parsed from metadata
|
||||
&& !(imgdata.rawparams.options & LIBRAW_RAWOPTIONS_CAMERAWB_FALLBACK_TO_DAYLIGHT))
|
||||
)))
|
||||
{
|
||||
memset(dsum, 0, sizeof dsum);
|
||||
bottom = MIN(greybox[1] + greybox[3], height);
|
||||
right = MIN(greybox[0] + greybox[2], width);
|
||||
for (row = greybox[1]; row < bottom; row += 8)
|
||||
for (col = greybox[0]; col < right; col += 8)
|
||||
{
|
||||
memset(sum, 0, sizeof sum);
|
||||
for (y = row; y < row + 8 && y < bottom; y++)
|
||||
for (x = col; x < col + 8 && x < right; x++)
|
||||
FORC4
|
||||
{
|
||||
if (filters)
|
||||
{
|
||||
c = fcol(y, x);
|
||||
val = BAYER2(y, x);
|
||||
}
|
||||
else
|
||||
val = image[y * width + x][c];
|
||||
if (val > (int)maximum - 25)
|
||||
goto skip_block;
|
||||
if ((val -= cblack[c]) < 0)
|
||||
val = 0;
|
||||
sum[c] += val;
|
||||
sum[c + 4]++;
|
||||
if (filters)
|
||||
break;
|
||||
}
|
||||
FORC(8) dsum[c] += sum[c];
|
||||
skip_block:;
|
||||
}
|
||||
FORC4 if (dsum[c]) pre_mul[c] = dsum[c + 4] / dsum[c];
|
||||
}
|
||||
if (use_camera_wb && cam_mul[0] > 0.00001f)
|
||||
{
|
||||
memset(sum, 0, sizeof sum);
|
||||
for (row = 0; row < 8; row++)
|
||||
for (col = 0; col < 8; col++)
|
||||
{
|
||||
c = FC(row, col);
|
||||
if ((val = white[row][col] - cblack[c]) > 0)
|
||||
sum[c] += val;
|
||||
sum[c + 4]++;
|
||||
}
|
||||
if (imgdata.color.as_shot_wb_applied)
|
||||
{
|
||||
// Nikon sRAW: camera WB already applied:
|
||||
pre_mul[0] = pre_mul[1] = pre_mul[2] = pre_mul[3] = 1.0;
|
||||
}
|
||||
else if (sum[0] && sum[1] && sum[2] && sum[3])
|
||||
FORC4 pre_mul[c] = (float)sum[c + 4] / sum[c];
|
||||
else if (cam_mul[0] > 0.00001f && cam_mul[2] > 0.00001f)
|
||||
memcpy(pre_mul, cam_mul, sizeof pre_mul);
|
||||
else
|
||||
{
|
||||
imgdata.process_warnings |= LIBRAW_WARN_BAD_CAMERA_WB;
|
||||
}
|
||||
}
|
||||
// Nikon sRAW, daylight
|
||||
if (imgdata.color.as_shot_wb_applied && !use_camera_wb && !use_auto_wb &&
|
||||
cam_mul[0] > 0.00001f && cam_mul[1] > 0.00001f && cam_mul[2] > 0.00001f)
|
||||
{
|
||||
for (c = 0; c < 3; c++)
|
||||
pre_mul[c] /= cam_mul[c];
|
||||
}
|
||||
if (pre_mul[1] == 0)
|
||||
pre_mul[1] = 1;
|
||||
if (pre_mul[3] == 0)
|
||||
pre_mul[3] = colors < 4 ? pre_mul[1] : 1;
|
||||
if (threshold)
|
||||
wavelet_denoise();
|
||||
maximum -= black;
|
||||
for (dmin = DBL_MAX, dmax = c = 0; c < 4; c++)
|
||||
{
|
||||
if (dmin > pre_mul[c])
|
||||
dmin = pre_mul[c];
|
||||
if (dmax < pre_mul[c])
|
||||
dmax = pre_mul[c];
|
||||
}
|
||||
if (!highlight)
|
||||
dmax = dmin;
|
||||
if (dmax > 0.00001 && maximum > 0)
|
||||
FORC4 scale_mul[c] = (pre_mul[c] /= dmax) * 65535.0 / maximum;
|
||||
else
|
||||
FORC4 scale_mul[c] = 1.0;
|
||||
|
||||
if (filters > 1000 && (cblack[4] + 1) / 2 == 1 && (cblack[5] + 1) / 2 == 1)
|
||||
{
|
||||
FORC4 cblack[FC(c / 2, c % 2)] +=
|
||||
cblack[6 + c / 2 % cblack[4] * cblack[5] + c % 2 % cblack[5]];
|
||||
cblack[4] = cblack[5] = 0;
|
||||
}
|
||||
size = iheight * iwidth;
|
||||
scale_colors_loop(scale_mul);
|
||||
if ((aber[0] != 1 || aber[2] != 1) && colors == 3)
|
||||
{
|
||||
for (c = 0; c < 4; c += 2)
|
||||
{
|
||||
if (aber[c] == 1)
|
||||
continue;
|
||||
img = (ushort *)malloc(size * sizeof *img);
|
||||
for (i = 0; i < size; i++)
|
||||
img[i] = image[i][c];
|
||||
for (row = 0; row < iheight; row++)
|
||||
{
|
||||
ur = fr = (row - iheight * 0.5) * aber[c] + iheight * 0.5;
|
||||
if (ur > (unsigned)iheight - 2)
|
||||
continue;
|
||||
fr -= ur;
|
||||
for (col = 0; col < iwidth; col++)
|
||||
{
|
||||
uc = fc = (col - iwidth * 0.5) * aber[c] + iwidth * 0.5;
|
||||
if (uc > (unsigned)iwidth - 2)
|
||||
continue;
|
||||
fc -= uc;
|
||||
pix = img + ur * iwidth + uc;
|
||||
image[row * iwidth + col][c] =
|
||||
(pix[0] * (1 - fc) + pix[1] * fc) * (1 - fr) +
|
||||
(pix[iwidth] * (1 - fc) + pix[iwidth + 1] * fc) * fr;
|
||||
}
|
||||
}
|
||||
free(img);
|
||||
}
|
||||
}
|
||||
RUN_CALLBACK(LIBRAW_PROGRESS_SCALE_COLORS, 1, 2);
|
||||
}
|
||||
|
||||
// green equilibration
|
||||
void LibRaw::green_matching()
|
||||
{
|
||||
int i, j;
|
||||
double m1, m2, c1, c2;
|
||||
int o1_1, o1_2, o1_3, o1_4;
|
||||
int o2_1, o2_2, o2_3, o2_4;
|
||||
ushort(*img)[4];
|
||||
const int margin = 3;
|
||||
int oj = 2, oi = 2;
|
||||
float f;
|
||||
const float thr = 0.01f;
|
||||
if (half_size || shrink)
|
||||
return;
|
||||
if (FC(oj, oi) != 3)
|
||||
oj++;
|
||||
if (FC(oj, oi) != 3)
|
||||
oi++;
|
||||
if (FC(oj, oi) != 3)
|
||||
oj--;
|
||||
|
||||
img = (ushort(*)[4])calloc(height * width, sizeof *image);
|
||||
memcpy(img, image, height * width * sizeof *image);
|
||||
|
||||
for (j = oj; j < height - margin; j += 2)
|
||||
for (i = oi; i < width - margin; i += 2)
|
||||
{
|
||||
o1_1 = img[(j - 1) * width + i - 1][1];
|
||||
o1_2 = img[(j - 1) * width + i + 1][1];
|
||||
o1_3 = img[(j + 1) * width + i - 1][1];
|
||||
o1_4 = img[(j + 1) * width + i + 1][1];
|
||||
o2_1 = img[(j - 2) * width + i][3];
|
||||
o2_2 = img[(j + 2) * width + i][3];
|
||||
o2_3 = img[j * width + i - 2][3];
|
||||
o2_4 = img[j * width + i + 2][3];
|
||||
|
||||
m1 = (o1_1 + o1_2 + o1_3 + o1_4) / 4.0;
|
||||
m2 = (o2_1 + o2_2 + o2_3 + o2_4) / 4.0;
|
||||
|
||||
c1 = (abs(o1_1 - o1_2) + abs(o1_1 - o1_3) + abs(o1_1 - o1_4) +
|
||||
abs(o1_2 - o1_3) + abs(o1_3 - o1_4) + abs(o1_2 - o1_4)) /
|
||||
6.0;
|
||||
c2 = (abs(o2_1 - o2_2) + abs(o2_1 - o2_3) + abs(o2_1 - o2_4) +
|
||||
abs(o2_2 - o2_3) + abs(o2_3 - o2_4) + abs(o2_2 - o2_4)) /
|
||||
6.0;
|
||||
if ((img[j * width + i][3] < maximum * 0.95) && (c1 < maximum * thr) &&
|
||||
(c2 < maximum * thr))
|
||||
{
|
||||
f = image[j * width + i][3] * m1 / m2;
|
||||
image[j * width + i][3] = f > 0xffff ? 0xffff : f;
|
||||
}
|
||||
}
|
||||
free(img);
|
||||
}
|
Reference in New Issue
Block a user