Commit 01074177 authored by Davis King's avatar Davis King

Upgraded the dng image format so it can natively store floating point

pixel types without any information loss.
parent 90668383
......@@ -14,6 +14,7 @@
#include "../uintn.h"
#include "../image_transforms/assign_image.h"
#include <algorithm>
#include "../vectorstream.h"
namespace dlib
{
......@@ -576,180 +577,243 @@ namespace dlib
else
image.clear();
typedef entropy_decoder::kernel_2a decoder_type;
decoder_type decoder;
decoder.set_stream(in);
entropy_decoder_model<256,decoder_type>::kernel_5a edm(decoder);
unsigned long symbol;
rgb_pixel p_rgb;
rgb_alpha_pixel p_rgba;
hsi_pixel p_hsi;
switch (type)
if (type != grayscale_float)
{
case rgb_alpha_paeth:
typedef entropy_decoder::kernel_2a decoder_type;
decoder_type decoder;
decoder.set_stream(in);
entropy_decoder_model<256,decoder_type>::kernel_5a edm(decoder);
unsigned long symbol;
rgb_pixel p_rgb;
rgb_alpha_pixel p_rgba;
hsi_pixel p_hsi;
switch (type)
{
case rgb_alpha_paeth:
for (long r = 0; r < image.nr(); ++r)
{
for (long c = 0; c < image.nc(); ++c)
for (long r = 0; r < image.nr(); ++r)
{
p_rgba = predictor_rgb_alpha_paeth(image,r,c);
edm.decode(symbol);
p_rgba.red += static_cast<unsigned char>(symbol);
for (long c = 0; c < image.nc(); ++c)
{
p_rgba = predictor_rgb_alpha_paeth(image,r,c);
edm.decode(symbol);
p_rgba.red += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_rgba.green += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_rgba.green += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_rgba.blue += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_rgba.blue += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_rgba.alpha += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_rgba.alpha += static_cast<unsigned char>(symbol);
assign_pixel(image[r][c],p_rgba);
assign_pixel(image[r][c],p_rgba);
}
}
}
break;
break;
case rgb_alpha:
case rgb_alpha:
for (long r = 0; r < image.nr(); ++r)
{
for (long c = 0; c < image.nc(); ++c)
for (long r = 0; r < image.nr(); ++r)
{
p_rgba = predictor_rgb_alpha(image,r,c);
edm.decode(symbol);
p_rgba.red += static_cast<unsigned char>(symbol);
for (long c = 0; c < image.nc(); ++c)
{
p_rgba = predictor_rgb_alpha(image,r,c);
edm.decode(symbol);
p_rgba.red += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_rgba.green += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_rgba.green += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_rgba.blue += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_rgba.blue += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_rgba.alpha += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_rgba.alpha += static_cast<unsigned char>(symbol);
assign_pixel(image[r][c],p_rgba);
assign_pixel(image[r][c],p_rgba);
}
}
}
break;
break;
case rgb_paeth:
case rgb_paeth:
for (long r = 0; r < image.nr(); ++r)
{
for (long c = 0; c < image.nc(); ++c)
for (long r = 0; r < image.nr(); ++r)
{
p_rgb = predictor_rgb_paeth(image,r,c);
edm.decode(symbol);
p_rgb.red += static_cast<unsigned char>(symbol);
for (long c = 0; c < image.nc(); ++c)
{
p_rgb = predictor_rgb_paeth(image,r,c);
edm.decode(symbol);
p_rgb.red += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_rgb.green += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_rgb.green += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_rgb.blue += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_rgb.blue += static_cast<unsigned char>(symbol);
assign_pixel(image[r][c],p_rgb);
assign_pixel(image[r][c],p_rgb);
}
}
}
break;
break;
case rgb:
case rgb:
for (long r = 0; r < image.nr(); ++r)
{
for (long c = 0; c < image.nc(); ++c)
for (long r = 0; r < image.nr(); ++r)
{
p_rgb = predictor_rgb(image,r,c);
edm.decode(symbol);
p_rgb.red += static_cast<unsigned char>(symbol);
for (long c = 0; c < image.nc(); ++c)
{
p_rgb = predictor_rgb(image,r,c);
edm.decode(symbol);
p_rgb.red += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_rgb.green += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_rgb.green += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_rgb.blue += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_rgb.blue += static_cast<unsigned char>(symbol);
assign_pixel(image[r][c],p_rgb);
assign_pixel(image[r][c],p_rgb);
}
}
}
break;
break;
case hsi:
case hsi:
for (long r = 0; r < image.nr(); ++r)
{
for (long c = 0; c < image.nc(); ++c)
for (long r = 0; r < image.nr(); ++r)
{
p_hsi = predictor_hsi(image,r,c);
edm.decode(symbol);
p_hsi.h += static_cast<unsigned char>(symbol);
for (long c = 0; c < image.nc(); ++c)
{
p_hsi = predictor_hsi(image,r,c);
edm.decode(symbol);
p_hsi.h += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_hsi.s += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_hsi.s += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_hsi.i += static_cast<unsigned char>(symbol);
edm.decode(symbol);
p_hsi.i += static_cast<unsigned char>(symbol);
assign_pixel(image[r][c],p_hsi);
assign_pixel(image[r][c],p_hsi);
}
}
}
break;
break;
case grayscale:
{
unsigned char p;
for (long r = 0; r < image.nr(); ++r)
case grayscale:
{
for (long c = 0; c < image.nc(); ++c)
unsigned char p;
for (long r = 0; r < image.nr(); ++r)
{
edm.decode(symbol);
p = static_cast<unsigned char>(symbol);
p += predictor_grayscale(image,r,c);
assign_pixel(image[r][c],p);
for (long c = 0; c < image.nc(); ++c)
{
edm.decode(symbol);
p = static_cast<unsigned char>(symbol);
p += predictor_grayscale(image,r,c);
assign_pixel(image[r][c],p);
}
}
}
}
break;
break;
case grayscale_16bit:
{
uint16 p;
for (long r = 0; r < image.nr(); ++r)
case grayscale_16bit:
{
for (long c = 0; c < image.nc(); ++c)
uint16 p;
for (long r = 0; r < image.nr(); ++r)
{
edm.decode(symbol);
p = static_cast<uint16>(symbol);
p <<= 8;
edm.decode(symbol);
p |= static_cast<uint16>(symbol);
p += predictor_grayscale_16(image,r,c);
assign_pixel(image[r][c],p);
for (long c = 0; c < image.nc(); ++c)
{
edm.decode(symbol);
p = static_cast<uint16>(symbol);
p <<= 8;
edm.decode(symbol);
p |= static_cast<uint16>(symbol);
p += predictor_grayscale_16(image,r,c);
assign_pixel(image[r][c],p);
}
}
}
}
break;
break;
default:
default:
throw image_load_error("corruption detected in the dng file");
} // switch (type)
edm.decode(symbol);
if (symbol != dng_magic_byte)
throw image_load_error("corruption detected in the dng file");
edm.decode(symbol);
if (symbol != dng_magic_byte)
throw image_load_error("corruption detected in the dng file");
edm.decode(symbol);
if (symbol != dng_magic_byte)
throw image_load_error("corruption detected in the dng file");
} // switch (type)
edm.decode(symbol);
if (symbol != dng_magic_byte)
throw image_load_error("corruption detected in the dng file");
edm.decode(symbol);
if (symbol != dng_magic_byte)
throw image_load_error("corruption detected in the dng file");
edm.decode(symbol);
if (symbol != dng_magic_byte)
throw image_load_error("corruption detected in the dng file");
edm.decode(symbol);
if (symbol != dng_magic_byte)
throw image_load_error("corruption detected in the dng file");
edm.decode(symbol);
if (symbol != dng_magic_byte)
throw image_load_error("corruption detected in the dng file");
}
else // if this is a grayscale_float type image
{
std::vector<int64> man(image.size());
std::vector<char> expbuf;
// get the mantissa data
for (unsigned long i = 0; i < man.size(); ++i)
deserialize(man[i], in);
// get the compressed exponent data
deserialize(expbuf, in);
typedef entropy_decoder::kernel_2a decoder_type;
typedef entropy_decoder_model<256,decoder_type>::kernel_4a edm_exp_type;
vectorstream inexp(expbuf);
decoder_type decoder;
decoder.set_stream(inexp);
edm_exp_type edm_exp(decoder);
float_details prev;
unsigned long i = 0;
// fill out the image
for (long r = 0; r < image.nr(); ++r)
{
for (long c = 0; c < image.nc(); ++c)
{
unsigned long exp1, exp2;
edm_exp.decode(exp1);
edm_exp.decode(exp2);
float_details cur(man[i++],(exp2<<8) | exp1);
cur.exponent += prev.exponent;
cur.mantissa += prev.mantissa;
prev = cur;
// Only use long double precision if the target image contains long
// doubles because it's slower to use those.
if (!is_same_type<typename image_type::type,long double>::value)
{
double temp = cur;
assign_pixel(image[r][c],temp);
}
else
{
long double temp = cur;
assign_pixel(image[r][c],temp);
}
}
}
unsigned long symbol;
edm_exp.decode(symbol);
if (symbol != dng_magic_byte)
throw image_load_error("corruption detected in the dng file");
edm_exp.decode(symbol);
if (symbol != dng_magic_byte)
throw image_load_error("corruption detected in the dng file");
edm_exp.decode(symbol);
if (symbol != dng_magic_byte)
throw image_load_error("corruption detected in the dng file");
edm_exp.decode(symbol);
if (symbol != dng_magic_byte)
throw image_load_error("corruption detected in the dng file");
}
}
catch (...)
{
......
......@@ -20,7 +20,8 @@ namespace dlib
rgb_paeth,
rgb_alpha,
rgb_alpha_paeth,
grayscale_16bit
grayscale_16bit,
grayscale_float
};
const unsigned long dng_magic_byte = 100;
......
......@@ -15,6 +15,8 @@
#include "dng_shared.h"
#include "../uintn.h"
#include "../dir_nav.h"
#include "../float_details.h"
#include "../vectorstream.h"
namespace dlib
{
......@@ -249,7 +251,9 @@ namespace dlib
false,
pixel_traits<typename image_type::type>::rgb_alpha,
false,
pixel_traits<typename image_type::type>::grayscale && sizeof(typename image_type::type) != 1
pixel_traits<typename image_type::type>::grayscale && sizeof(typename image_type::type) != 1 &&
!is_float_type<typename image_type::type>::value,
is_float_type<typename image_type::type>::value
>::value
>
struct save_dng_helper;
......@@ -257,6 +261,64 @@ namespace dlib
typedef entropy_encoder::kernel_2a encoder_type;
typedef entropy_encoder_model<256,encoder_type>::kernel_5a eem_type;
typedef entropy_encoder_model<256,encoder_type>::kernel_4a eem_exp_type;
template <typename image_type >
struct save_dng_helper<image_type, grayscale_float>
{
static void save_dng (
const image_type& image,
std::ostream& out
)
{
out.write("DNG",3);
unsigned long version = 1;
serialize(version,out);
unsigned long type = grayscale_float;
serialize(type,out);
serialize(image.nc(),out);
serialize(image.nr(),out);
// Write the compressed exponent data into expbuf. We will append it
// to the stream at the end of the loops.
std::vector<char> expbuf;
expbuf.reserve(image.size()*2);
vectorstream outexp(expbuf);
encoder_type encoder;
encoder.set_stream(outexp);
eem_exp_type eem_exp(encoder);
float_details prev;
for (long r = 0; r < image.nr(); ++r)
{
for (long c = 0; c < image.nc(); ++c)
{
float_details cur = image[r][c];
int16 exp = cur.exponent-prev.exponent;
int64 man = cur.mantissa-prev.mantissa;
prev = cur;
unsigned char ebyte1 = exp&0xFF;
unsigned char ebyte2 = exp>>8;
eem_exp.encode(ebyte1);
eem_exp.encode(ebyte2);
serialize(man, out);
}
}
// write out the magic byte to mark the end of the compressed data.
eem_exp.encode(dng_magic_byte);
eem_exp.encode(dng_magic_byte);
eem_exp.encode(dng_magic_byte);
eem_exp.encode(dng_magic_byte);
encoder.clear();
serialize(expbuf, out);
}
};
template <typename image_type >
struct save_dng_helper<image_type, grayscale_16bit>
{
......
......@@ -90,11 +90,11 @@ namespace dlib
- image[0][0] will be in the upper left corner of the image.
- image[image.nr()-1][image.nc()-1] will be in the lower right
corner of the image.
- This routine can save images containing any type of pixel. However, the
DNG format can natively store only the following pixel types: rgb_pixel,
hsi_pixel, rgb_alpha_pixel, uint8, and uint16. All other pixel types
will be converted into one of these types as appropriate before being
saved to disk.
- This routine can save images containing any type of pixel. However, the DNG
format can natively store only the following pixel types: rgb_pixel,
hsi_pixel, rgb_alpha_pixel, uint8, uint16, float, double, and long double.
All other pixel types will be converted into one of these types as
appropriate before being saved to disk.
throws
- image_save_error
This exception is thrown if there is an error that prevents us
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment