@ -0,0 +1,134 @@ |
||||
|
||||
/* arm_init.c - NEON optimised filter functions
|
||||
* |
||||
* Copyright (c) 2014 Glenn Randers-Pehrson |
||||
* Written by Mans Rullgard, 2011. |
||||
* Last changed in libpng 1.6.16 [December 22, 2014] |
||||
* |
||||
* This code is released under the libpng license. |
||||
* For conditions of distribution and use, see the disclaimer |
||||
* and license in png.h |
||||
*/ |
||||
/* Below, after checking __linux__, various non-C90 POSIX 1003.1 functions are
|
||||
* called. |
||||
*/ |
||||
#define _POSIX_SOURCE 1 |
||||
|
||||
#include "../pngpriv.h" |
||||
|
||||
#ifdef PNG_READ_SUPPORTED |
||||
|
||||
#if PNG_ARM_NEON_OPT > 0 |
||||
#ifdef PNG_ARM_NEON_CHECK_SUPPORTED /* Do run-time checks */ |
||||
/* WARNING: it is strongly recommended that you do not build libpng with
|
||||
* run-time checks for CPU features if at all possible. In the case of the ARM |
||||
* NEON instructions there is no processor-specific way of detecting the |
||||
* presence of the required support, therefore run-time detection is extremely |
||||
* OS specific. |
||||
* |
||||
* You may set the macro PNG_ARM_NEON_FILE to the file name of file containing |
||||
* a fragment of C source code which defines the png_have_neon function. There |
||||
* are a number of implementations in contrib/arm-neon, but the only one that |
||||
* has partial support is contrib/arm-neon/linux.c - a generic Linux |
||||
* implementation which reads /proc/cpufino. |
||||
*/ |
||||
#ifndef PNG_ARM_NEON_FILE |
||||
# ifdef __linux__ |
||||
# define PNG_ARM_NEON_FILE "contrib/arm-neon/linux.c" |
||||
# endif |
||||
#endif |
||||
|
||||
#ifdef PNG_ARM_NEON_FILE |
||||
|
||||
#include <signal.h> /* for sig_atomic_t */ |
||||
static int png_have_neon(png_structp png_ptr); |
||||
#include PNG_ARM_NEON_FILE |
||||
|
||||
#else /* PNG_ARM_NEON_FILE */ |
||||
# error "PNG_ARM_NEON_FILE undefined: no support for run-time ARM NEON checks" |
||||
#endif /* PNG_ARM_NEON_FILE */ |
||||
#endif /* PNG_ARM_NEON_CHECK_SUPPORTED */ |
||||
|
||||
#ifndef PNG_ALIGNED_MEMORY_SUPPORTED |
||||
# error "ALIGNED_MEMORY is required; set: -DPNG_ALIGNED_MEMORY_SUPPORTED" |
||||
#endif |
||||
|
||||
void |
||||
png_init_filter_functions_neon(png_structp pp, unsigned int bpp) |
||||
{ |
||||
/* The switch statement is compiled in for ARM_NEON_API, the call to
|
||||
* png_have_neon is compiled in for ARM_NEON_CHECK. If both are defined |
||||
* the check is only performed if the API has not set the NEON option on |
||||
* or off explicitly. In this case the check controls what happens. |
||||
* |
||||
* If the CHECK is not compiled in and the option is UNSET the behavior prior |
||||
* to 1.6.7 was to use the NEON code - this was a bug caused by having the |
||||
* wrong order of the 'ON' and 'default' cases. UNSET now defaults to OFF, |
||||
* as documented in png.h |
||||
*/ |
||||
#ifdef PNG_ARM_NEON_API_SUPPORTED |
||||
switch ((pp->options >> PNG_ARM_NEON) & 3) |
||||
{ |
||||
case PNG_OPTION_UNSET: |
||||
/* Allow the run-time check to execute if it has been enabled -
|
||||
* thus both API and CHECK can be turned on. If it isn't supported |
||||
* this case will fall through to the 'default' below, which just |
||||
* returns. |
||||
*/ |
||||
#endif /* PNG_ARM_NEON_API_SUPPORTED */ |
||||
#ifdef PNG_ARM_NEON_CHECK_SUPPORTED |
||||
{ |
||||
static volatile sig_atomic_t no_neon = -1; /* not checked */ |
||||
|
||||
if (no_neon < 0) |
||||
no_neon = !png_have_neon(pp); |
||||
|
||||
if (no_neon) |
||||
return; |
||||
} |
||||
#ifdef PNG_ARM_NEON_API_SUPPORTED |
||||
break; |
||||
#endif |
||||
#endif /* PNG_ARM_NEON_CHECK_SUPPORTED */ |
||||
|
||||
#ifdef PNG_ARM_NEON_API_SUPPORTED |
||||
default: /* OFF or INVALID */ |
||||
return; |
||||
|
||||
case PNG_OPTION_ON: |
||||
/* Option turned on */ |
||||
break; |
||||
} |
||||
#endif |
||||
|
||||
/* IMPORTANT: any new external functions used here must be declared using
|
||||
* PNG_INTERNAL_FUNCTION in ../pngpriv.h. This is required so that the |
||||
* 'prefix' option to configure works: |
||||
* |
||||
* ./configure --with-libpng-prefix=foobar_ |
||||
* |
||||
* Verify you have got this right by running the above command, doing a build |
||||
* and examining pngprefix.h; it must contain a #define for every external |
||||
* function you add. (Notice that this happens automatically for the |
||||
* initialization function.) |
||||
*/ |
||||
pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up_neon; |
||||
|
||||
if (bpp == 3) |
||||
{ |
||||
pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub3_neon; |
||||
pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg3_neon; |
||||
pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = |
||||
png_read_filter_row_paeth3_neon; |
||||
} |
||||
|
||||
else if (bpp == 4) |
||||
{ |
||||
pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub4_neon; |
||||
pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg4_neon; |
||||
pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = |
||||
png_read_filter_row_paeth4_neon; |
||||
} |
||||
} |
||||
#endif /* PNG_ARM_NEON_OPT > 0 */ |
||||
#endif /* READ */ |
@ -0,0 +1,373 @@ |
||||
|
||||
/* filter_neon_intrinsics.c - NEON optimised filter functions
|
||||
* |
||||
* Copyright (c) 2014 Glenn Randers-Pehrson |
||||
* Written by James Yu <james.yu at linaro.org>, October 2013. |
||||
* Based on filter_neon.S, written by Mans Rullgard, 2011. |
||||
* |
||||
* Last changed in libpng 1.6.16 [December 22, 2014] |
||||
* |
||||
* This code is released under the libpng license. |
||||
* For conditions of distribution and use, see the disclaimer |
||||
* and license in png.h |
||||
*/ |
||||
|
||||
#include "../pngpriv.h" |
||||
|
||||
#ifdef PNG_READ_SUPPORTED |
||||
|
||||
/* This code requires -mfpu=neon on the command line: */ |
||||
#if PNG_ARM_NEON_IMPLEMENTATION == 1 /* intrinsics code from pngpriv.h */ |
||||
|
||||
#include <arm_neon.h> |
||||
|
||||
/* libpng row pointers are not necessarily aligned to any particular boundary,
|
||||
* however this code will only work with appropriate alignment. arm/arm_init.c |
||||
* checks for this (and will not compile unless it is done). This code uses |
||||
* variants of png_aligncast to avoid compiler warnings. |
||||
*/ |
||||
#define png_ptr(type,pointer) png_aligncast(type *,pointer) |
||||
#define png_ptrc(type,pointer) png_aligncastconst(const type *,pointer) |
||||
|
||||
/* The following relies on a variable 'temp_pointer' being declared with type
|
||||
* 'type'. This is written this way just to hide the GCC strict aliasing |
||||
* warning; note that the code is safe because there never is an alias between |
||||
* the input and output pointers. |
||||
*/ |
||||
#define png_ldr(type,pointer)\ |
||||
(temp_pointer = png_ptr(type,pointer), *temp_pointer) |
||||
|
||||
#if PNG_ARM_NEON_OPT > 0 |
||||
|
||||
void |
||||
png_read_filter_row_up_neon(png_row_infop row_info, png_bytep row, |
||||
png_const_bytep prev_row) |
||||
{ |
||||
png_bytep rp = row; |
||||
png_bytep rp_stop = row + row_info->rowbytes; |
||||
png_const_bytep pp = prev_row; |
||||
|
||||
for (; rp < rp_stop; rp += 16, pp += 16) |
||||
{ |
||||
uint8x16_t qrp, qpp; |
||||
|
||||
qrp = vld1q_u8(rp); |
||||
qpp = vld1q_u8(pp); |
||||
qrp = vaddq_u8(qrp, qpp); |
||||
vst1q_u8(rp, qrp); |
||||
} |
||||
} |
||||
|
||||
void |
||||
png_read_filter_row_sub3_neon(png_row_infop row_info, png_bytep row, |
||||
png_const_bytep prev_row) |
||||
{ |
||||
png_bytep rp = row; |
||||
png_bytep rp_stop = row + row_info->rowbytes; |
||||
|
||||
uint8x16_t vtmp = vld1q_u8(rp); |
||||
uint8x8x2_t *vrpt = png_ptr(uint8x8x2_t, &vtmp); |
||||
uint8x8x2_t vrp = *vrpt; |
||||
|
||||
uint8x8x4_t vdest; |
||||
vdest.val[3] = vdup_n_u8(0); |
||||
|
||||
for (; rp < rp_stop;) |
||||
{ |
||||
uint8x8_t vtmp1, vtmp2; |
||||
uint32x2_t *temp_pointer; |
||||
|
||||
vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 3); |
||||
vdest.val[0] = vadd_u8(vdest.val[3], vrp.val[0]); |
||||
vtmp2 = vext_u8(vrp.val[0], vrp.val[1], 6); |
||||
vdest.val[1] = vadd_u8(vdest.val[0], vtmp1); |
||||
|
||||
vtmp1 = vext_u8(vrp.val[1], vrp.val[1], 1); |
||||
vdest.val[2] = vadd_u8(vdest.val[1], vtmp2); |
||||
vdest.val[3] = vadd_u8(vdest.val[2], vtmp1); |
||||
|
||||
vtmp = vld1q_u8(rp + 12); |
||||
vrpt = png_ptr(uint8x8x2_t, &vtmp); |
||||
vrp = *vrpt; |
||||
|
||||
vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[0]), 0); |
||||
rp += 3; |
||||
vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[1]), 0); |
||||
rp += 3; |
||||
vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[2]), 0); |
||||
rp += 3; |
||||
vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[3]), 0); |
||||
rp += 3; |
||||
} |
||||
|
||||
PNG_UNUSED(prev_row) |
||||
} |
||||
|
||||
void |
||||
png_read_filter_row_sub4_neon(png_row_infop row_info, png_bytep row, |
||||
png_const_bytep prev_row) |
||||
{ |
||||
png_bytep rp = row; |
||||
png_bytep rp_stop = row + row_info->rowbytes; |
||||
|
||||
uint8x8x4_t vdest; |
||||
vdest.val[3] = vdup_n_u8(0); |
||||
|
||||
for (; rp < rp_stop; rp += 16) |
||||
{ |
||||
uint32x2x4_t vtmp = vld4_u32(png_ptr(uint32_t,rp)); |
||||
uint8x8x4_t *vrpt = png_ptr(uint8x8x4_t,&vtmp); |
||||
uint8x8x4_t vrp = *vrpt; |
||||
uint32x2x4_t *temp_pointer; |
||||
|
||||
vdest.val[0] = vadd_u8(vdest.val[3], vrp.val[0]); |
||||
vdest.val[1] = vadd_u8(vdest.val[0], vrp.val[1]); |
||||
vdest.val[2] = vadd_u8(vdest.val[1], vrp.val[2]); |
||||
vdest.val[3] = vadd_u8(vdest.val[2], vrp.val[3]); |
||||
vst4_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2x4_t,&vdest), 0); |
||||
} |
||||
|
||||
PNG_UNUSED(prev_row) |
||||
} |
||||
|
||||
void |
||||
png_read_filter_row_avg3_neon(png_row_infop row_info, png_bytep row, |
||||
png_const_bytep prev_row) |
||||
{ |
||||
png_bytep rp = row; |
||||
png_const_bytep pp = prev_row; |
||||
png_bytep rp_stop = row + row_info->rowbytes; |
||||
|
||||
uint8x16_t vtmp; |
||||
uint8x8x2_t *vrpt; |
||||
uint8x8x2_t vrp; |
||||
uint8x8x4_t vdest; |
||||
vdest.val[3] = vdup_n_u8(0); |
||||
|
||||
vtmp = vld1q_u8(rp); |
||||
vrpt = png_ptr(uint8x8x2_t,&vtmp); |
||||
vrp = *vrpt; |
||||
|
||||
for (; rp < rp_stop; pp += 12) |
||||
{ |
||||
uint8x8_t vtmp1, vtmp2, vtmp3; |
||||
|
||||
uint8x8x2_t *vppt; |
||||
uint8x8x2_t vpp; |
||||
|
||||
uint32x2_t *temp_pointer; |
||||
|
||||
vtmp = vld1q_u8(pp); |
||||
vppt = png_ptr(uint8x8x2_t,&vtmp); |
||||
vpp = *vppt; |
||||
|
||||
vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 3); |
||||
vdest.val[0] = vhadd_u8(vdest.val[3], vpp.val[0]); |
||||
vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]); |
||||
|
||||
vtmp2 = vext_u8(vpp.val[0], vpp.val[1], 3); |
||||
vtmp3 = vext_u8(vrp.val[0], vrp.val[1], 6); |
||||
vdest.val[1] = vhadd_u8(vdest.val[0], vtmp2); |
||||
vdest.val[1] = vadd_u8(vdest.val[1], vtmp1); |
||||
|
||||
vtmp2 = vext_u8(vpp.val[0], vpp.val[1], 6); |
||||
vtmp1 = vext_u8(vrp.val[1], vrp.val[1], 1); |
||||
|
||||
vtmp = vld1q_u8(rp + 12); |
||||
vrpt = png_ptr(uint8x8x2_t,&vtmp); |
||||
vrp = *vrpt; |
||||
|
||||
vdest.val[2] = vhadd_u8(vdest.val[1], vtmp2); |
||||
vdest.val[2] = vadd_u8(vdest.val[2], vtmp3); |
||||
|
||||
vtmp2 = vext_u8(vpp.val[1], vpp.val[1], 1); |
||||
|
||||
vdest.val[3] = vhadd_u8(vdest.val[2], vtmp2); |
||||
vdest.val[3] = vadd_u8(vdest.val[3], vtmp1); |
||||
|
||||
vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[0]), 0); |
||||
rp += 3; |
||||
vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[1]), 0); |
||||
rp += 3; |
||||
vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[2]), 0); |
||||
rp += 3; |
||||
vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[3]), 0); |
||||
rp += 3; |
||||
} |
||||
} |
||||
|
||||
void |
||||
png_read_filter_row_avg4_neon(png_row_infop row_info, png_bytep row, |
||||
png_const_bytep prev_row) |
||||
{ |
||||
png_bytep rp = row; |
||||
png_bytep rp_stop = row + row_info->rowbytes; |
||||
png_const_bytep pp = prev_row; |
||||
|
||||
uint8x8x4_t vdest; |
||||
vdest.val[3] = vdup_n_u8(0); |
||||
|
||||
for (; rp < rp_stop; rp += 16, pp += 16) |
||||
{ |
||||
uint32x2x4_t vtmp; |
||||
uint8x8x4_t *vrpt, *vppt; |
||||
uint8x8x4_t vrp, vpp; |
||||
uint32x2x4_t *temp_pointer; |
||||
|
||||
vtmp = vld4_u32(png_ptr(uint32_t,rp)); |
||||
vrpt = png_ptr(uint8x8x4_t,&vtmp); |
||||
vrp = *vrpt; |
||||
vtmp = vld4_u32(png_ptrc(uint32_t,pp)); |
||||
vppt = png_ptr(uint8x8x4_t,&vtmp); |
||||
vpp = *vppt; |
||||
|
||||
vdest.val[0] = vhadd_u8(vdest.val[3], vpp.val[0]); |
||||
vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]); |
||||
vdest.val[1] = vhadd_u8(vdest.val[0], vpp.val[1]); |
||||
vdest.val[1] = vadd_u8(vdest.val[1], vrp.val[1]); |
||||
vdest.val[2] = vhadd_u8(vdest.val[1], vpp.val[2]); |
||||
vdest.val[2] = vadd_u8(vdest.val[2], vrp.val[2]); |
||||
vdest.val[3] = vhadd_u8(vdest.val[2], vpp.val[3]); |
||||
vdest.val[3] = vadd_u8(vdest.val[3], vrp.val[3]); |
||||
|
||||
vst4_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2x4_t,&vdest), 0); |
||||
} |
||||
} |
||||
|
||||
static uint8x8_t |
||||
paeth(uint8x8_t a, uint8x8_t b, uint8x8_t c) |
||||
{ |
||||
uint8x8_t d, e; |
||||
uint16x8_t p1, pa, pb, pc; |
||||
|
||||
p1 = vaddl_u8(a, b); /* a + b */ |
||||
pc = vaddl_u8(c, c); /* c * 2 */ |
||||
pa = vabdl_u8(b, c); /* pa */ |
||||
pb = vabdl_u8(a, c); /* pb */ |
||||
pc = vabdq_u16(p1, pc); /* pc */ |
||||
|
||||
p1 = vcleq_u16(pa, pb); /* pa <= pb */ |
||||
pa = vcleq_u16(pa, pc); /* pa <= pc */ |
||||
pb = vcleq_u16(pb, pc); /* pb <= pc */ |
||||
|
||||
p1 = vandq_u16(p1, pa); /* pa <= pb && pa <= pc */ |
||||
|
||||
d = vmovn_u16(pb); |
||||
e = vmovn_u16(p1); |
||||
|
||||
d = vbsl_u8(d, b, c); |
||||
e = vbsl_u8(e, a, d); |
||||
|
||||
return e; |
||||
} |
||||
|
||||
void |
||||
png_read_filter_row_paeth3_neon(png_row_infop row_info, png_bytep row, |
||||
png_const_bytep prev_row) |
||||
{ |
||||
png_bytep rp = row; |
||||
png_const_bytep pp = prev_row; |
||||
png_bytep rp_stop = row + row_info->rowbytes; |
||||
|
||||
uint8x16_t vtmp; |
||||
uint8x8x2_t *vrpt; |
||||
uint8x8x2_t vrp; |
||||
uint8x8_t vlast = vdup_n_u8(0); |
||||
uint8x8x4_t vdest; |
||||
vdest.val[3] = vdup_n_u8(0); |
||||
|
||||
vtmp = vld1q_u8(rp); |
||||
vrpt = png_ptr(uint8x8x2_t,&vtmp); |
||||
vrp = *vrpt; |
||||
|
||||
for (; rp < rp_stop; pp += 12) |
||||
{ |
||||
uint8x8x2_t *vppt; |
||||
uint8x8x2_t vpp; |
||||
uint8x8_t vtmp1, vtmp2, vtmp3; |
||||
uint32x2_t *temp_pointer; |
||||
|
||||
vtmp = vld1q_u8(pp); |
||||
vppt = png_ptr(uint8x8x2_t,&vtmp); |
||||
vpp = *vppt; |
||||
|
||||
vdest.val[0] = paeth(vdest.val[3], vpp.val[0], vlast); |
||||
vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]); |
||||
|
||||
vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 3); |
||||
vtmp2 = vext_u8(vpp.val[0], vpp.val[1], 3); |
||||
vdest.val[1] = paeth(vdest.val[0], vtmp2, vpp.val[0]); |
||||
vdest.val[1] = vadd_u8(vdest.val[1], vtmp1); |
||||
|
||||
vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 6); |
||||
vtmp3 = vext_u8(vpp.val[0], vpp.val[1], 6); |
||||
vdest.val[2] = paeth(vdest.val[1], vtmp3, vtmp2); |
||||
vdest.val[2] = vadd_u8(vdest.val[2], vtmp1); |
||||
|
||||
vtmp1 = vext_u8(vrp.val[1], vrp.val[1], 1); |
||||
vtmp2 = vext_u8(vpp.val[1], vpp.val[1], 1); |
||||
|
||||
vtmp = vld1q_u8(rp + 12); |
||||
vrpt = png_ptr(uint8x8x2_t,&vtmp); |
||||
vrp = *vrpt; |
||||
|
||||
vdest.val[3] = paeth(vdest.val[2], vtmp2, vtmp3); |
||||
vdest.val[3] = vadd_u8(vdest.val[3], vtmp1); |
||||
|
||||
vlast = vtmp2; |
||||
|
||||
vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[0]), 0); |
||||
rp += 3; |
||||
vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[1]), 0); |
||||
rp += 3; |
||||
vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[2]), 0); |
||||
rp += 3; |
||||
vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[3]), 0); |
||||
rp += 3; |
||||
} |
||||
} |
||||
|
||||
void |
||||
png_read_filter_row_paeth4_neon(png_row_infop row_info, png_bytep row, |
||||
png_const_bytep prev_row) |
||||
{ |
||||
png_bytep rp = row; |
||||
png_bytep rp_stop = row + row_info->rowbytes; |
||||
png_const_bytep pp = prev_row; |
||||
|
||||
uint8x8_t vlast = vdup_n_u8(0); |
||||
uint8x8x4_t vdest; |
||||
vdest.val[3] = vdup_n_u8(0); |
||||
|
||||
for (; rp < rp_stop; rp += 16, pp += 16) |
||||
{ |
||||
uint32x2x4_t vtmp; |
||||
uint8x8x4_t *vrpt, *vppt; |
||||
uint8x8x4_t vrp, vpp; |
||||
uint32x2x4_t *temp_pointer; |
||||
|
||||
vtmp = vld4_u32(png_ptr(uint32_t,rp)); |
||||
vrpt = png_ptr(uint8x8x4_t,&vtmp); |
||||
vrp = *vrpt; |
||||
vtmp = vld4_u32(png_ptrc(uint32_t,pp)); |
||||
vppt = png_ptr(uint8x8x4_t,&vtmp); |
||||
vpp = *vppt; |
||||
|
||||
vdest.val[0] = paeth(vdest.val[3], vpp.val[0], vlast); |
||||
vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]); |
||||
vdest.val[1] = paeth(vdest.val[0], vpp.val[1], vpp.val[0]); |
||||
vdest.val[1] = vadd_u8(vdest.val[1], vrp.val[1]); |
||||
vdest.val[2] = paeth(vdest.val[1], vpp.val[2], vpp.val[1]); |
||||
vdest.val[2] = vadd_u8(vdest.val[2], vrp.val[2]); |
||||
vdest.val[3] = paeth(vdest.val[2], vpp.val[3], vpp.val[2]); |
||||
vdest.val[3] = vadd_u8(vdest.val[3], vrp.val[3]); |
||||
|
||||
vlast = vpp.val[3]; |
||||
|
||||
vst4_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2x4_t,&vdest), 0); |
||||
} |
||||
} |
||||
|
||||
#endif /* PNG_ARM_NEON_OPT > 0 */ |
||||
#endif /* PNG_ARM_NEON_IMPLEMENTATION == 1 (intrinsics) */ |
||||
#endif /* READ */ |
@ -0,0 +1,139 @@ |
||||
FILE(TO_CMAKE_PATH "$ENV{GSTREAMER_DIR}" TRY1_DIR) |
||||
FILE(TO_CMAKE_PATH "${GSTREAMER_DIR}" TRY2_DIR) |
||||
FILE(GLOB GSTREAMER_DIR ${TRY1_DIR} ${TRY2_DIR}) |
||||
|
||||
FIND_PATH(GSTREAMER_gst_INCLUDE_DIR gst/gst.h |
||||
PATHS ${GSTREAMER_DIR}/include/gstreamer-1.0 ${GSTREAMER_DIR}/include /usr/local/include/gstreamer-1.0 /usr/include/gstreamer-1.0 |
||||
ENV INCLUDE DOC "Directory containing gst/gst.h include file") |
||||
|
||||
FIND_PATH(GSTREAMER_glib_INCLUDE_DIR glib.h |
||||
PATHS ${GSTREAMER_DIR}/include/glib-2.0/ |
||||
ENV INCLUDE DOC "Directory containing glib.h include file") |
||||
|
||||
FIND_PATH(GSTREAMER_glibconfig_INCLUDE_DIR glibconfig.h |
||||
PATHS ${GSTREAMER_DIR}/lib/glib-2.0/include |
||||
ENV INCLUDE DOC "Directory containing glibconfig.h include file") |
||||
|
||||
FIND_PATH(GSTREAMER_gstconfig_INCLUDE_DIR gst/gstconfig.h |
||||
PATHS ${GSTREAMER_DIR}/lib/gstreamer-1.0/include ${GSTREAMER_DIR}/include ${GSTREAMER_DIR}/lib/include /usr/local/include/gstreamer-1.0 /usr/include/gstreamer-1.0 /usr/local/lib/include/gstreamer-1.0 /usr/lib/include/gstreamer-1.0 |
||||
ENV INCLUDE DOC "Directory containing gst/gstconfig.h include file") |
||||
|
||||
FIND_LIBRARY(GSTREAMER_gstaudio_LIBRARY NAMES gstaudio libgstaudio-1.0 gstaudio-1.0 |
||||
PATHS ${GSTREMAER_DIR}/lib ${GSTREAMER_DIR}/bin ${GSTREAMER_DIR}/win32/bin ${GSTREAMER_DIR}/bin/bin C:/gstreamer/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/lib /usr/local/lib /usr/lib |
||||
ENV LIB |
||||
DOC "gstaudio library to link with" |
||||
NO_SYSTEM_ENVIRONMENT_PATH) |
||||
|
||||
FIND_LIBRARY(GSTREAMER_gstapp_LIBRARY NAMES gstapp libgstapp-1.0 gstapp-1.0 |
||||
PATHS ${GSTREAMER_DIR}/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/bin ${GSTREAMER_DIR}/bin/bin C:/gstreamer/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/lib /usr/local/lib /usr/lib |
||||
ENV LIB |
||||
DOC "gstapp library to link with" |
||||
NO_SYSTEM_ENVIRONMENT_PATH) |
||||
|
||||
FIND_LIBRARY(GSTREAMER_gstbase_LIBRARY NAMES gstbase libgstbase-1.0 gstbase-1.0 |
||||
PATHS ${GSTREAMER_DIR}/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/bin ${GSTREAMER_DIR}/bin/bin C:/gstreamer/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/lib /usr/local/lib /usr/lib |
||||
ENV LIB |
||||
DOC "gstbase library to link with" |
||||
NO_SYSTEM_ENVIRONMENT_PATH) |
||||
|
||||
FIND_LIBRARY(GLIB_gstcdda_LIBRARY NAMES gstcdda libgstcdda-1.0 gstcdda-1.0 |
||||
PATHS ${GSTREAMER_DIR}/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/bin ${GSTREAMER_DIR}/bin/bin C:/gstreamer/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/lib /usr/local/lib /usr/lib |
||||
ENV LIB |
||||
DOC "gstcdda library to link with" |
||||
NO_SYSTEM_ENVIRONMENT_PATH) |
||||
|
||||
FIND_LIBRARY(GSTREAMER_gstcontroller_LIBRARY NAMES gstcontroller libgstcontroller-1.0 gstcontroller-1.0 |
||||
PATHS ${GSTREAMER_DIR}/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/bin ${GSTREAMER_DIR}/bin/bin C:/gstreamer/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/lib /usr/local/lib /usr/lib |
||||
ENV LIB |
||||
DOC "gstcontroller library to link with" |
||||
NO_SYSTEM_ENVIRONMENT_PATH) |
||||
|
||||
|
||||
FIND_LIBRARY(GSTREAMER_gstnet_LIBRARY NAMES gstnet libgstnet-1.0 gstnet-1.0 |
||||
PATHS ${GSTREAMER_DIR}/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/bin ${GSTREAMER_DIR}/bin/bin C:/gstreamer/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/lib /usr/local/lib /usr/lib |
||||
ENV LIB |
||||
DOC "gstnet library to link with" |
||||
NO_SYSTEM_ENVIRONMENT_PATH) |
||||
|
||||
FIND_LIBRARY(GSTREAMER_gstpbutils_LIBRARY NAMES gstpbutils libgstpbutils-1.0 gstpbutils-1.0 |
||||
PATHS ${GSTREAMER_DIR}/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/bin ${GSTREAMER_DIR}/bin/bin C:/gstreamer/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/lib /usr/local/lib /usr/lib |
||||
ENV LIB |
||||
DOC "gstpbutils library to link with" |
||||
NO_SYSTEM_ENVIRONMENT_PATH) |
||||
|
||||
FIND_LIBRARY(GSTREAMER_gstreamer_LIBRARY NAMES gstreamer libgstreamer-1.0 gstreamer-1.0 |
||||
PATHS ${GSTREAMER_DIR}/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/bin ${GSTREAMER_DIR}/bin/bin C:/gstreamer/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/lib /usr/local/lib /usr/lib |
||||
ENV LIB |
||||
DOC "gstreamer library to link with" |
||||
NO_SYSTEM_ENVIRONMENT_PATH) |
||||
|
||||
FIND_LIBRARY(GSTREAMER_gstriff_LIBRARY NAMES gstriff libgstriff-1.0 gstriff-1.0 |
||||
PATHS ${GSTREAMER_DIR}/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/bin ${GSTREAMER_DIR}/bin/bin C:/gstreamer/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/lib /usr/local/lib /usr/lib |
||||
ENV LIB |
||||
DOC "gstriff library to link with" |
||||
NO_SYSTEM_ENVIRONMENT_PATH) |
||||
|
||||
FIND_LIBRARY(GSTREAMER_gstrtp_LIBRARY NAMES gstrtp libgstrtp-1.0 gstrtp-1.0 |
||||
PATHS ${GSTREAMER_DIR}/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/bin ${GSTREAMER_DIR}/bin/bin C:/gstreamer/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/lib /usr/local/lib /usr/lib |
||||
ENV LIB |
||||
DOC "gstrtp library to link with" |
||||
NO_SYSTEM_ENVIRONMENT_PATH) |
||||
|
||||
FIND_LIBRARY(GSTREAMER_gstrtsp_LIBRARY NAMES gstrtsp libgstrtsp-1.0 gstrtsp-1.0 |
||||
PATHS ${GSTREAMER_DIR}/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/bin ${GSTREAMER_DIR}/bin/bin C:/gstreamer/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/lib /usr/local/lib /usr/lib |
||||
ENV LIB |
||||
DOC "gstrtsp library to link with" |
||||
NO_SYSTEM_ENVIRONMENT_PATH) |
||||
|
||||
FIND_LIBRARY(GSTREAMER_gstsdp_LIBRARY NAMES gstsdp libgstsdp-1.0 gstsdp-1.0 |
||||
PATHS ${GSTREAMER_DIR}/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/bin ${GSTREAMER_DIR}/bin/bin C:/gstreamer/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/lib /usr/local/lib /usr/lib |
||||
ENV LIB |
||||
DOC "gstsdp library to link with" |
||||
NO_SYSTEM_ENVIRONMENT_PATH) |
||||
|
||||
FIND_LIBRARY(GSTREAMER_gsttag_LIBRARY NAMES gsttag libgsttag-1.0 gsttag-1.0 |
||||
PATHS ${GSTREAMER_DIR}/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/bin ${GSTREAMER_DIR}/bin/bin C:/gstreamer/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/lib /usr/local/lib /usr/lib |
||||
ENV LIB |
||||
DOC "gsttag library to link with" |
||||
NO_SYSTEM_ENVIRONMENT_PATH) |
||||
|
||||
FIND_LIBRARY(GSTREAMER_gstvideo_LIBRARY NAMES gstvideo libgstvideo-1.0 gstvideo-1.0 |
||||
PATHS ${GSTREAMER_DIR}/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/bin ${GSTREAMER_DIR}/bin/bin C:/gstreamer/bin ${GSTREAMER_DIR}/lib ${GSTREAMER_DIR}/win32/lib /usr/local/lib /usr/lib |
||||
ENV LIB |
||||
DOC "gstvideo library to link with" |
||||
NO_SYSTEM_ENVIRONMENT_PATH) |
||||
|
||||
FIND_LIBRARY(GLIB_LIBRARY NAMES libglib-2.0 glib-2.0 |
||||
PATHS ${GSTREAMER_DIR}/lib |
||||
ENV LIB |
||||
DOC "Glib library" |
||||
NO_SYSTEM_ENVIRONMENT_PATH) |
||||
|
||||
FIND_LIBRARY(GOBJECT_LIBRARY NAMES libobject-2.0 gobject-2.0 |
||||
PATHS ${GSTREAMER_DIR}/lib |
||||
ENV LIB |
||||
DOC "Glib library" |
||||
NO_SYSTEM_ENVIRONMENT_PATH) |
||||
|
||||
IF (GSTREAMER_gst_INCLUDE_DIR AND GSTREAMER_gstconfig_INCLUDE_DIR AND |
||||
GSTREAMER_gstaudio_LIBRARY AND GSTREAMER_gstbase_LIBRARY AND GSTREAMER_gstcontroller_LIBRARY AND GSTREAMER_gstnet_LIBRARY |
||||
AND GSTREAMER_gstpbutils_LIBRARY AND GSTREAMER_gstreamer_LIBRARY AND |
||||
GSTREAMER_gstriff_LIBRARY AND GSTREAMER_gstrtp_LIBRARY AND GSTREAMER_gstrtsp_LIBRARY AND GSTREAMER_gstsdp_LIBRARY AND |
||||
GSTREAMER_gsttag_LIBRARY AND GSTREAMER_gstvideo_LIBRARY AND GLIB_LIBRARY AND GSTREAMER_gstapp_LIBRARY AND GOBJECT_LIBRARY) |
||||
SET(GSTREAMER_INCLUDE_DIR ${GSTREAMER_gst_INCLUDE_DIR} ${GSTREAMER_gstconfig_INCLUDE_DIR} ${GSTREAMER_glib_INCLUDE_DIR} ${GSTREAMER_glibconfig_INCLUDE_DIR}) |
||||
|
||||
list(REMOVE_DUPLICATES GSTREAMER_INCLUDE_DIR) |
||||
SET(GSTREAMER_LIBRARIES ${GSTREAMER_gstaudio_LIBRARY} ${GSTREAMER_gstbase_LIBRARY} |
||||
${GSTREAMER_gstcontroller_LIBRARY} ${GSTREAMER_gstdataprotocol_LIBRARY} ${GSTREAMER_gstinterfaces_LIBRARY} |
||||
${GSTREAMER_gstnet_LIBRARY} ${GSTREAMER_gstpbutils_LIBRARY} |
||||
${GSTREAMER_gstreamer_LIBRARY} ${GSTREAMER_gstriff_LIBRARY} ${GSTREAMER_gstrtp_LIBRARY} |
||||
${GSTREAMER_gstrtsp_LIBRARY} ${GSTREAMER_gstsdp_LIBRARY} ${GSTREAMER_gsttag_LIBRARY} ${GSTREAMER_gstvideo_LIBRARY} ${GLIB_LIBRARY} |
||||
${GSTREAMER_gstapp_LIBRARY} ${GOBJECT_LIBRARY}) |
||||
|
||||
list(REMOVE_DUPLICATES GSTREAMER_LIBRARIES) |
||||
SET(GSTREAMER_FOUND TRUE) |
||||
ENDIF (GSTREAMER_gst_INCLUDE_DIR AND GSTREAMER_gstconfig_INCLUDE_DIR AND |
||||
GSTREAMER_gstaudio_LIBRARY AND GSTREAMER_gstbase_LIBRARY AND GSTREAMER_gstcontroller_LIBRARY |
||||
AND GSTREAMER_gstnet_LIBRARY AND GSTREAMER_gstpbutils_LIBRARY AND GSTREAMER_gstreamer_LIBRARY AND |
||||
GSTREAMER_gstriff_LIBRARY AND GSTREAMER_gstrtp_LIBRARY AND GSTREAMER_gstrtsp_LIBRARY AND GSTREAMER_gstsdp_LIBRARY AND |
||||
GSTREAMER_gsttag_LIBRARY AND GSTREAMER_gstvideo_LIBRARY AND GLIB_LIBRARY AND GSTREAMER_gstapp_LIBRARY AND GOBJECT_LIBRARY) |
@ -1,6 +1,6 @@ |
||||
#ifndef _CUSTOM_HAL_INCLUDED_ |
||||
#define _CUSTOM_HAL_INCLUDED_ |
||||
|
||||
@OPENCV_HAL_HEADERS_INCLUDES@ |
||||
@_includes@ |
||||
|
||||
#endif |
||||
|
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 114 KiB |
After Width: | Height: | Size: 75 KiB |
After Width: | Height: | Size: 96 KiB |
@ -0,0 +1,177 @@ |
||||
High Dynamic Range (HDR) {#tutorial_py_hdr} |
||||
======================== |
||||
|
||||
Goal |
||||
---- |
||||
|
||||
In this chapter, we will |
||||
|
||||
- Learn how to generate and display HDR image from an exposure sequence. |
||||
- Use exposure fusion to merge an exposure sequence. |
||||
|
||||
Theory |
||||
------ |
||||
|
||||
High-dynamic-range imaging (HDRI or HDR) is a technique used in imaging and photography to reproduce |
||||
a greater dynamic range of luminosity than is possible with standard digital imaging or photographic |
||||
techniques. While the human eye can adjust to a wide range of light conditions, most imaging devices use 8-bits |
||||
per channel, so we are limited to only 256 levels. When we take photographs of a real |
||||
world scene, bright regions may be overexposed, while the dark ones may be underexposed, so we |
||||
can’t capture all details using a single exposure. HDR imaging works with images that use more |
||||
than 8 bits per channel (usually 32-bit float values), allowing much wider dynamic range. |
||||
|
||||
There are different ways to obtain HDR images, but the most common one is to use photographs of |
||||
the scene taken with different exposure values. To combine these exposures it is useful to know your |
||||
camera’s response function and there are algorithms to estimate it. After the HDR image has been |
||||
merged, it has to be converted back to 8-bit to view it on usual displays. This process is called |
||||
tonemapping. Additional complexities arise when objects of the scene or camera move between shots, |
||||
since images with different exposures should be registered and aligned. |
||||
|
||||
In this tutorial we show 2 algorithms (Debvec, Robertson) to generate and display HDR image from an |
||||
exposure sequence, and demonstrate an alternative approach called exposure fusion (Mertens), that |
||||
produces low dynamic range image and does not need the exposure times data. |
||||
Furthermore, we estimate the camera response function (CRF) which is of great value for many computer |
||||
vision algorithms. |
||||
Each step of HDR pipeline can be implemented using different algorithms and parameters, so take a |
||||
look at the reference manual to see them all. |
||||
|
||||
|
||||
Exposure sequence HDR |
||||
--------------------- |
||||
|
||||
In this tutorial we will look on the following scene, where we have 4 exposure |
||||
images, with exposure times of: 15, 2.5, 1/4 and 1/30 seconds. (You can download |
||||
the images from [Wikipedia](https://en.wikipedia.org/wiki/High-dynamic-range_imaging)) |
||||
|
||||
 |
||||
|
||||
### 1. Loading exposure images into a list |
||||
|
||||
The first stage is simply loading all images into a list. |
||||
In addition, we will need the exposure times for the regular HDR algorithms. |
||||
Pay attention for the data types, as the images should be 1-channel or 3-channels |
||||
8-bit (np.uint8) and the exposure times need to be float32 and in seconds. |
||||
|
||||
@code{.py} |
||||
import cv2 |
||||
import numpy as np |
||||
|
||||
# Loading exposure images into a list |
||||
img_fn = ["img0.jpg", "img1.jpg", "img2.jpg", "img3.jpg"] |
||||
img_list = [cv2.imread(fn) for fn in img_fn] |
||||
exposure_times = np.array([15.0, 2.5, 0.25, 0.0333], dtype=np.float32) |
||||
@endcode |
||||
|
||||
### 2. Merge exposures into HDR image |
||||
|
||||
In this stage we merge the exposure sequence into one HDR image, showing 2 possibilities |
||||
which we have in OpenCV. The first method is Debvec and the second one is Robertson. |
||||
Notice that the HDR image is of type float32, and not uint8, as it contains the |
||||
full dynamic range of all exposure images. |
||||
|
||||
@code{.py} |
||||
# Merge exposures to HDR image |
||||
merge_debvec = cv2.createMergeDebevec() |
||||
hdr_debvec = merge_debvec.process(img_list, times=exposure_times.copy()) |
||||
merge_robertson = cv2.createMergeRobertson() |
||||
hdr_robertson = merge_robertson.process(img_list, times=exposure_times.copy()) |
||||
@endcode |
||||
|
||||
### 3. Tonemap HDR image |
||||
|
||||
We map the 32-bit float HDR data into the range [0..1]. |
||||
Actually, in some cases the values can be larger than 1 or lower the 0, so notice |
||||
we will later have to clip the data in order to avoid overflow. |
||||
|
||||
@code{.py} |
||||
# Tonemap HDR image |
||||
tonemap1 = cv2.createTonemapDurand(gamma=2.2) |
||||
res_debvec = tonemap1.process(hdr_debvec.copy()) |
||||
tonemap2 = cv2.createTonemapDurand(gamma=1.3) |
||||
res_robertson = tonemap2.process(hdr_robertson.copy()) |
||||
@endcode |
||||
|
||||
### 4. Merge exposures using Mertens fusion |
||||
|
||||
Here we show an alternative algorithm to merge the exposure images, where |
||||
we do not need the exposure times. We also do not need to use any tonemap |
||||
algorithm because the Mertens algorithm already gives us the result in the |
||||
range of [0..1]. |
||||
|
||||
@code{.py} |
||||
# Exposure fusion using Mertens |
||||
merge_mertens = cv2.createMergeMertens() |
||||
res_mertens = merge_mertens.process(img_list) |
||||
@endcode |
||||
|
||||
### 5. Convert to 8-bit and save |
||||
|
||||
In order to save or display the results, we need to convert the data into 8-bit |
||||
integers in the range of [0..255]. |
||||
|
||||
@code{.py} |
||||
# Convert datatype to 8-bit and save |
||||
res_debvec_8bit = np.clip(res_debvec*255, 0, 255).astype('uint8') |
||||
res_robertson_8bit = np.clip(res_robertson*255, 0, 255).astype('uint8') |
||||
res_mertens_8bit = np.clip(res_mertens*255, 0, 255).astype('uint8') |
||||
|
||||
cv2.imwrite("ldr_debvec.jpg", res_debvec_8bit) |
||||
cv2.imwrite("ldr_robertson.jpg", res_robertson_8bit) |
||||
cv2.imwrite("fusion_mertens.jpg", res_mertens_8bit) |
||||
@endcode |
||||
|
||||
Results |
||||
------- |
||||
|
||||
You can see the different results but consider that each algorithm have additional |
||||
extra parameters that you should fit to get your desired outcome. Best practice is |
||||
to try the different methods and see which one performs best for your scene. |
||||
|
||||
### Debvec: |
||||
|
||||
 |
||||
|
||||
### Robertson: |
||||
|
||||
 |
||||
|
||||
### Mertenes Fusion: |
||||
|
||||
 |
||||
|
||||
|
||||
Estimating Camera Response Function |
||||
----------------------------------- |
||||
|
||||
The camera response function (CRF) gives us the connection between the scene radiance |
||||
to the measured intensity values. The CRF if of great importance in some computer vision |
||||
algorithms, including HDR algorithms. Here we estimate the inverse camera response |
||||
function and use it for the HDR merge. |
||||
|
||||
@code{.py} |
||||
# Estimate camera response function (CRF) |
||||
cal_debvec = cv2.createCalibrateDebevec() |
||||
crf_debvec = cal_debvec.process(img_list, times=exposure_times) |
||||
hdr_debvec = merge_debvec.process(img_list, times=exposure_times.copy(), response=crf_debvec.copy()) |
||||
cal_robertson = cv2.createCalibrateRobertson() |
||||
crf_robertson = cal_robertson.process(img_list, times=exposure_times) |
||||
hdr_robertson = merge_robertson.process(img_list, times=exposure_times.copy(), response=crf_robertson.copy()) |
||||
@endcode |
||||
|
||||
The camera response function is represented by a 256-length vector for each color channel. |
||||
For this sequence we got the following estimation: |
||||
|
||||
 |
||||
|
||||
Additional Resources |
||||
-------------------- |
||||
|
||||
1. Paul E Debevec and Jitendra Malik. Recovering high dynamic range radiance maps from photographs. In ACM SIGGRAPH 2008 classes, page 31. ACM, 2008. |
||||
2. Mark A Robertson, Sean Borman, and Robert L Stevenson. Dynamic range improvement through multiple exposures. In Image Processing, 1999. ICIP 99. Proceedings. 1999 International Conference on, volume 3, pages 159–163. IEEE, 1999. |
||||
3. Tom Mertens, Jan Kautz, and Frank Van Reeth. Exposure fusion. In Computer Graphics and Applications, 2007. PG'07. 15th Pacific Conference on, pages 382–390. IEEE, 2007. |
||||
4. Images from [Wikipedia-HDR](https://en.wikipedia.org/wiki/High-dynamic-range_imaging) |
||||
|
||||
Exercises |
||||
--------- |
||||
1. Try all tonemap algorithms: [Drago](http://docs.opencv.org/master/da/d53/classcv_1_1TonemapDrago.html), [Durand](http://docs.opencv.org/master/da/d3d/classcv_1_1TonemapDurand.html), [Mantiuk](http://docs.opencv.org/master/de/d76/classcv_1_1TonemapMantiuk.html) and [Reinhard](http://docs.opencv.org/master/d0/dec/classcv_1_1TonemapReinhard.html). |
||||
2. Try changing the parameters in the HDR calibration and tonemap methods. |
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 111 KiB |
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 120 KiB |
@ -0,0 +1,12 @@ |
||||
Image Input and Output (imgcodecs module) {#tutorial_table_of_content_imgcodecs} |
||||
========================================= |
||||
|
||||
This section contains tutorials about how to read/save your image files. |
||||
|
||||
- @subpage tutorial_raster_io_gdal |
||||
|
||||
*Compatibility:* \> OpenCV 2.0 |
||||
|
||||
*Author:* Marvin Smith |
||||
|
||||
Read common GIS Raster and DEM files to display and manipulate geographic data. |
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
@ -0,0 +1,23 @@ |
||||
Video Input and Output (videoio module) {#tutorial_table_of_content_videoio} |
||||
========================================= |
||||
|
||||
This section contains tutorials about how to read/save your video files. |
||||
|
||||
- @subpage tutorial_video_input_psnr_ssim |
||||
|
||||
*Compatibility:* \> OpenCV 2.0 |
||||
|
||||
*Author:* Bernát Gábor |
||||
|
||||
You will learn how to read video streams, and how to calculate similarity values such as PSNR |
||||
or SSIM. |
||||
|
||||
- @subpage tutorial_video_write |
||||
|
||||
*Compatibility:* \> OpenCV 2.0 |
||||
|
||||
*Author:* Bernát Gábor |
||||
|
||||
- @subpage tutorial_kinect_openni |
||||
|
||||
- @subpage tutorial_intelperc |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |