Commit 77658d7c authored by Davis King's avatar Davis King

Added a function called assign_image_scaled() which copies an image but also

does an intelligent scaling if the source and destination images have differing
dynamic ranges.  I also modified the image display widgets to use assign_image_scaled()
instead of assign_image().

--HG--
extra : convert_revision : svn%3Afdd8eb12-d10e-0410-9acb-85c331704f74/trunk%403973
parent ff77bcc1
......@@ -406,7 +406,7 @@ namespace dlib
)
{
auto_mutex M(m);
assign_image(img,new_img);
assign_image_scaled(img,new_img);
rectangle old(rect);
rect.set_right(rect.left()+img.nc()-1);
rect.set_bottom(rect.top()+img.nr()-1);
......
......@@ -3085,7 +3085,7 @@ namespace dlib
else
parent.invalidate_rectangle(rect);
assign_image(img,new_img);
assign_image_scaled(img,new_img);
}
struct overlay_rect
......
......@@ -5,6 +5,7 @@
#include "../pixel.h"
#include "assign_image_abstract.h"
#include "../statistics.h"
namespace dlib
{
......@@ -21,7 +22,7 @@ namespace dlib
)
{
// check for the case where dest is the same object as src
if ((void*)&dest == (void*)&src)
if (is_same_object(dest,src))
return;
dest.set_size(src.nr(),src.nc());
......@@ -35,6 +36,77 @@ namespace dlib
}
}
// ----------------------------------------------------------------------------------------
template <
typename dest_image_type,
typename src_image_type
>
void assign_image_scaled (
dest_image_type& dest,
const src_image_type& src,
const double thresh = 4
)
{
DLIB_ASSERT( thresh > 0,
"\tvoid assign_image_scaled()"
<< "\n\t You have given an threshold value"
<< "\n\t thresh: " << thresh
);
// If the source and destination have the same range of values in their pixels then we don't need to do any
// special scaling. So just call the regular assign_image().
if (pixel_traits<typename dest_image_type::type>::max() == pixel_traits<typename src_image_type::type>::max() &&
pixel_traits<typename dest_image_type::type>::min() == pixel_traits<typename src_image_type::type>::min() )
{
assign_image(dest, src);
return;
}
dest.set_size(src.nr(),src.nc());
if (src.size() == 0)
return;
if (src.size() == 1)
{
assign_pixel(dest[0][0], src[0][0]);
return;
}
// gather image statistics
running_stats<double> rs;
for (long r = 0; r < src.nr(); ++r)
{
for (long c = 0; c < src.nc(); ++c)
{
rs.add(get_pixel_intensity(src[r][c]));
}
}
// Figure out the range of pixel values based on image statistics. There might be some huge
// outliers so don't just pick the min and max values.
const double upper = std::min(rs.mean() + thresh*rs.stddev(), rs.max());
const double lower = std::max(rs.mean() - thresh*rs.stddev(), rs.min());
typedef typename pixel_traits<typename dest_image_type::type>::basic_pixel_type dpix_type;
const dpix_type dest_min = pixel_traits<typename dest_image_type::type>::min();
const dpix_type dest_max = pixel_traits<typename dest_image_type::type>::max();
const double scale = (upper!=lower)? ((dest_max - dest_min) / (upper - lower)) : 0;
for (long r = 0; r < src.nr(); ++r)
{
for (long c = 0; c < src.nc(); ++c)
{
const double val = get_pixel_intensity(src[r][c]) - lower;
assign_pixel(dest[r][c], scale*val + dest_min);
}
}
}
// ----------------------------------------------------------------------------------------
template <
......
......@@ -32,6 +32,57 @@ namespace dlib
(i.e. copies the src image to dest image)
!*/
// ----------------------------------------------------------------------------------------
template <
typename dest_image_type,
typename src_image_type
>
void assign_image_scaled (
dest_image_type& dest_img,
const src_image_type& src_img,
const double thresh = 4
);
/*!
requires
- src_image_type == is an implementation of array2d/array2d_kernel_abstract.h
- dest_image_type == is an implementation of array2d/array2d_kernel_abstract.h
- pixel_traits<typename src_image_type::type> is defined
- pixel_traits<typename dest_image_type::type> is defined
- thresh > 0
ensures
- #dest_img.nc() == src_img.nc()
- #dest_img.nr() == src_img.nr()
- if (dest_image_type and src_image_type both contain pixels with the same dynamic
range as determined by the min() and max() pixel_traits properties) then
- performs: assign_image(dest_img, src_img)
(i.e. in this case, no scaling is performed. )
- else
- #dest_img will be converted to a grayscale image
- scales the contents of src_img into the dynamic range of dest_img and then
assigns the result into dest_img. The thresh parameter is used to filter
source pixel values which are outliers. These outliers will saturate
at the edge of the destination image's dynamic range.
- Specifically, for all valid r and c:
- scales get_pixel_intensity(src_img[r][c]) into the dynamic range
of the dest_img. This is done by computing the mean and standard
deviation of src_img. Call the mean M and the standard deviation
D. Then the scaling from src_img to dest_img is performed using
the following mapping:
let SRC_UPPER = min(M + thresh*D, max(array_to_matrix(src_img)))
let SRC_LOWER = max(M - thresh*D, min(array_to_matrix(src_img)))
let DEST_UPPER = pixel_traits<dest_image_type::type>::max()
let DEST_LOWER = pixel_traits<dest_image_type::type>::min()
MAPPING: [SRC_LOWER, SRC_UPPER] -> [DEST_LOWER, DEST_UPPER]
Where this mapping is a linear mapping of values from the left range
into the right range of values. Source pixel values outside the left
range are modified to be at the appropriate end of the range.
The scaled pixel is then stored in dest_img[r][c].
!*/
// ----------------------------------------------------------------------------------------
template <
......
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